第 4 卷
| 11 | --- filterEvents:结构事件(turn/*)不在语义文档里--- |
|---|---|
| 12 | 命中0条(turn/start不产生搜索文档,所以是0) |
| 13 | --- filterEvents:text过滤兜底FTS搜不到的中文子串--- |
| 14 | FTS搜「落盘」:命中0个会话 |
| 15 | text过滤搜「落盘」:命中1条(返回文档数组:没有snippet,也不分页) |
| 16 | ·seq11 user/message:日志怎么落盘? |
| 17 | --- filterEvents:text匹配时按空白切段--- |
| 18 | ·seq12 assistant/message:顺序是:先写内存的⏎events,再flush到磁盘。 |
| 19 | 搜索词按空白切成两段、段间用\s+连,所以原文里两段之间隔着换行也能命中; |
| 20 | 而*、?、(这些正则特殊字符会被转义,在你手里永远是字面量。 |
text 子句:FTS 搜不到时的兜底。前面几个都按元数据圈定,只有它按内容找——所以它也用不了 values(那是候选值列表),改用 text 装要匹配的那段内容。上一节那个搜不到
的“落盘”,用它就捞得出来:
复制代码
| 1 | awaitctx.sessionQuery.searchSessions({query:'落盘'}) | //命中0个会话 |
|---|---|---|
| 2 | awaitctx.sessionQuery.filterEvents(SessionId('sess-grandchild'), [ | |
| 3 | {kind:'text',text:'落盘'}, | |
| 4 | ]) |
它做的是逐条扫描:搜索词按空白切成几段,每段都按字面文本处理(源码里 compileSessionTextFilter 把它编译成正则,但元字符会被转义——你输 .* 搜到的就
是这两个字符),段之间允许任意空白,不区分大小写。所以它搜的是字面子串:中文子串、英文半个词都能搜到。代价是没有索引,一次要扫一份日志,慢。
返回的是文档数组,不分页、按 seq 升序,和全文搜索“按相关性 + 游标翻页”正好相反。
到这里,“怎么搜”这一问就齐了:按内容搜(全文搜索),按条件筛(精确过滤)。下一节换第三问:怎么追。
谱系的数据基础是 header 里的 parentSession:第 9 讲聊 fork 时提过,它记的是“从哪个会话分出来的”,只在 fork 时写下。每个子会话各记一条,把这些散在各处的 parent 拼起
来,就是一张谱系。追的时候分两个方向:
往上:搜到有用的记录后,想知道它是从哪次会话分出来的(典型流程就是先搜、再追)
往下:精确过滤的 parent 过滤器能“只看 fork 自这个会话的那些”,靠的就是谱系数据。
追这类关系的同样是 ctx.sessionQuery 上的 traceSession(id)。跑 npm run start:ch11:lineage,先造一条 root → child → grandchild 的谱系,再查:
复制代码 1--- 追踪 sess-grandchild 的谱系 ---
2目标:sess-grandchild 3完整:true
4祖先(由近及远):
5· sess-child 6· sess-root
7--- 追踪 sess-root 的后代 --- 8目标:sess-root
9后代树:
10· sess-child 11· sess-grandchild
traceSession() 一次读出目标往上、往下两个方向:
往上:ancestors,一条线,从直接父级往外排(追 sess-grandchild 得到 sesschild → sess-root),第一个是最亲的父级,最后一个是最远的祖先。
往下:descendants,一棵树,每一项是一个从直接子级开始的节点,节点里又带一层自己的 descendants,一层套一层(追 sess-root 得到 sess-child,它下面又套着
sess-grandchild)。同一层的兄弟按创建时间排,时间相同再按 id 排。

形状不同,是因为 parentSession 是单向的:它只写在子会话的 header 里、指向父级,没有反过来的“子”字段。往上是顺着它一跳一跳(成链);往下得先把整个语料库扫一遍、按
它归成“父 → 子们”再展开(成树)。
不过祖先这条链不一定追得到顶。返回结果里还带一个 complete:目标、ancestors、 descendants 每次都在,此外只再带两个字段里的一个,带 root 还是
unresolvedParentId,由 complete 决定。
complete附带字段含义
祖先链一路追到了顶;root 是链顶那条记录(目标自己 TRUEroot 就是根时,root 就是目标)
链断了——某个父级不在当前语料库里(比如父会话是 FALSEunresolvedParentId从另一个工作区 fork 来的,这个查询引擎没看见
它),unresolvedParentId 是第一个追不到的那个