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

 

参考文档:https://www.jianshu.com/p/83e4771f697e

 

关于Filter

从solr到es,一路下来对搜索引擎的长期使用,工作内容也包含大量的搜索优化的问题,无论是搜索质量还是速度都是需要关心的问题。有一个结论我一直记得,就是能使用filter的情况尽量使用filter,filter速度快,而且自带缓存。但是之前是知其然不知其所以然,今天想到这个,所以专门研究了一下到底filter的原理。

Filter查询为什么快

关于bitset

首先介绍bitset是什么

可以简单的理解为bit数组,即数组中只包含0或1

关于Filter

以以下的数据举例子

worddoc1doc2doc3
hownoyesyes
areyesyesno
younoyesyes

yes和no表示索引是否包含word的词
现在我们给出filter的条件word:are,根据表中所得为yes,yes,no,将yes做1,no做0,于是我们获得了这个filter条件在这个索引中的bitset[1, 1, 0]
然后我们再加一个条件word:you,获得新的bitset[0,1,1]
条件和起来的意思是word:are && word:you,所以我们就做位运算就可以了,可得到新集合[0, 1, 0],到这里完成了一次过滤查询。

关于缓存

filter的特点就在于缓存速度快,那它是怎么缓存的呢?和我过去接触到的kv缓存的方式不一样,es会缓存一些bitset,当下次还有filter查询的时候直接访问的bitset,这样有以下好处

  • bitset的内存占用非常小
  • 位运算速度飞快
  • 不需要再次访问倒排索引表
    以上表举例的话,当我们的查询再次设计刚才的filter时,直接访问[0, 1, 0]即可。
    以下引用官方文档中关于缓存规则的描述

为了解决问题,Elasticsearch 会基于使用频次自动缓存查询。如果一个非评分查询在最近的 256 次查询中被使用过(次数取决于查询类型),那么这个查询就会作为缓存的候选。但是,并不是所有的片段都能保证缓存 bitset 。只有那些文档数量超过 10,000 (或超过总文档数量的 3% )才会缓存 bitset 。因为小的片段可以很快的进行搜索和合并,这里缓存的意义不大。
一旦缓存了,非评分计算的 bitset 会一直驻留在缓存中直到它被剔除。剔除规则是基于 LRU 的:一旦缓存满了,最近最少使用的过滤器会被剔除。



作者:十五倍压枪
链接:https://www.jianshu.com/p/12dc1f07934d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值