# filter 原理剖析

核心是 bitset,还有 caching 机制

# 1. 搜索数据,获取 document list

在倒排索引中查找搜索串,获取 document list

date 来举例

word doc1 doc2 doc3
2017-01-01 * *
2017-02-02 * *
2017-03-03 * * *

filter:2017-02-02

到倒排索引中一找,发现 2017-02-02 对应的 document list 是 doc2,doc3

# 2. 构建 bitset

为每个在倒排索引中搜索到的结果,构建一个 bitset,[0, 0, 0, 1, 0, 1]

使用找到的 doc list 构建一个 bitset:就是一个二进制的数组,数组每个元素都是 0 或 1, 用来标识一个 doc对一个 filter 条件是否匹配,如果匹配就是 1,不匹配就是 0

如 filter:2017-02-02 :[0, 1, 1]

  • doc1:不匹配这个 filter 的
  • doc2 和 do3:是匹配这个 filter 的

尽可能用简单的数据结构去实现复杂的功能,可以节省内存空间,提升性能

# 3. 遍历 bitset,查找满足条件的 documt

遍历每个过滤条件对应的 bitset,优先从最稀疏的开始搜索,查找满足所有条件的 document

后面会讲解,一次性其实可以在一个 search 请求中,发出多个 filter 条件,每个 filter 条件都会对应一个 bitset 遍历每个 filter 条件对应的 bitset,先从最稀疏的开始遍历

[0, 0, 0, 1, 0, 0]:比较稀疏,可以简单任务是 1 最少的
[0, 1, 0, 1, 0, 1]
1
2

先遍历比较稀疏的 bitset,就可以先过滤掉尽可能多的数据;遍历所有的 bitset,找到匹配所有 filter 条件的doc

比如请求:filter,postDate=2017-01-01,userID=1

postDate: [0, 0, 1, 1, 0, 0]
userID:   [0, 1, 0, 1, 0, 1]
1
2

遍历完两个 bitset 之后,找到的匹配所有条件的 doc,就是 doc4 (都是 1)

就可以将document作为结果返回给client了

# 4. caching bitset

caching bitset:跟踪 query,在最近 256个 query 中超过一定次数的过滤条件,缓存其 bitset。对于小 segment(<1000,或<3%),不缓存 bitset。

比如 postDate=2017-01-01,[0, 0, 1, 1, 0, 0],可以缓存在内存中, 这样下次如果再有这个条件过来的时候,就不用重新扫描倒排索引,反复生成 bitset,可以大幅度提升性能。

在最近的 256 个 filter 中,有某个 filter 超过了一定的次数,次数不固定,就会自动缓存这个 filter 对应的 bitset

小 segment 不缓存

filter 针对小 segment 获取到的结果,可以不缓存,segment 记录数 <1000,或者 segment 大小 < index 总大小的 3%

因为:

  • segment 数据量很小,此时哪怕是扫描也很快;
  • segment 会在后台自动合并,小 segment 很快就会跟其他小 segment 合并成大 segment,此时就缓存也没有什么意义,segment 很快就消失了

filter 与 query 相比的好处

好处就是 filter 会 caching,但是之前不知道 caching 的是什么东西,实际上并不是一个 filter 返回的完整的 doc list 数据结果。 而是 filter bitset 缓存起来。下次不用扫描倒排索引了。

# 5. filter 大部分情况下会比 query 先执行

filter 大部分情况下来说,在 query 之前执行,先尽量过滤掉尽可能多的数据

  • query:是会计算 doc 对搜索条件的 relevance score,还会根据这个 score 去排序
  • filter:只是简单过滤出想要的数据,不计算 relevance score,也不排序

TIP

之前我一直以为 filter 是在 query 中条件查找之后,在结果上进行单纯的过滤操作。 现在看来并不是这样

# 6. 有修改或者更新,cached bitset 自动更新

如果 document 新增或修改,那么 cached bitset 会被自动更新

postDate=2017-01-01,[0, 0, 1, 0]

document,id=5,postDate=2017-01-01,会自动更新到 postDate=2017-01-01 这个 filter 的 bitset 中,全自动,缓存会自动更新。postDate=2017-01-01的bitset,[0, 0, 1, 0, 1]
document,id=1,postDate=2016-12-30,修改为 postDate-2017-01-01,此时也会自动更新 bitset,[1, 0, 1, 0, 1]
1
2
3
4

以后只要是有相同的 filter 条件的,会直接来使用这个过滤条件对应的 cached bitset