Elasticsearch-39-filter原理深度剖析

filter执行原理

场景

举个例子,假设有个字段是date类型的,在倒排索引中:

word document1 document2 document3
2017-01-01
2017-02-02
2017-03-03

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

这时候一个filter查询:2017-02-02,在倒排索引里面找,对应的document list是doc2,doc3

为每个在倒排索引中搜索到的结果构建一个bitset

这点非常重要, 使用找到的document list构建一个bitset,一个二进制数组,数组每个元素都是0或1,用来标识一个doc对一个filter条件是否匹配,如果匹配就是1,不匹配就是0.
上面的例子中,构建的bitset就是[0,1,1]

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

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

在一个search请求中,可以发出多个filter条件(这个后面再具体说),每个filter会对应一个bitset
遍历每个filter条件对应的bitset,先从最稀疏的开始遍历.

怎么算稀疏呢?
[0,0,0,1,0,0] – 比较稀疏
[0,1,0,1,0,1]
先遍历比较稀疏的bitset,可以过滤掉尽可能多的数据

比如现在有个请求 filter: postDate=2017-01,userID=1,然后构建的两个bitset分别是:
[0,0,1,==1==,0,0]
[0,1,0,==1==,0,1]
遍历玩两个bitset之后,找到匹配所有条件的document,就是第4个,这个时候就可以将符合结果document返回给客户端了

caching bitset 跟踪query

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

举个例子,在最近的256次查询中,postDate=2017-02-02这个条件出现超过了一定的次数(不固定), 就会自动缓存这个filter对应的bitset

filter对于小的segment中获取到的结果可以不缓存, segment中记录数小于1000的和segment大小小于index总大小的3%的

因为segment数据量很小的时候,扫描是很快的,而且我们之前有说过,segment会在后台自动合并的,小的segment很快会和其他小的segment合并,此时缓存也就没有什么意义了

大部分情况下 filter会在query之前执行

filter先执行可以先过滤掉一部分数据,之前说过query是会计算相关度分数,然后去排序的,而filter是不计算分数,也不排序,所以先执行filter过滤掉尽可能多的数据

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

举个例子,之前有个filter 过滤条件是postDate=2017-02-02,然后他的bitset是[0,0,0,1]
这个时候如果新增了一条document进来 postDate也是 2017-02-02,id是5, 那么这个bitset会自动更新为[0,0,0,1,1]
同理,如果id = 1的document的postDate更新为2017-02-02 那么bitset也会更新为[1,0,0,1,1]

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