<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>wzz</name>
    <email>369090561@qq.com</email>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <icon>https://www.gravatar.com/avatar/6346e1136915a2e1dd7f9c0040190dc6</icon>
  <id>https://blog.kfad127.xyz/</id>
  <link href="https://blog.kfad127.xyz/" rel="alternate"/>
  <link href="https://blog.kfad127.xyz/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, wzz</rights>
  <subtitle>欢迎到访~</subtitle>
  <title>k-fad 的博客</title>
  <updated>2026-10-21T02:08:11.000Z</updated>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="工作心得记录" scheme="https://blog.kfad127.xyz/categories/work-notes/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="复盘" scheme="https://blog.kfad127.xyz/tags/%E5%A4%8D%E7%9B%98/"/>
    <category term="教育" scheme="https://blog.kfad127.xyz/tags/%E6%95%99%E8%82%B2/"/>
    <category term="素材库" scheme="https://blog.kfad127.xyz/tags/%E7%B4%A0%E6%9D%90%E5%BA%93/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/local-material-familiarity-cover.jpg" alt="给 AI 补充家乡素材，先得知道孩子熟不熟悉封面"></p><p>最近在做 AI 作文辅导，给它补了一批河南本地素材。</p><p>起点很实际：希望孩子不知道写什么的时候，AI 能提供一些离生活更近的线索。</p><p>作文辅导可以帮孩子分析题目、整理结构、修改句子，但在这些之前，得先有一件他愿意写、也有内容可讲的事。如果选材时一直问“你想到了什么”“还有没有别的”，孩子卡住了，后面的流程也很难继续。</p><span id="more"></span><p>我想试试，能不能让这个问题变得具体一点。</p><p>比如写《推荐一个好地方》，AI 知道一些当地的公园、图书馆或公共场所，就有机会帮孩子回忆：有没有去过其中某个地方，有没有哪一次还记得。如果孩子提到一个熟悉的地点，AI 也能顺着这个地方，找到更具体的观察角度。</p><p>这是引入本地素材库最想解决的问题：让选材时的提示更具体，也让后面的追问有一些依据。</p><p>范文库能提供写法参考，本地素材库则更靠近“写什么”这一头。我希望它能帮助孩子想起自己的经历，再从那些经历里慢慢整理出内容。</p><p>所以，素材卡里除了名称和经过核对的地方信息，还要考虑怎样使用：适合什么年级、什么习作，可以从哪个观察点开始问，需要先向孩子确认什么。</p><p>拿一张公园卡来说，介绍里有园名、有景物，并不意味着辅导时要把这些介绍讲给孩子听。它更适合提醒 AI：如果孩子确实去过，可以问问那次在哪里停留过，注意到了什么，自己做了什么。</p><p>这样，库里的内容才有机会接到孩子的话上。</p><p>原来的素材主要围绕郑州，这次扩大到河南其他地区，整理了两百多张卡。核对来源、修改内容、匹配习作单元，做了不少工作。但审核时，有一栏让我重新想了想这个库的作用。</p><p>那一栏叫学生熟悉度。</p><p>这批素材选的是“目标学生较熟悉”，填写的依据却是“仅附近或特定群体接触，需限定使用范围”。</p><p>范围明显对不上。最后，统一改成了“仅部分学生接触”。</p><p>这次调整没有增加新的调查证据，只是把原来写得太宽的判断收回来。我们核实了一个地方的名称和归属，还不能由此知道哪些孩子去过、去过几次、现在记得什么。</p><p>“本地”这个词，容易让人觉得距离已经很近了。可同一座城市里的孩子，日常生活也可能很不一样。住在哪里，怎么上下学，平时跟家人去哪些地方，都会影响他熟悉什么。</p><p>一个很有名的景区，他可能只听过名字；家附近一个没有收进库里的小广场，却可能有很多话可讲。</p><p>想到这里，我觉得素材库还要解决另一个问题：给出线索以后，能不能根据孩子的回答及时调整。</p><p>如果孩子说没去过，就换一个地方，或者让他自己提。已经说出了想写的内容，就顺着他的内容聊。哪怕他说的地方库里没有，也应该能继续下去。</p><p>否则，准备了很多素材，反而可能让 AI 一直围着自己的清单打转。孩子说一句“不知道”，它就再推荐一个地方，看起来一直在推进，离孩子真正想写的事却未必更近。</p><p>对我来说，这是这次整理中很有价值的提醒。素材库既要有内容，也要想好什么时候用、用到哪里停下来。</p><p>还有一点，是采集本身带来的偏向。</p><p>公园、景区、场馆往往有公开名录，名称和位置也比较容易核实。顺着这些来源整理，很自然就会先收进来一批这样的对象。</p><p>但孩子的生活里，还有很多不容易从名录里找到的东西。上学路上经常经过的一处地方，家里准备一顿饭的过程，一次普通的社区活动，都可能有值得写的细节。</p><p>后面继续补素材，我会更留意这些日常场景，也会更仔细地看一张卡能引出什么。一个地名可以对应很多问题，适合低年级观察的内容、推荐一个地方需要说明的理由、一次活动里值得记下的动作，并不能直接套用同一种问法。</p><p>以前比较容易关注库里有多少条、覆盖了多少地方。做过这一轮以后，我更想知道的是：这些内容到了对话里，能不能帮孩子想起一件具体的事，讲出一点原本没说出来的细节。</p><p>这批扩展素材还在做接入核验，实际辅导效果要等后续使用再看。接下来值得观察的，也正是这些细小的地方：孩子接不接得住提示，说不熟悉以后能不能顺利换题，有了自己的材料以后，AI 还会不会反复推荐。</p><p>素材可以继续补，孩子的回答也要一直听。也许聊到最后，他最想写的仍然是楼下那个没有正式名字的小地方。能从那里接着问下去，这个库就有机会帮上忙。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/21/local-material-familiarity/</id>
    <link href="https://blog.kfad127.xyz/2026/10/21/local-material-familiarity/"/>
    <published>2026-10-21T02:08:11.000Z</published>
    <summary>给 AI 作文辅导补充家乡线索，希望孩子更容易想起自己的经历。一次熟悉度审核，也让我重新想了想素材库该怎样发挥作用。</summary>
    <title>给 AI 补充家乡素材，先得知道孩子熟不熟悉</title>
    <updated>2026-10-21T02:08:11.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="sanxing" scheme="https://blog.kfad127.xyz/categories/sanxing/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="亲子" scheme="https://blog.kfad127.xyz/tags/%E4%BA%B2%E5%AD%90/"/>
    <category term="产品设计" scheme="https://blog.kfad127.xyz/tags/%E4%BA%A7%E5%93%81%E8%AE%BE%E8%AE%A1/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/sanxing-small-buttons-cover.jpg" alt="这次更新三省，我最在意的是几个小按钮封面"></p><p>做三省，是因为我对 AI 感兴趣，想做一些东西，让孩子也能用一用、体验一下。同时，我也希望借这个过程，多了解孩子一些。</p><p>我想知道他最近在意什么，什么事情愿意多讲一点，有没有一些我平时没留意到的想法。三省就是顺着这个念头做的：孩子可以跟里面的“小省”聊聊今天发生的事，再把愿意留下的话放进自己的小本子。</p><p>这次更新，参考了一些 AI 产品的交互方式，也重新看了三省自己的聊天流程。加了连续聊天、记忆，还能选一张图片，配着自己的话讲今天。做这些功能的时候，也补了几个之前考虑得不够细的地方。</p><span id="more"></span><p>比如，语音识别错了，能不能直接改。</p><p>之前说完一段话，转成文字，主要就是发送或者取消。识别错一个词，也缺少直接改字的地方。整段取消，就要重新说一遍；直接发出去，又不完全是自己想说的话。</p><p>现在，普通语音模式下可以先看一下识别结果，改好再发。录音结束以后，文字留在那里，等孩子确认。未发送的内容也补了恢复：在当前标签页里刷新页面，可以把刚才打的字、识别出的文字找回来。</p><p>这些都是很普通的功能，却容易在开发时被漏掉。注意力先放在模型能不能回复、回复得怎么样，回头把整个流程走一遍，才发现输入和修改也有不方便的地方。</p><p>我希望孩子能比较轻松地把话说出来。这件事除了看小省怎么接话，也要看前面的几个操作顺不顺手。机器听错了一个词，应该有个方便的办法改掉它。</p><p>连续聊天也是这次加的。</p><p>以前要说一段、点一下发送，再等小省回复。开启“连续聊”以后，停顿一会儿，内容会自动发出去；小省说完，再继续听。想停下来改字，可以暂停；小省说话时，也能点一下打断。</p><p>这样能少点几次按钮，不过实际用起来怎么样，还得试。孩子说话时会停顿，会改口，有时一句话还没想完。程序等多久再接话合适，单靠我自己试，判断不了。</p><p>所以先保留两种方式，让孩子自己选。后面看看他更习惯哪一种，在哪些地方会卡住，再接着改。</p><p>另一个改动，是让小省记住一些事情。</p><p>我希望聊天能有一点连续性。上次聊过的爱好、最近在做的事，下次还能接着说，不必每回都重新介绍。如果每次打开都像第一次见面，很多话也很难往下聊。</p><p>但一句话说出口，跟愿意让它一直被记住，需要分别确认。随口说过的念头，过几天可能就变了。小省如果一直拿那句话来接话，也未必合适。</p><p>目前的做法是，记忆默认关闭，孩子确认以后才保存。之后可以修改，可以关闭，也可以删除。让小省记住的内容，不会自动写进当天的小本子，也不会自动分享给家长。</p><p>做这部分的时候，我也重新想了想，自己希望通过 AI 了解孩子，具体是想了解什么。</p><p>一份很完整、很通顺的总结，读起来可能很方便。可里面对孩子心情、想法的判断，未必准确。孩子随口说的一句话，放在不同情境里，意思也可能不一样。</p><p>我更希望它能帮我留意一些具体的内容：最近反复提起了什么，哪件事愿意多讲一点，有什么话值得找个时间接着听。知道这些以后，我可以带着更具体的话题，和孩子继续聊。</p><p>这也是为什么，我在意他能不能改掉识别错的字，能不能决定哪些内容留下来，以及能不能删掉之前让小省记住的话。至少这些记录，要尽量接近他自己想表达的意思。</p><p>这轮更新已经部署，接下来准备让孩子体验这些新功能。微信里的语音表现、停顿多久比较合适，还有这些按钮好不好找，都要在实际使用里再看。</p><p>我现在也不知道，他会不会喜欢连续聊，会不会愿意让小省记住一些事。先看他怎么用，听听他怎么说。也希望能从他愿意讲的话里，多找到一些和他聊下去的话题。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/19/sanxing-small-buttons/</id>
    <link href="https://blog.kfad127.xyz/2026/10/19/sanxing-small-buttons/"/>
    <published>2026-10-19T01:39:19.000Z</published>
    <summary>想让孩子体验 AI，也想借这个过程多了解孩子一些。这次更新三省，补上了改字、暂停和记忆管理这些小操作。</summary>
    <title>这次更新三省，我最在意的是几个小按钮</title>
    <updated>2026-10-19T01:39:19.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="工作心得记录" scheme="https://blog.kfad127.xyz/categories/work-notes/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="上下文" scheme="https://blog.kfad127.xyz/tags/%E4%B8%8A%E4%B8%8B%E6%96%87/"/>
    <category term="复盘" scheme="https://blog.kfad127.xyz/tags/%E5%A4%8D%E7%9B%98/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/ai-context-more-is-better-cover.svg" alt="发给 AI 的东西，真的越多越好吗？封面"></p><p>昨天写了<a href="/2026/10/15/ai-grading-ruler/">《给 AI 打分之前，先检查一下尺子》</a>，讲评分这件事本身也需要验证。</p><p>今天想往前挪一步，看看打分之前，我们到底给 AI 发了什么。</p><p>最近排查作文辅导的输入，在一个长历史样本里看到了一个数字：<strong>逐字坐标表，占了总输入字符的 87.3%。</strong></p><p>接近九万个字符，八成多都在告诉模型：每个字在哪里。</p><span id="more"></span><h2 id="先把输入摊开"><a href="#先把输入摊开" class="headerlink" title="先把输入摊开"></a>先把输入摊开</h2><p>先交代范围。这是 10 月 15 日用本地模型替身跑的一次输入尺寸观测，材料是构造的合成样本，没有向外部模型发请求。</p><p>它能让我看见程序准备发送什么，不能告诉我模型实际读得怎样。</p><p>其中一个长历史、进入落笔阶段的样本，拆出来是这样：</p><table><thead><tr><th>内容</th><th align="right">字符数</th></tr></thead><tbody><tr><td>总输入</td><td align="right">86,988</td></tr><tr><td>其中的逐字坐标表</td><td align="right">75,920</td></tr><tr><td>坐标表占比</td><td align="right">87.3%</td></tr></tbody></table><p>这里统计的是字符，不能直接当作 token，也不能按这个比例计算费用。它也只是一个样本，不能代表所有对话。</p><p>但这个样本已经足够让我停下来，重新看看这张表。</p><h2 id="坐标表有它的用处"><a href="#坐标表有它的用处" class="headerlink" title="坐标表有它的用处"></a>坐标表有它的用处</h2><p>做作文辅导，有一件事我一直很在意：AI 引用孩子的话，得找到出处。</p><p>孩子说过什么、AI 建议过什么、孩子真正写下了什么，要分开。尤其到了修改阶段，不能只说“这句话改好了”，还得知道改的是哪条消息里的哪一段。</p><p>于是输入里除了原话，还附了一张逐字的位置表。</p><p>举个简化的例子，原话是“爷爷爱下棋”，旁边再给一份：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">0：爷</span><br><span class="line">1：爷</span><br><span class="line">2：爱</span><br><span class="line">3：下</span><br><span class="line">4：棋</span><br></pre></td></tr></table></figure><p>模型引用时，就可以同时返回文字和起止位置，后端再核验它有没有指对地方。</p><p>这个设计的出发点很明确：让引用更容易检查。可当原话变长、历史消息变多，每个字都要带着编号和格式再展开一遍，辅助信息也跟着膨胀了。</p><p><strong>原本用来帮助定位的一张表，最后占了大部分输入篇幅。</strong></p><h2 id="越怕遗漏，越容易加东西"><a href="#越怕遗漏，越容易加东西" class="headerlink" title="越怕遗漏，越容易加东西"></a>越怕遗漏，越容易加东西</h2><p>这张表让我想起做这个项目时经常遇到的取舍。</p><p>希望 AI 记住孩子前面说过的话，就带上历史；希望它知道现在该做什么，就带上任务；希望它别把建议当成事实，就带上来源；希望它别提前往下走，就补充推进条件。</p><p>每一项单独看，都有理由。</p><p>但把它们放到同一次请求里，还需要再问一遍：这些内容在这一轮分别起什么作用？有没有重复表达同一件事？哪些要交给模型理解，哪些只需要程序保存和检查？</p><p>以前关注得更多的是“还缺什么”。这次把输入拆开，才看见另一个工作：检查已经加进去的东西。</p><p>那 87.3% 暂时不能证明模型因此漏掉了事实、回答慢了，或者出现了什么压缩问题。它首先暴露的是一个很具体的工程现象：为了说明原文的位置，我们用了很多篇幅。</p><p>这部分值得单独拿出来改，也值得单独验证。</p><h2 id="我想先调整一下分工"><a href="#我想先调整一下分工" class="headerlink" title="我想先调整一下分工"></a>我想先调整一下分工</h2><p>目前考虑的一个方向，是让模型返回消息编号、精确原文，以及必要的消歧线索，再由程序去定位和核验。</p><p>另一个方向，是只给当前任务相关的片段提供局部坐标，需要时再映射回原消息。</p><p>这两种都还是候选方案。</p><p>定位也没有“搜一下原文”那么简单。同一句话可能出现两次，孩子可能改口、撤回，也可能在修改稿里保留了原句。程序找到第一次匹配，不代表找到了这次要引用的地方。</p><p>表情和组合字符的计数也要对齐。输入短了，引用却指错了，省下来的篇幅就没有意义。</p><p>所以接下来要保留的，是准确找到原话、分清来源、识别修改的能力；至于要不要继续把每个字的位置都交给模型，可以试着换一种做法。</p><p><strong>这次想调整的是分工：模型判断要引用什么，程序负责把位置核准。</strong></p><h2 id="短了之后，还要重新跑一遍"><a href="#短了之后，还要重新跑一遍" class="headerlink" title="短了之后，还要重新跑一遍"></a>短了之后，还要重新跑一遍</h2><p>真正比较时，我准备先固定同一批材料、任务和模型，分别跑原输入与精简输入。</p><p>先看引用：有没有漏、有没有串消息、重复片段能否区分、修改和撤回后是否仍然正确。</p><p>再看辅导：有没有重复追问、忽略刚补充的材料、把 AI 给的建议算成孩子自己的表达。</p><p>最后记录实际 token、响应时间和成本。短历史、长历史，以及不同阶段，也要分别看，不能用一组顺利的结果替其他情况作答。</p><p>如果同时换模型、改教学策略、删掉一批约束，即使结果变了，也很难知道是哪一步起了作用。这一轮想先把输入这件事看清楚。</p><p>目前完成的是观测和方案，精简还没实施，真实调用的前后对照也没跑。所以这篇暂时没有“省了多少费用、效果提升多少”的结论。</p><p>只记下一个新的检查习惯：以后再往输入里加一块内容，除了问它有没有用，也问问它应该由谁来处理。</p><p>先从这张坐标表开始。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/16/ai-context-more-is-better/</id>
    <link href="https://blog.kfad127.xyz/2026/10/16/ai-context-more-is-better/"/>
    <published>2026-10-16T02:13:00.000Z</published>
    <summary>一次本地输入观测里，逐字坐标表占了字符的八成多。为准确引用加上的设计，也需要重新检查分工。</summary>
    <title>发给 AI 的东西，真的越多越好吗？</title>
    <updated>2026-10-16T02:13:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="工作心得记录" scheme="https://blog.kfad127.xyz/categories/work-notes/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="复盘" scheme="https://blog.kfad127.xyz/tags/%E5%A4%8D%E7%9B%98/"/>
    <category term="教育" scheme="https://blog.kfad127.xyz/tags/%E6%95%99%E8%82%B2/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/ai-grading-ruler-cover.png" alt="给 AI 打分之前，先检查一下尺子封面"></p><p>昨天写了《教 AI 陪小学生写作文》，讲怎么把作文辅导做扎实。其实这几个月还有另一半工作，一直没写：<strong>怎么知道它辅导得好不好。</strong></p><p>答案听起来简单：打个分。真做起来，大部分时间花在了分数之外——先检查那把打分的尺子。</p><span id="more"></span><h2 id="一个满分"><a href="#一个满分" class="headerlink" title="一个满分"></a>一个满分</h2><p>先讲件小事，出自我业余在做的「三省」，就是前几篇提过的、给孩子用的那个对话小玩意。</p><p>它有一套回复质量评分器，AI 每回复孩子一句，就打一次分。前几天我做了一次复现测试：孩子的输入是「我今天画了一张画」，我让回复里故意补了一句「老师把它贴在教室里了」——孩子没说过这话。</p><p>评分器的结论：<strong>100 分，零问题。</strong></p><p>说明一下，这是本地构造的复现，不是真实孩子的对话。但正因为是构造的，结论才干净：那套评分器量的是词语重合和固定句式，它能看出这句话「写得像不像样」，看不出「是不是编的」。尺子没坏，是它根本量不了这个维度。</p><p>这个案例后来被冻成反例用例。修正方向也不是把阈值再调严，而是换量法：回复里的事实陈述，必须能回溯到孩子的原话，回溯不到就不许出现。</p><p>真正留下的是那个感受：<strong>看见满分，得先问一句，它量的到底是什么。</strong></p><h2 id="「好」的定义不够具体"><a href="#「好」的定义不够具体" class="headerlink" title="「好」的定义不够具体"></a>「好」的定义不够具体</h2><p>公司项目里同样的问题，规模更大。老规矩，隐去业务细节，只留方法。</p><p>给作文辅导 AI 打分的规则里，每个维度的锚点写的是「明确合适／部分合适／不合适」，正反例是空的。这意味着两个评分员拿同一把尺子，量的其实是各自脑补的「合适」。AI 评分员也一样——锚点越含糊，它打分越像掷骰子。</p><p>修法是把锚点写具体，具体到「维度 × 阶段 × 孩子正在做什么」。比如孩子说「不会写」：</p><ul><li><strong>1 分</strong>：针对当前缺口，给出孩子做得到的具体支架；</li><li><strong>0.5 分</strong>：有承接，但任务还笼统，「再写具体一点」这种；</li><li><strong>0 分</strong>：忽略求助，重复施压；</li><li><strong>看不出、缺前文</strong>：null。</li></ul><p>最后那个 null，是这轮真正学会的东西。</p><h2 id="不知道，就写不知道"><a href="#不知道，就写不知道" class="headerlink" title="不知道，就写不知道"></a>不知道，就写不知道</h2><p>信息不足、执行失败、确实表现差，是三件不同的事，不能都记成 0 分。</p><p>有道算术题让我印象很深：十轮对话，八轮 1 分、两轮 0 分，均值 0.8。把难评的那两轮改成 null 排除掉，覆盖率还有八成，均值变成 1.0。</p><p><strong>缺分不是随机的。</strong> 越难评的轮次越容易缺；哪个候选受益于「把难的排掉」，评估就会悄悄偏爱谁。所以缺分要记原因：没抽样、执行失败、上下文不足、证据不足，各是各的，不能一键当 null 剔掉。</p><h2 id="换了尺子，分数不能直接比"><a href="#换了尺子，分数不能直接比" class="headerlink" title="换了尺子，分数不能直接比"></a>换了尺子，分数不能直接比</h2><p>评估规则本身也在改：改判据、改权重、出候选版本。这里有个特别顺手的坑：新版本平均分比旧版本高，于是宣布「效果提升」。</p><p>可分数变了，可能只是刻度变了。两套规则的分数都是 0 到 100，不代表它们共用一把尺子。</p><p>所以后来把三样东西拆开记：规则是一个版本，辅导策略是一个版本，所有候选共同接受的公共参考再是一个版本。比较候选，用公共参考的尺度，不拿各自的总分互比。还有一条更狠的：不能让一套规则给自己优化出来的辅导策略打高分——那是老师给自己的学生判卷。</p><h2 id="谁来校准打分的-AI"><a href="#谁来校准打分的-AI" class="headerlink" title="谁来校准打分的 AI"></a>谁来校准打分的 AI</h2><p>最后是人的问题。AI 评分员也需要金标：两位教研独立盲评，分歧请第三人仲裁。</p><p>「八成一致率」听着不错。但样本只有二十条、对十六条的话，这个数字的置信区间大约是 58% 到 92%——下限只比抛硬币略好。样本不凑够，一致率本身就是一个不确定的数。</p><p>这周做第一批真实模型试评，同一条开场回复发给六个候选规则：六组全是 100 分。这不能说明六个规则一样好，只能说明这条材料没有区分度。好材料和坏材料都得有，分数才有含义。</p><h2 id="还没做的事"><a href="#还没做的事" class="headerlink" title="还没做的事"></a>还没做的事</h2><p>诚实清单：</p><ul><li>真实人工校准还没完成。攒下的真实评审样本全来自同一段对话，盲评标签也还没打完。</li><li>教学效果验证没开始。规则更可靠是一回事，孩子学得更好是另一回事，两件事要分别证明。</li></ul><p>上一篇的结尾是「先把什么不算数定清楚」。这一篇往下多走一步：<strong>连打分这件事本身，也得先证明自己算数。</strong></p><p>这是「工作心得记录」的第二篇。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/15/ai-grading-ruler/</id>
    <link href="https://blog.kfad127.xyz/2026/10/15/ai-grading-ruler/"/>
    <published>2026-10-15T03:30:00.000Z</published>
    <summary>满分也可能只是尺子没量到：锚点、缺分、跨版本分数和人工校准。</summary>
    <title>给 AI 打分之前，先检查一下尺子</title>
    <updated>2026-10-15T03:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="工作心得记录" scheme="https://blog.kfad127.xyz/categories/work-notes/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="复盘" scheme="https://blog.kfad127.xyz/tags/%E5%A4%8D%E7%9B%98/"/>
    <category term="教育" scheme="https://blog.kfad127.xyz/tags/%E6%95%99%E8%82%B2/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/composition-tutor-notes-cover.png" alt="教 AI 陪小学生写作文，这几个月的心得封面"></p><p>这几个月的主要工作，是给小学三到六年级的孩子做一个 AI 作文辅导：孩子跟它聊，它带着孩子把一篇作文从选题一步步做到落笔。产品还在内部迭代，没上线。</p><p>趁周末把最近的笔记翻了一遍，挑几条真正长经验的记下来。</p><p>先说明：这是公司项目，文中隐去了产品和内部细节，只留方法层面的心得，案例里的孩子一律化名。</p><span id="more"></span><h2 id="起点：一次自我审计"><a href="#起点：一次自我审计" class="headerlink" title="起点：一次自我审计"></a>起点：一次自我审计</h2><p>八月的时候，看到一篇公众号文章，讲 AI 辅导作业的种种坑。拿它当镜子照了照自己的产品，逐条对下来，宏观流程只有五成多对得上。</p><p>那天做的决定是：流程骨架保留，教学内核重做。</p><p>现在回头看，那个打分本身不重要，重要的是敢逐条对——AI 产品最容易的就是自我感觉良好，demo 顺一遍全是亮点。</p><h2 id="四条边界"><a href="#四条边界" class="headerlink" title="四条边界"></a>四条边界</h2><p>重做之后，给产品立了四条边界，需求过来都先过这四条：</p><ol><li><strong>不代写。</strong> AI 是辅导者，第一轮绝不交付完整作文。作文要孩子自己写。</li><li><strong>每轮一个节奏。</strong> 接住孩子说的话，形成一个看得见的小成果，然后只推进一个真实缺口。不多问，不抢答。</li><li><strong>分账。</strong> 孩子说的事实、AI 给的支架、AI 给的参考，严格分开记。AI 给的东西不计入孩子的能力——参考的权重是零。</li><li><strong>看证据不看轮数。</strong> 阶段推进靠孩子的有效证据，不是聊够几轮就跳下一阶段。孩子连说四句「不知道」，轮数再够也不该往前走。</li></ol><p>「轮数不等于学习成果」，这句话现在写在方案第一页。</p><h2 id="单测全绿，真实对话全挂"><a href="#单测全绿，真实对话全挂" class="headerlink" title="单测全绿，真实对话全挂"></a>单测全绿，真实对话全挂</h2><p>九月第一天，拿真实模型回放了四条完整对话案例。</p><p>四条全不通过：要么提前跳阶段，要么关键出口没交付。</p><p>而在这之前，离线测试是全绿的，两百多项。</p><p>这件事的教训后来被我原样写进了文档：<strong>当前最大的风险不是继续扩功能，而是把「离线单测通过」误当作「学生端体验已通过」。</strong></p><p>之后做了两件事。真实模型回放进发布流程；回归检查挂进 git 的 pre-commit 钩子，提交前强制跑，失败就拒绝提交。到现在回归涨到八百多项，其中一部分是把历史用户反馈的原话冻结成用例——二十多类问题，每类一条不漏。</p><h2 id="三个真实案例"><a href="#三个真实案例" class="headerlink" title="三个真实案例"></a>三个真实案例</h2><p>最近的迭代，基本是被三条真实对话推着走的：</p><p><strong>棋迷爷爷。</strong> 孩子说想写爷爷，爷爷爱下棋，是个大棋迷，顺口罗列了三个习惯。系统立刻认为选题完成，把框架导图和落笔任务全推了出来——可孩子也许只是随口说说，还没选定要写哪件事。更糟的是导图里人物那栏，生成的提示是「按题目要求安排这一部分」，一句空话。</p><p>修法：给「准备就绪」加了条件和产物核验——产物里有空话，就不算就绪。</p><p><strong>旧外号。</strong> 一个孩子已经补充了新的细节，AI 的回复还在引用三轮前的旧外号；孩子选好了场景，它又把事例重问一遍。根因是回应锚在了旧消息上。</p><p>修法：每轮回应强制绑定最新一条有效消息。</p><p><strong>从出汗推断着急。</strong> AI 在例文提示里写「妈妈多着急呀」。孩子只说过妈妈出了汗，「着急」是模型脑补的。这种无来源的情绪和因果，放在作文辅导里尤其危险——它是在教孩子编。</p><p>修法：AI 面向孩子的具体事实、情绪、因果和关系陈述，必须能回溯到孩子的原话或题目材料，回溯不到就不许出现。</p><p>三个案例修完，共同的教训是文档里那句：<strong>用单一案例特判修复，容易把人物、题目、年级写死，其他题型继续失败。</strong> 所以每条反馈都走同一个闭环：编号、根因分类、修复、用例、发布证据。不再拿单个孩子的故事打补丁。</p><h2 id="模型和代码怎么分工"><a href="#模型和代码怎么分工" class="headerlink" title="模型和代码怎么分工"></a>模型和代码怎么分工</h2><p>这几个月最大的架构心得，一句话能说完：</p><p><strong>Prompt 表达意图，不变量交给代码。</strong></p><p>模型负责语言和开放表达——把话说得让孩子听得懂、愿意接。但状态推进、事实核验、来源追溯、长度控制、失败兜底，全部是确定性的代码在管：规划器只输出候选 JSON，后端逐项核验；模型挂了就走规则兜底，绝不把失败提示甩给孩子。</p><p>只靠 Prompt 约束模型，迟早会多问、代写、提前跳阶段或者编造事实——不是模型不行，是把教学的不变量寄托在了概率上。</p><h2 id="还没做的事"><a href="#还没做的事" class="headerlink" title="还没做的事"></a>还没做的事</h2><p>诚实的部分：</p><ul><li>没上线。所有「重构」「升级」都发生在内部环境，线上效果一个字不敢提。</li><li>不宣称提升成绩。模拟评分的改善不等于孩子的学习效果，这句也写在报告里。</li><li>发现一个成本问题：多轮长对话里，内部状态坐标表能占到八成以上的输入，下一轮先给它瘦身。</li><li>一千二百道安全题集列好了，还没跑。</li></ul><h2 id="写在最后"><a href="#写在最后" class="headerlink" title="写在最后"></a>写在最后</h2><p>这几个月真正学会的，不是什么 Prompt 技巧，而是一个顺序问题：先把「什么不算数」定清楚——AI 给的不算孩子的能力，轮数不算成果，单测通过不算体验好——剩下的，才谈得上做好。</p><p>这是「工作心得记录」的第一篇。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/14/composition-tutor-notes/</id>
    <link href="https://blog.kfad127.xyz/2026/10/14/composition-tutor-notes/"/>
    <published>2026-10-14T09:20:00.000Z</published>
    <summary>单测全绿不等于孩子体验好：AI 作文辅导的边界、坑和方法。</summary>
    <title>教 AI 陪小学生写作文，这几个月的心得</title>
    <updated>2026-10-14T09:20:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="sanxing" scheme="https://blog.kfad127.xyz/categories/sanxing/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="亲子" scheme="https://blog.kfad127.xyz/tags/%E4%BA%B2%E5%AD%90/"/>
    <category term="产品设计" scheme="https://blog.kfad127.xyz/tags/%E4%BA%A7%E5%93%81%E8%AE%BE%E8%AE%A1/"/>
    <content>
      <![CDATA[<p><img src="/images/wechat-articles/03_fouryo_cover.png" alt="四岁的孩子，是怎么想事情的封面"></p><p>上一篇说到，我给上学的孩子做了一个对话小玩意：孩子放学跟它聊两句，家长那边收到一份温和的小结。</p><p>这个月它往前走了几步：有了名字，叫三省；里面陪聊的角色，叫小省。真正部署到了自己的服务器上，前后发了三个版本，九十多项自动回归测试和多轮对话的评测跑下来，全是绿的。</p><p>但有一件事，一直没敢写进完成栏：真实孩子的试用，还没开始。</p><p>而在组织试用之前，我先被家里四岁的小朋友上了一课。</p><span id="more"></span><h2 id="四岁的孩子，不回答「今天怎么样」"><a href="#四岁的孩子，不回答「今天怎么样」" class="headerlink" title="四岁的孩子，不回答「今天怎么样」"></a>四岁的孩子，不回答「今天怎么样」</h2><p>想理解四岁的孩子怎么想事情，先要接受一件事：他们的世界里，时间只有「刚才」和「不是刚才」。「昨天」泛指一切过去，「明天」泛指一切未来。你问「今天在幼儿园做了什么」，等于让一个没有目录的人做全文检索。</p><p>他们的叙述是拼图式的。讲一件事，跳着讲，中间插一段别的，再跳回来。主角的恐龙玩具缺了哪颗牙记得清清楚楚，事情发生在哪儿、当时还有谁，说不清。</p><p>情绪词的库存也很小：开心、生气、害怕、难过，差不多就这些。更多的情绪说不出来，直接演——突然不说话，突然摔东西，突然黏着你不放。</p><p>问「今天过得怎么样」，四岁的孩子基本给不出答案。不是不想说，是这个问题对他们来说太大。</p><h2 id="我开始让-AI-帮我「听」"><a href="#我开始让-AI-帮我「听」" class="headerlink" title="我开始让 AI 帮我「听」"></a>我开始让 AI 帮我「听」</h2><p>后来我换了个办法。小朋友颠三倒四讲事情的时候，我录下来，转成文字，交给模型。不求它给结论，只让它帮我列出来：这几段话里，反复出现的是什么。</p><p>就这么一件小事，第一周就看出一个我完全没注意到的东西：连续好几天，翻来覆去提到的，都是同一件很小的事。大人下班回家，注意力是碎的，听的时候在忙别的，孩子讲第二遍还会嫌烦。模型不一样，它最擅长的就是「又是它」。</p><p>但也很快被敲了一次警钟。有一次它顺手给了一段总结，特别通顺，特别像那么回事，其中一句还挺动人。我差点就信了，回头对着录音核了一遍——那句最关键的话，孩子根本没说过。</p><p>AI 帮我听，不能替我听。</p><p>这也是做三省时我最坚持的一条：日记正文只用孩子的原话摘录，模型不许改写、不许润色，每句话都能追溯到是哪一条消息来的。宁可留一份磕磕绊绊的真实，不要一份通顺漂亮的转述。</p><h2 id="「每日总结」这个词，本身就想错了"><a href="#「每日总结」这个词，本身就想错了" class="headerlink" title="「每日总结」这个词，本身就想错了"></a>「每日总结」这个词，本身就想错了</h2><p>前面说了，我最初的目标里有一条：帮孩子培养每日总结的习惯。</p><p>做了几个月，越做越觉得，这个说法是成人思维。总结是给有目录的人用的。四岁的孩子不需要总结，需要的是仪式——固定的时间，固定的一问，固定的一句话。</p><p>三省里有两条规定，我现在觉得放到哪个年龄都成立：</p><p>每轮只聊一个话题，每个话题最多轻轻追问一次。多问一句，聊天就变成审问——上一篇那张清单里，「连环追问」排第一条。</p><p>收尾的这句话，是整个产品里我最喜欢的：「谢谢你和小省聊。我们看看想记下的话吧，不记也可以。」最重要的其实是最后那半句，「不记也可以」。</p><p>还有一次实打实的改设计。最早的方案里，低龄的孩子如果说完沉默八秒，系统就自动把草稿保存下来，当时觉得这是贴心兜底。后来整段推翻，改成：沉默不自动保存。因为替孩子做主的那一刻，这个小本子就不再是他自己的了。</p><h2 id="习惯是长出来的，不是打卡打出来的"><a href="#习惯是长出来的，不是打卡打出来的" class="headerlink" title="习惯是长出来的，不是打卡打出来的"></a>习惯是长出来的，不是打卡打出来的</h2><p>落到四岁的小朋友身上，现在的做法土了很多：</p><p>睡前只问一个问题：「今天最喜欢的一秒钟是什么？」</p><p>心情不追问，指卡片。</p><p>不记录，不打卡，不复盘。过了大概一个星期，变成小朋友反过来提醒：「今天还没问呢。」</p><p>到这一步，我觉得这个习惯才算长出来了。它长在孩子自己身上，而不是长在一张表上。</p><h2 id="先承认我不会"><a href="#先承认我不会" class="headerlink" title="先承认我不会"></a>先承认我不会</h2><p>写到这里会发现，这篇里真正管用的，不是 AI 教会了孩子什么，而是 AI 帮我这个大人慢了下来、听得更仔细了一点。</p><p>三省的文档里，我一直留着一行话：自动检查通过，不代表人工评审通过；合成语料的评测，也不证明真实的孩子用起来合适。</p><p>四岁的这位，就是最严格的人工评审。</p><p>先过这一关，再说别的。</p><p>先记到这里。老规矩，不立 flag。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/14/four-year-old-thinking/</id>
    <link href="https://blog.kfad127.xyz/2026/10/14/four-year-old-thinking/"/>
    <published>2026-10-14T08:30:00.000Z</published>
    <summary>给上学的孩子做的小应用，被家里四岁的这位先上了一课。</summary>
    <title>四岁的孩子，是怎么想事情的</title>
    <updated>2026-10-14T08:30:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="sanxing" scheme="https://blog.kfad127.xyz/categories/sanxing/"/>
    <category term="AI" scheme="https://blog.kfad127.xyz/tags/AI/"/>
    <category term="亲子" scheme="https://blog.kfad127.xyz/tags/%E4%BA%B2%E5%AD%90/"/>
    <category term="产品设计" scheme="https://blog.kfad127.xyz/tags/%E4%BA%A7%E5%93%81%E8%AE%BE%E8%AE%A1/"/>
    <content>
      <![CDATA[<p><img src="/images/wechat-articles/02_wordlist_cover.png" alt="我列了一张清单：AI 不能对孩子说的话封面"></p><p>上一篇说到，想写一点自己折腾的小项目。</p><p>今天就写这个。</p><h2 id="事情的起点"><a href="#事情的起点" class="headerlink" title="事情的起点"></a>事情的起点</h2><p>这半年断断续续在做一个给孩子的 AI 对话小玩意。孩子放学后跟它聊两句，说说今天怎么样，家长那边收到一份温和的当日小结。</p><p>想法很简单。真做起来，第一个卡住我的不是技术，是一个问题：</p><p><strong>AI 哪些话不能说？</strong></p><p>代码可以让它什么都说。但什么都说，对一个七八岁的孩子，显然不行。</p><span id="more"></span><h2 id="列清单"><a href="#列清单" class="headerlink" title="列清单"></a>列清单</h2><p>于是我开始列清单。</p><p>一开始以为很快就能列完，不就说几句话嘛。结果列着列着，越列越长：</p><ul><li>不追问痛处。孩子说被批评了，不能连环追问「为什么被批评？你是不是做错了什么？」——听上去像审问。</li><li>不贴标签。「你就是太敏感了」「你就是不努力」这类句子，禁止出现。</li><li>不比较。「别人家的孩子都能……」这条我删得毫无犹豫。</li><li>不否定感受。孩子说难过，不能说「这有什么好难过的」。</li><li>不替大人许诺。「告诉你爸妈他们就不生气了」——我凭什么替他们许诺。</li><li>不教孩子瞒着家长。这条是底线，尤其当孩子说「别告诉我妈」的时候。</li><li>涉及安全的事（伤害自己、被欺负、被虐待），必须让大人知道，但方式要温和，不能吓到孩子。</li></ul><p>列到三四十条的时候，我停下来了。</p><h2 id="镜子"><a href="#镜子" class="headerlink" title="镜子"></a>镜子</h2><p>因为我发现，这张清单像一面镜子。</p><p>上面这些「AI 不能说的话」，有一大半，我自己——一个还算是耐心的家长——都说过。有的最近就说过。</p><p>「这有什么好难过的」，说过。</p><p>「你看人家谁谁谁」，说过。</p><p>追问「为什么就你被批评」，也说过。</p><p>不是说这些话的人是坏人。大多数时候是着急，是关心，是话赶话到了那儿。但这些话到了孩子耳朵里，就是清单上那一条。</p><p>有意思的地方在于：<strong>给机器立规矩容易，给自己立规矩难。</strong></p><p>给机器加上禁止规则和安全过滤，可以减少它说出这些话的机会，但不能保证永远不会出错，还需要持续测试和人工留意。人也不一样。人明知道不该说，着急的时候照样说。</p><h2 id="后来"><a href="#后来" class="headerlink" title="后来"></a>后来</h2><p>后来我把这张清单写进了代码，配了一个安全过滤模块。孩子的话先过一遍检测，有需要大人注意的信号，会用温和的方式让家长知道，而不是把原话直接转述出去。</p><p>什么算温和？简单说就是：让家长「留意」，而不是「监控」。</p><p>技术细节没什么可写的，网上教程很多。真正难的是这张清单本身——每一条背后都是一次「大人该怎么跟孩子说话」的取舍。</p><p>清单还在改。上个月孩子说了句什么，我犹豫半天要不要加一条，最后没加，因为我意识到那是我自己的问题，不是机器的问题。</p><p>先记到这里。</p><p>下一篇不知道什么时候。老规矩，不立 flag。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/14/ai-child-wordlist/</id>
    <link href="https://blog.kfad127.xyz/2026/10/14/ai-child-wordlist/"/>
    <published>2026-10-14T07:01:00.000Z</published>
    <summary>写安全过滤的时候，列着列着发现这张清单像面镜子。</summary>
    <title>我列了一张清单：AI 不能对孩子说的话</title>
    <updated>2026-10-14T07:01:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="日常生活" scheme="https://blog.kfad127.xyz/categories/daily-life/"/>
    <category term="随笔" scheme="https://blog.kfad127.xyz/tags/%E9%9A%8F%E7%AC%94/"/>
    <category term="记录" scheme="https://blog.kfad127.xyz/tags/%E8%AE%B0%E5%BD%95/"/>
    <content>
      <![CDATA[<p><img src="/images/wechat-articles/01_restart_cover.png" alt="很久没写东西了 想再开始记录一些封面"></p><p>很久没有在这里写东西了。</p><p>打开后台，上一篇文章的日期已经记不清。也不是没想过更新，只是每次打开就关上——不知道写什么，写了又觉得没必要发。</p><p>今天突然想，那就不想这些了。先写起来再说。</p><span id="more"></span><h2 id="想写，是因为有些东西不写就过去了"><a href="#想写，是因为有些东西不写就过去了" class="headerlink" title="想写，是因为有些东西不写就过去了"></a>想写，是因为有些东西不写就过去了</h2><p>最近半年，我做的事其实不少。看了一些东西，做了一些东西，也想过一些事。</p><p>但很多东西没有被记下来。</p><p>过几天回头想，只剩一点模糊的印象——「好像那阵子在折腾什么来着」。具体在折腾什么、当时怎么想的、为什么后来没继续，全都没了。</p><p>这种感觉挺奇怪的。明明是自己经历过的事，却像别人的事一样，只剩一句话的总结。</p><p>所以这次想试试，把那些当时觉得「值得想一下」的小事，随手写下来。</p><p>不是日记，也不是什么深度文章。就是一些片段。</p><h2 id="不打算给自己定什么计划"><a href="#不打算给自己定什么计划" class="headerlink" title="不打算给自己定什么计划"></a>不打算给自己定什么计划</h2><p>以前每次说要重新开始写，都会先做一份「内容规划」：</p><ul><li>每周更新几篇</li><li>主题分几个系列</li><li>第一个月发什么、第二个月发什么</li></ul><p>然后大多在第二周就停了。</p><p>这次不做规划。</p><p>想到什么就写什么，写完了就放上来。没想到的时候就不写。如果一个月只写一篇，那就一个月一篇。如果某周突然想写三篇，也行。</p><p>不给自己定目标，反而觉得轻松一些。</p><h2 id="大概会写一些什么"><a href="#大概会写一些什么" class="headerlink" title="大概会写一些什么"></a>大概会写一些什么</h2><p>也不是完全没有方向。</p><p>我自己是做技术的，平时会折腾一些 AI 工具、做一些小东西、也观察生活里的一些细节。这些可能都会写。</p><p>具体一点：</p><ul><li>自己在做的小项目，做到哪一步、卡在哪里、想到了什么</li><li>用各种 AI 工具的真实感受，不是评测，是「这玩意儿到底有没有用」的那种感受</li><li>偶尔写一些和孩子、和家人相关的观察</li><li>看到什么有意思的东西、读到什么觉得不错的内容，也可能记一下</li></ul><p>没那么严肃，也不追求每篇都「有用」。</p><h2 id="写给自己看"><a href="#写给自己看" class="headerlink" title="写给自己看"></a>写给自己看</h2><p>我知道公众号通常是写给读者看的，要考虑阅读量、互动、涨粉。</p><p>但这次我想先放下这些。</p><p>就当是给自己留一个记录的地方。如果有人看到，觉得某一段还行，那挺好。如果没什么人看，也没关系——反正东西在这儿了，过几年自己回头翻，能想起当时在做什么、在想什么，就够了。</p><p>这是第一篇。</p><p>下一篇不知道什么时候，写什么也不知道。</p><p>但应该不会再隔那么久了。</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2026/10/14/restart-writing/</id>
    <link href="https://blog.kfad127.xyz/2026/10/14/restart-writing/"/>
    <published>2026-10-14T07:00:00.000Z</published>
    <summary>不是为了什么目标，就是想写一点东西。</summary>
    <title>很久没写东西了 想再开始记录一些</title>
    <updated>2026-10-14T07:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="Hadoop" scheme="https://blog.kfad127.xyz/categories/hadoop/"/>
    <category term="hadoop" scheme="https://blog.kfad127.xyz/tags/hadoop/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/hive-hbase-cover.jpg" alt="hive 与 hbase 封面"></p><h3 id="一、从Hbase、hive如何产生的角度看"><a href="#一、从Hbase、hive如何产生的角度看" class="headerlink" title="一、从Hbase、hive如何产生的角度看"></a>一、从Hbase、hive如何产生的角度看</h3><p>Hadoop的起源于google的三大论文：</p><pre><code>GFS：Google的分布式文件系统Google File SystemMapReduce：Google的MapReduce开源分布式并行计算框架 BigTable：一个大型的分布式数据库</code></pre><p>其中的演变关系：</p><pre><code>GFS ——&gt; HDFSGoogle MapReduce——&gt;Hadoop MapReduce BigTable ——&gt; Hbase</code></pre><span id="more"></span><p>Hadoop的核心是HDFS和MapReduce，Hbase和hive都是在此基础上发展来的。HDFS（Hadoop Distributed File System，Hadoop分布式文件系统），它是一个高度容错性的系统，适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问，适合那些有着超大数据集（large data set）的应用程序。</p><p>Hbase作为面向列的数据库运行在HDFS之上，HDFS缺乏随即读写操作，Hbase正是为此而出现。HBase以Google BigTable为蓝本，以键值对的形式存储。项目的目标就是快速在主机内数十亿行数据中定位所需的数据并访问它。<br>MapReduce是一套从海量源数据提取分析元素最后返回结果集的编程模型。MapReduce的基本原理就是：将大的数据分析分成小块逐个分析，最后再将提取出来的数据汇总分析，最终获得我们想要的内容。</p><p>但是，MapReduce需要编写java代码，对于习惯使用mysql等数据库进行数据处理与分析的工作人员，使用不是很方便，Hive就由此而产生。</p><p>Hive起源于FaceBook，在Hadoop中扮演数据仓库的角色，建立在Hadoop集群的最顶层，对存储在Hadoop群上的数据提供类SQL的接口进行操作。你可以用 HiveQL进行select，join，等等操作。如果你有数据仓库的需求并且你擅长写SQL并且不想写MapReduce jobs就可以用Hive代替，用Hive开离线的进行数据处理与分析工作。</p><hr><h3 id="二、Hbase、Hive相关概况知识"><a href="#二、Hbase、Hive相关概况知识" class="headerlink" title="二、Hbase、Hive相关概况知识"></a>二、Hbase、Hive相关概况知识</h3><p>Hbase是一个数据库，一个NoSql的数据库，像其他数据库一样提供随即读写功能，Hadoop不能满足实时需要，Hbase正可以满足。如果你需要实时访问一些数据，就把它存入HBase。</p><p>官方对Hbase的解释：</p><pre><code>Use Apache HBase™ when you need random, realtime read/write access to your Big Data. This project&#39;s goal is the hosting of very large tables -- billions of rows X millions of columns – a top clusters of commodity hardware. </code></pre><p>Hbase以键值对的形式储存数据。其包含了4种主要的数据操作方式:</p><ol><li>添加或更新数据行；</li><li>扫描获取某范围内的cells；</li><li>为某一具体数据行返回对应的cells；</li><li>从数据表中删除数据行&#x2F;列，或列的描述信息，列信息可用于获取数据变动前的取值；</li></ol><p>Hive是基于Hadoop的一个数据仓库工具，可以将结构化的数据文件映射为一张数据库表，并提供完整的sql查询功能，可以将sql语句转换为MapReduce任务进行运行。</p><p>官方对Hive的解释：</p><pre><code>The Apache Hive ™ data warehouse software facilitates reading, writing, and managing large datasets residing in distributed storage using SQL. Structure can be projected onto data already in storage.A command line tool and JDBC driver are provided to connect users to Hive.</code></pre><p>Hive以表的形式存储数据。其数据存储模型主要有：</p><ol><li>内部表。分为真实数据（存储在HDFS上）和表格中的元数据（存储在关系型数据库中）；</li><li>外部表。建立与HDFS与Hbase的映射，指定仓库目录以外的位置访问数据；</li><li>分区。对表进行分区管理，提高管理与查询效率；</li><li>桶。把表组织成桶，更加高效的处理与查询大规模数据集；</li></ol><hr><h3 id="三、两者的使用场景"><a href="#三、两者的使用场景" class="headerlink" title="三、两者的使用场景"></a>三、两者的使用场景</h3><ul><li>Hbase的应用场景：</li></ul><ol><li>成熟的数据分析主题，查询模式已经确立，并且不会轻易改变；</li><li>传统的关系型数据库已经无法承受负荷，高速插入，大量读取；</li></ol><ul><li>Hive的应用场景：</li></ul><ol><li>Hive适用于网络日志等数据量大、静态的数据查询。例如：用户消费行为记录，网站访问足迹等。但是不适用于联机实时在线查询的场合。</li><li>Hive更适合于数据仓库的任务，Hive主要用于静态的结构以及需要经常分析的工作。Hive与SQL相似促使 其成为Hadoop与其他BI工具结合的理想交集</li></ol><hr><h3 id="四、Hive与Hbase的联系与区别"><a href="#四、Hive与Hbase的联系与区别" class="headerlink" title="四、Hive与Hbase的联系与区别"></a>四、Hive与Hbase的联系与区别</h3><ul><li>联系：</li></ul><p>Hbase与Hive都是架构在hadoop之上的，都是用HDFS作为底层存储的；<br>Hbase可以在Hive中建立映射，在Hive上分析Hbase中表的数据；</p><ul><li>区别：</li></ul><p>Hive本身不存储和计算数据，它完全依赖于HDFS和MapReduce，Hive中的表纯逻辑。Hive需要用到HDFS存储文件，需要用到MapReduce计算框架。</p><p>Hbase是物理表，不是逻辑表，提供一个超大的内存hash表，搜索引擎通过它来存储索引，方便查询操作；</p><hr><h5 id="Ps"><a href="#Ps" class="headerlink" title="Ps:"></a>Ps:</h5><p>转自一篇网上的一段评论</p><p>“hive和hbase哪里像了，好像哪里都不像，既然哪里都不像，又何来的“区别是什么”这一问题，他俩所有的都算区别。</p><p>那么，hive是什么？</p><p>白话一点再加不严格一点，hive可以认为是map-reduce的一个包装。hive的意义就是把好写的hive的sql转换为复杂难写的map-reduce程序。</p><p>于是，hbase是什么？</p><p>同样白话一点加不严格一点，hbase可以认为是hdfs的一个包装。他的本质是数据存储，是个NoSql数据库；hbase部署于hdfs之上，并且克服了hdfs在随机读写方面的缺点。”       </p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2018/05/04/hive%E4%B8%8Ehbase/</id>
    <link href="https://blog.kfad127.xyz/2018/05/04/hive%E4%B8%8Ehbase/"/>
    <published>2018-05-04T06:58:00.000Z</published>
    <summary>
      <![CDATA[<p><img src="/images/covers/hive-hbase-cover.jpg" alt="hive 与 hbase 封面"></p>
<h3 id="一、从Hbase、hive如何产生的角度看"><a href="#一、从Hbase、hive如何产生的角度看" class="headerlink" title="一、从Hbase、hive如何产生的角度看"></a>一、从Hbase、hive如何产生的角度看</h3><p>Hadoop的起源于google的三大论文：</p>
<pre><code>GFS：Google的分布式文件系统Google File System
MapReduce：Google的MapReduce开源分布式并行计算框架 
BigTable：一个大型的分布式数据库
</code></pre>
<p>其中的演变关系：</p>
<pre><code>GFS ——&gt; HDFS
Google MapReduce——&gt;Hadoop MapReduce 
BigTable ——&gt; Hbase
</code></pre>]]>
    </summary>
    <title>hive 与 hbase</title>
    <updated>2018-05-04T06:58:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <category term="Hadoop" scheme="https://blog.kfad127.xyz/categories/hadoop/"/>
    <category term="impala" scheme="https://blog.kfad127.xyz/tags/impala/"/>
    <content>
      <![CDATA[<p><img src="/images/covers/impala-tests-cover.jpg" alt="impala测试封面"></p><h4 id="测试思路"><a href="#测试思路" class="headerlink" title="测试思路"></a>测试思路</h4><ul><li><p>从单表开始，区分外部表与内部表，进行count、group by等</p></li><li><p>多表关联，join</p></li></ul><span id="more"></span><h4 id="测试过程"><a href="#测试过程" class="headerlink" title="测试过程"></a>测试过程</h4><hr><h5 id="一、-单表测试-（选取外部表-：weblog-clicklog）"><a href="#一、-单表测试-（选取外部表-：weblog-clicklog）" class="headerlink" title="一、 单表测试 （选取外部表 ：weblog.clicklog）"></a>一、 单表测试 （选取外部表 ：weblog.clicklog）</h5><h5 id="测试sql"><a href="#测试sql" class="headerlink" title="测试sql"></a>测试sql</h5><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) <span class="keyword">from</span> test.log t <span class="keyword">where</span> t.day <span class="operator">&gt;=</span> <span class="string">&#x27;20180101&#x27;</span></span><br></pre></td></tr></table></figure><blockquote><p>注：impala里不是默认数字为字符串，表中day类型为string，故必须加引号，hive里不需要;</p></blockquote><h5 id="在执行sql程序时，需要查看表结构和表列结构，以及sql查询的执行计划"><a href="#在执行sql程序时，需要查看表结构和表列结构，以及sql查询的执行计划" class="headerlink" title="在执行sql程序时，需要查看表结构和表列结构，以及sql查询的执行计划"></a>在执行sql程序时，需要查看表结构和表列结构，以及sql查询的执行计划</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">SHOW TABLE STATS test.log; <span class="comment">// 查看表结构</span></span><br><span class="line"><span class="comment">//部分结果：</span></span><br><span class="line">[master3.xxx:<span class="number">21000</span>] &gt; show table stats test.log;</span><br><span class="line">Query: show table stats test.log</span><br><span class="line">+----------+------------+--------+-----------+--------------+-------------------+--------+-------------------+------------------------------------+</span><br><span class="line">| day      | #Rows      | #Files | Size      | Bytes Cached | Cache Replication | Format | Incremental stats | Location                           |</span><br><span class="line">+----------+------------+--------+-----------+--------------+-------------------+--------+-------------------+------------------------------------+</span><br><span class="line">| <span class="number">2011</span>     | <span class="number">67949737</span>   | <span class="number">27</span>     | <span class="number">10.</span>83GB   | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/2011         |</span></span><br><span class="line">| <span class="number">2012</span>     | <span class="number">192232112</span>  | <span class="number">43</span>     | <span class="number">29.</span>28GB   | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/2012         |</span></span><br><span class="line">| <span class="number">2013</span>     | <span class="number">228772618</span>  | <span class="number">49</span>     | <span class="number">38.</span>02GB   | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/2013         |</span></span><br><span class="line">| <span class="number">2014</span>     | <span class="number">297606490</span>  | <span class="number">58</span>     | <span class="number">49.</span>50GB   | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/2014         |</span></span><br><span class="line">| <span class="number">2015</span>     | <span class="number">242917770</span>  | <span class="number">46</span>     | <span class="number">41.</span>65GB   | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/2015         |</span></span><br><span class="line">| <span class="number">2016</span>     | <span class="number">601817475</span>  | <span class="number">59</span>     | <span class="number">111.</span>37GB  | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/2016         |</span></span><br><span class="line">| <span class="number">20170314</span> | <span class="number">62669849</span>   | <span class="number">116</span>    | <span class="number">14.</span>64GB   | NOT CACHED   | NOT CACHED        | TEXT   | <span class="literal">true</span>              | hdfs:<span class="comment">//outputpath/log/fullvisitlog</span></span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">SHOW COLUMN STATS test.log; <span class="comment">// 查看表列结构</span></span><br><span class="line"><span class="comment">//示例：</span></span><br><span class="line">[master3.xxx:<span class="number">21000</span>] &gt; show column stats test.log;</span><br><span class="line">Query: show column stats test.log</span><br><span class="line">+------------------+--------+------------------+--------+----------+-------------------+</span><br><span class="line">| Column           | Type   | #Distinct Values | #Nulls | Max Size | Avg Size          |</span><br><span class="line">+------------------+--------+------------------+--------+----------+-------------------+</span><br><span class="line">| sessionid        | STRING | <span class="number">5482802</span>          | -<span class="number">1</span>     | <span class="number">42</span>       | <span class="number">9.360500335693359</span> |</span><br><span class="line">| id               | INT    | <span class="number">6539936</span>          | -<span class="number">1</span>     | <span class="number">4</span>        | <span class="number">4</span>                 |</span><br><span class="line">| ip               | STRING | <span class="number">11691739</span>         | -<span class="number">1</span>     | <span class="number">20</span>       | <span class="number">13.18490028381348</span> |</span><br><span class="line">| day              | STRING | <span class="number">329</span>              | <span class="number">0</span>      | -<span class="number">1</span>       | -<span class="number">1</span>                |</span><br><span class="line">+------------------+--------+------------------+--------+----------+-------------------+</span><br></pre></td></tr></table></figure><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">explain <span class="keyword">select</span> <span class="built_in">count</span>(<span class="operator">*</span>) <span class="keyword">from</span> test.log t <span class="comment">-- 查看sql执行计划</span></span><br><span class="line"><span class="comment">--示例：</span></span><br><span class="line">[master3.xxx:<span class="number">21000</span>] <span class="operator">&gt;</span> explain <span class="keyword">select</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) <span class="keyword">from</span> test.log t <span class="keyword">where</span> t.day <span class="operator">&gt;=</span> <span class="string">&#x27;20180101&#x27;</span>;</span><br><span class="line">Query: explain <span class="keyword">select</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) <span class="keyword">from</span> test.log t <span class="keyword">where</span> t.day <span class="operator">&gt;=</span> <span class="string">&#x27;20180101&#x27;</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> Explain String                                                                     <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> Max <span class="keyword">Per</span><span class="operator">-</span>Host Resource Reservation: Memory<span class="operator">=</span><span class="number">68.00</span>MB                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="keyword">Per</span><span class="operator">-</span>Host Resource Estimates: Memory<span class="operator">=</span><span class="number">3.52</span>GB                                         <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> WARNING: The following tables <span class="keyword">are</span> missing relevant <span class="keyword">table</span> <span class="keyword">and</span><span class="operator">/</span><span class="keyword">or</span> <span class="keyword">column</span> statistics. <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> weblog.clicklog                                                                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>                                                                                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> PLAN<span class="operator">-</span>ROOT SINK                                                                     <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">06</span>:AGGREGATE [FINALIZE]                                                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  output: count:<span class="keyword">merge</span>(t.id)                                                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">05</span>:EXCHANGE [UNPARTITIONED]                                                        <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">02</span>:AGGREGATE                                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  output: <span class="built_in">count</span>(t.id)                                                          <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">04</span>:AGGREGATE                                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: t.id                                                               <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">03</span>:EXCHANGE [HASH(t.id)]                                                        <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">01</span>:AGGREGATE [STREAMING]                                                           <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: t.id                                                               <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">00</span>:SCAN HDFS [test.log t]                                                   <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>    partitions<span class="operator">=</span><span class="number">38</span><span class="operator">/</span><span class="number">329</span> files<span class="operator">=</span><span class="number">119</span> size<span class="operator">=</span><span class="number">17.38</span>GB                                        <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">------------------------------------------------------------------------------------+</span></span><br></pre></td></tr></table></figure><blockquote><p>注：如果表每日都会更新时，需要对impala中的表更新，才能与hive中的表同步；</p></blockquote><h5 id="impala与hive同步"><a href="#impala与hive同步" class="headerlink" title="impala与hive同步"></a>impala与hive同步</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">INVALIDATE METADATA;                   <span class="comment">//重新加载所有库中的所有表</span></span><br><span class="line"></span><br><span class="line">INVALIDATE METADATA [table] ;           <span class="comment">//重新加载指定的某个表</span></span><br><span class="line"></span><br><span class="line">REFRESH [table];                             <span class="comment">//刷新某个表</span></span><br><span class="line"></span><br><span class="line">REFRESH [table] PARTITION [partition];       <span class="comment">//刷新某个表的某个分区</span></span><br></pre></td></tr></table></figure><ul><li>使用原则</li></ul><p>如果在使用过程中涉及到了元数据或者数据的更新，则需要使用这两者中的一个操作完成，具体如何选择需要根据如下原则：</p><ol><li>invalidate metadata操作比refresh要重量级;</li><li>如果涉及到表的schema改变，使用invalidate metadata [table]，eg：在hive中create表后，需要在impala使用invalidate metadata [table];</li><li>如果只是涉及到表的数据改变，使用refresh [table];</li><li>如果只是涉及到表的某一个分区数据改变，使用refresh [table] partition [partition];</li><li>禁止使用invalidate metadata什么都不加，宁愿重启catalogd;</li></ol><h5 id="测试结果"><a href="#测试结果" class="headerlink" title="测试结果"></a>测试结果</h5><p>impala</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">[master3.xxx:21000] &gt; select count(distinct t.id) from test.log t where t.day &gt;= &#x27;20180101&#x27;;</span><br><span class="line">Query: select count(distinct t.id) from test.log t where t.day &gt;= &#x27;20180101&#x27;</span><br><span class="line">Query submitted at: 2018-02-08 11:26:49 (Coordinator: http://master3.xxx:25000)</span><br><span class="line">Query progress can be monitored at: http://master3.xxx.cn:25000/query_plan?query_id=26450a1b2ff192cd:4eb613700000000</span><br><span class="line">+-------------------------+</span><br><span class="line">| count(distinct t.webid) |</span><br><span class="line">+-------------------------+</span><br><span class="line">| 537135                  |</span><br><span class="line">+-------------------------+</span><br><span class="line">Fetched 1 row(s) in 56.45s</span><br></pre></td></tr></table></figure><p>hive</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">hive&gt; select count(distinct t.id) from test.log t where t.day &gt;= &#x27;20180101&#x27;;</span><br><span class="line">Query ID = knox_20180208113005_f7aa9011-fbc0-4355-86c5-5877d0b9e385</span><br><span class="line">Total jobs = 1</span><br><span class="line">Launching Job 1 out of 1</span><br><span class="line">Tez session was closed. Reopening...</span><br><span class="line">Session re-established.</span><br><span class="line">Status: Running (Executing on YARN cluster with App id application_1517483782112_3346)</span><br><span class="line"></span><br><span class="line">--------------------------------------------------------------------------------</span><br><span class="line">        VERTICES      STATUS  TOTAL  COMPLETED  RUNNING  PENDING  FAILED  KILLED</span><br><span class="line">--------------------------------------------------------------------------------</span><br><span class="line">Map 1 ..........   SUCCEEDED    950        950        0        0       0       0</span><br><span class="line">Reducer 2 ......   SUCCEEDED     70         70        0        0       0       0</span><br><span class="line">Reducer 3 ......   SUCCEEDED      1          1        0        0       0       0</span><br><span class="line">--------------------------------------------------------------------------------</span><br><span class="line">VERTICES: 03/03  [==========================&gt;&gt;] 100%  ELAPSED TIME: 53.57 s</span><br><span class="line">--------------------------------------------------------------------------------</span><br><span class="line">OK</span><br><span class="line">537135</span><br><span class="line">Time taken: 71.619 seconds, Fetched: 1 row(s)</span><br></pre></td></tr></table></figure><ul><li><p>从测试结果上看，两者从运行速度上并没有什么差别，没有网上说的比hive有十倍或者十几倍的差距；</p></li><li><p>故考虑impala的性能优化</p></li></ul><h5 id="impala性能优化"><a href="#impala性能优化" class="headerlink" title="impala性能优化"></a>impala性能优化</h5><p>目前从表结构以及执行计划中发现的，并结合网上查找的资料，进行以下两点优化，以后对impala有更深的了解后，再进行补充：</p><h5 id="1-表的存储结构"><a href="#1-表的存储结构" class="headerlink" title="1. 表的存储结构"></a>1. 表的存储结构</h5><p>从SHOW TABLE STATS命令中可以发现 表的format，上述测试的test.log的format是TEXT；</p><p>在网上查找资料，参考<a target="_blank" rel="noopener" href="http://blog.csdn.net/mtj66/article/details/53968991">hive表的文件存储格式</a></p><p>发现parquet格式与impala组合会提高表的查询效率，故测试建立parquet存储格式的临时表；</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- hive</span></span><br><span class="line"><span class="keyword">create table</span> temp_log_20180209 <span class="keyword">as</span></span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> test.log t <span class="keyword">where</span> t.day <span class="operator">&gt;=</span> <span class="string">&#x27;20180101&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">create table</span> temp_parquet_log_20180209 <span class="keyword">like</span> temp_log_20180209 stored <span class="keyword">as</span> parquet;</span><br><span class="line"></span><br><span class="line"><span class="keyword">insert</span> overwrite <span class="keyword">table</span> temp_parquet_log_20180209</span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> temp_log_20180209;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- impala</span></span><br><span class="line">invalidate metadata temp_parquet_log_20180209;</span><br><span class="line">refresh temp_parquet_log_20180209;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 查询一下表，看表是否与hive同步</span></span><br><span class="line"><span class="keyword">select</span> <span class="operator">*</span> <span class="keyword">from</span> temp_parquet_log_20180209 limit <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- 测试sql</span></span><br><span class="line"><span class="keyword">select</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) <span class="keyword">from</span> temp_parquet_log_20180209 t;</span><br><span class="line"></span><br><span class="line">[master3.xxx:<span class="number">21000</span>] <span class="operator">&gt;</span> <span class="keyword">select</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) <span class="keyword">from</span> temp_parquet_log_20180209 t;</span><br><span class="line">Query: <span class="keyword">select</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) <span class="keyword">from</span> temp_parquet_log_20180209 t</span><br><span class="line">Query submitted <span class="keyword">at</span>: <span class="number">2018</span><span class="number">-02</span><span class="number">-09</span> <span class="number">10</span>:<span class="number">41</span>:<span class="number">47</span> (Coordinator: http:<span class="operator">/</span><span class="operator">/</span>master3.xxx:<span class="number">25000</span>)</span><br><span class="line">Query progress can be monitored <span class="keyword">at</span>: http:<span class="operator">/</span><span class="operator">/</span>master3.xxx:<span class="number">25000</span><span class="operator">/</span>query_plan?query_id<span class="operator">=</span><span class="number">3e419</span>e1a5cd39ff3:<span class="number">214415700000000</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------+</span></span><br><span class="line"><span class="operator">|</span> <span class="built_in">count</span>(<span class="keyword">distinct</span> t.id)    <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------+</span></span><br><span class="line"><span class="operator">|</span> <span class="number">543267</span>                  <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">-------------------------+</span></span><br><span class="line">Fetched <span class="number">1</span> <span class="type">row</span>(s) <span class="keyword">in</span> <span class="number">2.50</span>s</span><br><span class="line"></span><br><span class="line"><span class="comment">--ps: 与之前TEXT格式测试的结果不一致时因为文档编写时间不在同一天，sql选取的时间（20180101——当前日期）在同一天结果是一致的；</span></span><br></pre></td></tr></table></figure><p>表的存储格式修改后，impala的查询效率确定有提高，从56.25s 到 2.50s ;</p><h5 id="2-表信息计算"><a href="#2-表信息计算" class="headerlink" title="2. 表信息计算"></a>2. 表信息计算</h5><p>在explain命令中，查看执行计划中发现里面存在warning，在网上查找资料，了解warning内容；</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WARNING: The following tables are missing relevant table and/or column statistics.</span><br></pre></td></tr></table></figure><p>大致意思应该是缺失对表的表信息与列信息的统计数据;</p><p>当统计信息可用时，Impala 可以更好的优化复杂的或多表查询，可以更好地理解数据量和值的分布，并使用这些信息帮助查询并行处理和分布负载。这里impala提供里对表信息更详尽统计的命令：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">COMPUTE STATS tablename;  <span class="comment">//对于不分区的表，或者虽然分区，但一次加载，不会再更新新分区的表，使用COMPUTE STATS更好</span></span><br><span class="line"></span><br><span class="line">COMPUTE INCREMENTAL STATS tablename; <span class="comment">//更适合要频繁增加具有大量数据的分区的表</span></span><br><span class="line"></span><br><span class="line">COMPUTE INCREMENTAL STATS test.<span class="type">log</span> <span class="title function_">PARTITION</span><span class="params">(day=<span class="string">&#x27;20180208&#x27;</span>)</span>; <span class="comment">//单独添加一个分区的例子</span></span><br></pre></td></tr></table></figure><hr><h5 id="二、表关联查询-join"><a href="#二、表关联查询-join" class="headerlink" title="二、表关联查询 (join)"></a>二、表关联查询 (join)</h5><p>选取表：temp_parquet_log_20180209 、parquet_user(存储格式为parquet的用户信息表)</p><h5 id="测试sql-1"><a href="#测试sql-1" class="headerlink" title="测试sql"></a>测试sql</h5><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- impala</span></span><br><span class="line"><span class="keyword">select</span> u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line"><span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line"><span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line">[master3.xxx:<span class="number">21000</span>] <span class="operator">&gt;</span> <span class="keyword">select</span> u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line">                              <span class="operator">&gt;</span> <span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line">                              <span class="operator">&gt;</span> <span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line">                              <span class="operator">&gt;</span> <span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span>;</span><br><span class="line">Query: <span class="keyword">select</span> u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line"><span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line"><span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span></span><br><span class="line">Query submitted <span class="keyword">at</span>: <span class="number">2018</span><span class="number">-02</span><span class="number">-09</span> <span class="number">11</span>:<span class="number">45</span>:<span class="number">40</span> (Coordinator: http:<span class="operator">/</span><span class="operator">/</span>master3.xxx:<span class="number">25000</span>)</span><br><span class="line">Query progress can be monitored <span class="keyword">at</span>: http:<span class="operator">/</span><span class="operator">/</span>master3.xxx:<span class="number">25000</span><span class="operator">/</span>query_plan?query_id<span class="operator">=</span><span class="number">411</span>b014308ff95:ea54e37200000000</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------+-------+</span></span><br><span class="line"><span class="operator">|</span> province_name <span class="operator">|</span> nums  <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------+-------+</span></span><br><span class="line"><span class="operator">|</span> AAA          <span class="operator">|</span> <span class="number">7542</span>  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> BBB          <span class="operator">|</span> <span class="number">492</span>   <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">--------------+-------+</span></span><br><span class="line">Fetched <span class="number">5</span> <span class="type">row</span>(s) <span class="keyword">in</span> <span class="number">15.67</span>s</span><br><span class="line"></span><br><span class="line"><span class="comment">-- hive</span></span><br><span class="line">hive<span class="operator">&gt;</span> <span class="keyword">select</span> u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line">    <span class="operator">&gt;</span> <span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line">    <span class="operator">&gt;</span> <span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line">    <span class="operator">&gt;</span> <span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span>;</span><br><span class="line">Query ID <span class="operator">=</span> knox_20180209113911_032594e3<span class="number">-15</span>aa<span class="number">-4063</span><span class="number">-9300</span><span class="number">-58</span>aefe2d94f8</span><br><span class="line">Total jobs <span class="operator">=</span> <span class="number">1</span></span><br><span class="line">Launching Job <span class="number">1</span> <span class="keyword">out</span> <span class="keyword">of</span> <span class="number">1</span></span><br><span class="line">Tez session was closed. Reopening...</span><br><span class="line">Session re<span class="operator">-</span>established.</span><br><span class="line">Status: <span class="keyword">Running</span> (Executing <span class="keyword">on</span> YARN cluster <span class="keyword">with</span> App id application_1517483782112_3824)</span><br><span class="line"></span><br><span class="line"><span class="comment">--------------------------------------------------------------------------------</span></span><br><span class="line">        VERTICES      STATUS  TOTAL  COMPLETED  <span class="keyword">RUNNING</span>  PENDING  FAILED  KILLED</span><br><span class="line"><span class="comment">--------------------------------------------------------------------------------</span></span><br><span class="line">Map <span class="number">1</span> ..........   SUCCEEDED    <span class="number">227</span>        <span class="number">227</span>        <span class="number">0</span>        <span class="number">0</span>       <span class="number">0</span>       <span class="number">0</span></span><br><span class="line">Map <span class="number">3</span> ..........   SUCCEEDED     <span class="number">51</span>         <span class="number">51</span>        <span class="number">0</span>        <span class="number">0</span>       <span class="number">0</span>       <span class="number">0</span></span><br><span class="line">Reducer <span class="number">2</span> ......   SUCCEEDED      <span class="number">4</span>          <span class="number">4</span>        <span class="number">0</span>        <span class="number">0</span>       <span class="number">0</span>       <span class="number">0</span></span><br><span class="line"><span class="comment">--------------------------------------------------------------------------------</span></span><br><span class="line">VERTICES: <span class="number">03</span><span class="operator">/</span><span class="number">03</span>  [<span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">=</span><span class="operator">&gt;&gt;</span>] <span class="number">100</span><span class="operator">%</span>  ELAPSED <span class="type">TIME</span>: <span class="number">86.82</span> s</span><br><span class="line"><span class="comment">--------------------------------------------------------------------------------</span></span><br><span class="line">OK</span><br><span class="line">AAA  <span class="number">7542</span></span><br><span class="line">BBB  <span class="number">492</span></span><br><span class="line"><span class="type">Time</span> taken: <span class="number">97.863</span> seconds, Fetched: <span class="number">5</span> <span class="type">row</span>(s)</span><br></pre></td></tr></table></figure><p>这里，我已经对两个表进行了compute table的处理，可以看出效率比hive高，但是，我们在查询之前却没有看sql的执行计划，看是否还有调优的地方；</p><h4 id="join调优的原则"><a href="#join调优的原则" class="headerlink" title="join调优的原则"></a>join调优的原则</h4><ol><li>最大的表放首位。这个表在查询的时候是每个impala节点直接从磁盘读取的，因此它的大小对于内存使用没影响。</li><li>然后按表大小有大到小依次排序。这些表的内容全部都是要在网络中传递的，所以，表越到后面越小越好。</li><li>通过执行COMPUTE STATS来收集涉及到的所有表的统计信息</li></ol><blockquote><p>值得注意的一点是，这里的“大小”是就每个表在查询后生成的中间结果涉及到的行的数量来定的。比如，一次查询，要join两个表：销售表和用户表。查询的结果是100个不同的用户共有5000条消费记录。因为涉及用户表的行比销售表少（100&lt;5000）。所以用户表应该放在后面（右边）</p></blockquote><h4 id="join调优"><a href="#join调优" class="headerlink" title="join调优"></a>join调优</h4><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">-- 执行查询计划</span></span><br><span class="line"><span class="keyword">select</span> u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line"><span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line"><span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span>;</span><br><span class="line"><span class="comment">-- 这里只列出执行计划结果</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> Explain String                                          <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> Max <span class="keyword">Per</span><span class="operator">-</span>Host Resource Reservation: Memory<span class="operator">=</span><span class="number">105.94</span>MB      <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="keyword">Per</span><span class="operator">-</span>Host Resource Estimates: Memory<span class="operator">=</span><span class="number">14.52</span>GB             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>                                                         <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> PLAN<span class="operator">-</span>ROOT SINK                                          <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">10</span>:EXCHANGE [UNPARTITIONED]                             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  limit: <span class="number">5</span>                                             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">09</span>:AGGREGATE [FINALIZE]                                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  output: count:<span class="keyword">merge</span>(t.id)                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  limit: <span class="number">5</span>                                             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">08</span>:EXCHANGE [HASH(u.province_name)]                     <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">04</span>:AGGREGATE [STREAMING]                                <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  output: <span class="built_in">count</span>(t.id)                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">07</span>:AGGREGATE                                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name,  t.id                     <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">06</span>:EXCHANGE [HASH(u.province_name,t.id)]                <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">03</span>:AGGREGATE [STREAMING]                                <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name,  t.id                     <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">02</span>:HASH <span class="keyword">JOIN</span> [<span class="keyword">INNER</span> <span class="keyword">JOIN</span>, BROADCAST]                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  hash predicates: u.id <span class="operator">=</span> t.id                         <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  runtime filters: RF000 <span class="operator">&lt;</span><span class="operator">-</span> t.id                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span><span class="comment">--05:EXCHANGE [BROADCAST]                              |</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="operator">|</span>                                                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="number">00</span>:SCAN HDFS [temp_parquet_log_20180209 t]           <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>     partitions<span class="operator">=</span><span class="number">1</span><span class="operator">/</span><span class="number">1</span> files<span class="operator">=</span><span class="number">976</span> size<span class="operator">=</span><span class="number">3.09</span>GB              <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">01</span>:SCAN HDFS [parquet_user u]                           <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>    partitions<span class="operator">=</span><span class="number">1</span><span class="operator">/</span><span class="number">1</span> files<span class="operator">=</span><span class="number">4</span> size<span class="operator">=</span><span class="number">811.63</span>MB                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>    runtime filters: RF000 <span class="operator">-</span><span class="operator">&gt;</span> u.id                       <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------+</span></span><br></pre></td></tr></table></figure><p>从执行计划里可以看出，第二步 hash关联中，是由 用户表中的id 关联 轨迹日志中的id，并不是由轨迹日志(大)到 用户表(小);</p><p>impala中提供了一个straight_join关键词，手动调整关联顺序，即按照sql语句的顺序，而不采用impala中自动优化查询；</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">explain <span class="keyword">select</span> straight_join u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line"><span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line"><span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span>;</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> Explain String                                          <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------+</span></span><br><span class="line"><span class="operator">|</span> Max <span class="keyword">Per</span><span class="operator">-</span>Host Resource Reservation: Memory<span class="operator">=</span><span class="number">105.94</span>MB      <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="keyword">Per</span><span class="operator">-</span>Host Resource Estimates: Memory<span class="operator">=</span><span class="number">14.75</span>GB             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>                                                         <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> PLAN<span class="operator">-</span>ROOT SINK                                          <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">10</span>:EXCHANGE [UNPARTITIONED]                             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  limit: <span class="number">5</span>                                             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">09</span>:AGGREGATE [FINALIZE]                                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  output: count:<span class="keyword">merge</span>(t.id)                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  limit: <span class="number">5</span>                                             <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">08</span>:EXCHANGE [HASH(u.province_name)]                     <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">04</span>:AGGREGATE [STREAMING]                                <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  output: <span class="built_in">count</span>(t.id)                                  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">07</span>:AGGREGATE                                            <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name, u.area_name, t.id         <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">06</span>:EXCHANGE [HASH(u.province_name,t.id)]                <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">03</span>:AGGREGATE [STREAMING]                                <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="keyword">group</span> <span class="keyword">by</span>: u.province_name,  t.id                     <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">02</span>:HASH <span class="keyword">JOIN</span> [<span class="keyword">INNER</span> <span class="keyword">JOIN</span>, BROADCAST]                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  hash predicates: t.id <span class="operator">=</span> u.id                         <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  runtime filters: RF000 <span class="operator">&lt;</span><span class="operator">-</span> u.id                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span><span class="comment">--05:EXCHANGE [BROADCAST]                              |</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="operator">|</span>                                                    <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>  <span class="number">01</span>:SCAN HDFS [parquet_user u]                        <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>     partitions<span class="operator">=</span><span class="number">1</span><span class="operator">/</span><span class="number">1</span> files<span class="operator">=</span><span class="number">4</span> size<span class="operator">=</span><span class="number">811.63</span>MB              <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="operator">|</span>                                                       <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> <span class="number">00</span>:SCAN HDFS [temp_parquet_log_20180209 t]              <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>    partitions<span class="operator">=</span><span class="number">1</span><span class="operator">/</span><span class="number">1</span> files<span class="operator">=</span><span class="number">976</span> size<span class="operator">=</span><span class="number">3.09</span>GB                 <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span>    runtime filters: RF000 <span class="operator">-</span><span class="operator">&gt;</span> t.id                       <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------------------------------------------------+</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- 在进行测试</span></span><br><span class="line">[master3.xxx:<span class="number">21000</span>] <span class="operator">&gt;</span> <span class="keyword">select</span> straight_join u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line">                              <span class="operator">&gt;</span> <span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line">                              <span class="operator">&gt;</span> <span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line">                              <span class="operator">&gt;</span> <span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span>;</span><br><span class="line">Query: <span class="keyword">select</span> straight_join u.province_name,<span class="built_in">count</span>(<span class="keyword">distinct</span> t.id) nums</span><br><span class="line"><span class="keyword">from</span> temp_parquet_log_20180209 t,parquet_user u</span><br><span class="line"><span class="keyword">where</span> t.id <span class="operator">=</span> u.id</span><br><span class="line"><span class="keyword">group</span> <span class="keyword">by</span> u.province_name limit <span class="number">5</span></span><br><span class="line">Query submitted <span class="keyword">at</span>: <span class="number">2018</span><span class="number">-02</span><span class="number">-09</span> <span class="number">11</span>:<span class="number">42</span>:<span class="number">26</span> (Coordinator: http:<span class="operator">/</span><span class="operator">/</span>master3.xxx:<span class="number">25000</span>)</span><br><span class="line">Query progress can be monitored <span class="keyword">at</span>: http:<span class="operator">/</span><span class="operator">/</span>master3.xxx:<span class="number">25000</span><span class="operator">/</span>query_plan?query_id<span class="operator">=</span>a44d5d5cabe90eec:ed20c60100000000</span><br><span class="line"><span class="operator">+</span><span class="comment">---------------+-------+</span></span><br><span class="line"><span class="operator">|</span> province_name <span class="operator">|</span> nums  <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------+-------+</span></span><br><span class="line"><span class="operator">|</span> AAA          <span class="operator">|</span> <span class="number">7542</span>  <span class="operator">|</span></span><br><span class="line"><span class="operator">|</span> BBB          <span class="operator">|</span> <span class="number">492</span>   <span class="operator">|</span></span><br><span class="line"><span class="operator">+</span><span class="comment">---------------+-------+</span></span><br><span class="line">Fetched <span class="number">5</span> <span class="type">row</span>(s) <span class="keyword">in</span> <span class="number">7.25</span>s</span><br></pre></td></tr></table></figure><p>最后测试结果又比之前提高了一倍，15.67s 到 7.25s;</p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2018/05/04/impala%E6%B5%8B%E8%AF%95/</id>
    <link href="https://blog.kfad127.xyz/2018/05/04/impala%E6%B5%8B%E8%AF%95/"/>
    <published>2018-05-04T04:58:00.000Z</published>
    <summary>
      <![CDATA[<p><img src="/images/covers/impala-tests-cover.jpg" alt="impala测试封面"></p>
<h4 id="测试思路"><a href="#测试思路" class="headerlink" title="测试思路"></a>测试思路</h4><ul>
<li><p>从单表开始，区分外部表与内部表，进行count、group by等</p>
</li>
<li><p>多表关联，join</p>
</li>
</ul>]]>
    </summary>
    <title>impala测试</title>
    <updated>2018-05-04T04:58:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>wzz</name>
      <email>369090561@qq.com</email>
    </author>
    <content>
      <![CDATA[<p><img src="/images/covers/hello-world-cover.jpg" alt="Hello World 封面"></p><p>Welcome to <a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a target="_blank" rel="noopener" href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a target="_blank" rel="noopener" href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a target="_blank" rel="noopener" href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><span id="more"></span><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a target="_blank" rel="noopener" href="https://hexo.io/docs/deployment.html">Deployment</a></p>]]>
    </content>
    <id>https://blog.kfad127.xyz/2018/05/02/hello-world/</id>
    <link href="https://blog.kfad127.xyz/2018/05/02/hello-world/"/>
    <published>2018-05-02T03:38:25.000Z</published>
    <summary>
      <![CDATA[<p><img src="/images/covers/hello-world-cover.jpg" alt="Hello World 封面"></p>
<p>Welcome to <a target="_blank" rel="noopener" href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a target="_blank" rel="noopener" href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a target="_blank" rel="noopener" href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a target="_blank" rel="noopener" href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p>]]>
    </summary>
    <title>Hello World</title>
    <updated>2018-05-02T03:38:25.000Z</updated>
  </entry>
</feed>
