es filter过滤的bitset机制和caching机制
document存储数据为:
PUT /forum/article/_bulk { "index": { "_id": 1 }} { "articleID" : "XHDK-A-1293-#fJ3", "userID" : 1, "hidden": false, "postDate": "2017-01-01" } { "index": { "_id": 2 }} { "articleID" : "KDKE-B-9947-#kL5", "userID" : 1, "hidden": false, "postDate": "2017-01-02" } { "index": { "_id": 3 }} { "articleID" : "JODL-X-1937-#pV7", "userID" : 2, "hidden": false, "postDate": "2017-01-01" } { "index": { "_id": 4 }} { "articleID" : "QQPX-R-3956-#aD8", "userID" : 2, "hidden": true, "postDate": "2017-01-02" }
查询语句(获取userid==1 && postDate==2017-01-01的document 并且articleID包含XHDK):
GET /forum/article/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "hidden": "false"}},
{ "term": { "postDate": "2017-01-01" }} ,
{ "match": { "articleID": "XHDK"}}
]
}
}
}
此语句查询过程,涉及到caching和bitset部分。
bitset机制
(1) 在倒排索引中查找字符串,获取documnet list。
(2)位每个在倒排索引中搜索到的结果,构建一个bitset。0代表不匹配,1代表匹配,使用bitset这种数据结构可以节省内存空间,提升性能。
"term": { "hidden": "false"}------>[1,1,1,0]
"term": { "postDate": "2017-01-01" }----> [1,0,1,0]
"match": { "articleID": "XHDK"}------> [1,0,0,0]
(3)遍历每个过滤条件对应的bitset,优先从最稀疏的开始搜索,查找所有满足所有条件的document
最稀疏的应该是"match": { "articleID": "XHDK"}------> [1,0,0,0]。这样可以尽可能多的过滤掉documnet。
再过滤"term": { "postDate": "2017-01-01" }----> [1,0,1,0]。
遍历完后bitset之后,找到所有匹配的document。[1,0,0,0],也就是document==1一个。
caching机制
(1)跟踪query,在最近256个query中超过一定次数的过滤条件,缓存其bitset。对于小segment(<1000,或<3%),不缓存bitset。
使用缓存,可以不用重新扫描倒排索引,不用反复生成bitset,可以大幅度提升性能。
为什么小的segment不进行缓存:segment数据量很小,此时哪怕是扫描也很快;segment会在后台自动合并,小segment很快就会跟其他小segment合并成大segment,此时就缓存也没有什么意义,segment很快就消失了。
(2)filter大部分情况下来说,在query之前执行,先尽量过滤掉尽可能多的数据
query:是会计算doc对搜索条件的relevance score,还会根据这个score去排序
filter:只是简单过滤出想要的数据,不计算relevance score,也不排序
(3)如果document有新增或修改,那么cached bitset会被自动更新
(4)以后只要是有相同的filter条件的,会直接来使用这个过滤条件对应的cached bitset