模式与分词
写入主线的第一步是 Index::create_in_dir(path, schema),第二步是把文档交给 IndexWriter。在这两步之前,有四件事要先定下来:索引里有哪些字段、每个字段怎么处理(schema);一个值最后变成什么字节去查词典(Term);文档本身用什么类型传进来、怎么存进 doc store 又怎么取回来(Document);文本怎么切成词(tokenizer)。这一部分讲的就是这四件事。
代码在 src/schema/(9882 行,其中 document/ 4502 行)、src/tokenizer/(9111 行,但 ascii_folding_filter.rs 4066 行和 stop_word_filter/stopwords.rs 2319 行都是数据表,真正的逻辑不到 2800 行)和独立的 tantivy-tokenizer-api crate(src/lib.rs 180 行)。行数都按 tag 0.27.0 统计,含单元测试。
- Schema 与字段:
SchemaBuilder按添加顺序给字段编号;FieldType有 12 个变体,0.27.0 新增TieBreaker和Custom;TEXT、STRING、STORED、FAST、INDEXED是类型层面的标志列表,|组合时indexing取左边那个;schema 原样序列化进meta.json,打开时按它重建。 - Term:
Term是「字段 + 类型码 + 值」,但词典里的键只有值;数字用大端字节加符号位翻转变成可排序的 8 字节,日期在倒排里截到秒,JSON 字段用\x01分隔路径、\x00结束路径;文中打印了五种类型的真实字节。 - 文档:
Document和Value两个 trait 让任何类型都能直接被索引;默认的TantivyDocument是把所有值压进一个Vec<u8>的CompactDoc;doc store 里每个文档是「字段数 + (字段号, 类型码, 值)…」,没设STORED的字段根本不写,取回来就是没有。 - 分词:
Tokenizer、TokenStream、TokenFilter在tantivy-tokenizer-api里,TextAnalyzer把一条 filter 链装进一个 box;默认注册四个名字;schema 只存名字,没注册时写入在commit才报错、查询在解析时报错;default对中文几乎不可用,tantivy-jieba 通过同一个 api crate 接进来。
flowchart TB sch["Schema"] --> fe["FieldEntry"] fe --> name["分词器名字"] name --> tm["TokenizerManager"] doc["Document"] --> val["ReferenceValue"] val --> ta["TextAnalyzer"] tm --> ta ta --> term["Term 字节"] term --> td["词典与倒排"] val --> store["doc store"] val --> fast["快速字段"]
字段值从 Document 出来以后分三路:建索引的经过分词变成 Term,进词典和倒排表(倒排表、词典);STORED 的原样序列化进 doc store;FAST 的进列存(快速字段)。三路各自读 schema,互不相干,所以一个字段可以只索引不存、只存不索引,或者三样都要。
💬 关联讨论
发起讨论加载中...