在elasticsearch里如何高效的使用filter

今天在做查询category的时候,遇到一个问题,查询出来的cateogry为food,fun的形式.但是我需要的只是food或者fun 不包含逗号.
开始想着在aggs后再做过滤,这样有些麻烦.遂在query中过滤掉category字段带逗号的.
同事说如果不做打分建议使用filter而不要使用query,这样会提高一定的效率.(注:打分只会对属性为text的字段,如果字段属性为keyword则不会打分)
所以在实际的需求中,只要不存在分词搜索那么都可以在的filter中将需要过滤的条件过滤掉.
同时filter还会对结果进行缓存,提高查询效率.





转载:http://blog.csdn.net/hljlzc2007/article/details/18549145
这里有一篇很好的文章,很不错,翻译和整理了一下,英文不错的,
建议直接看原文:http://euphonious-intuition.com/2013/05/all-about-elasticsearch-filter-bitsets/

elasticsearch里面有BOOL filter、AND、OR、NOT filter,这几个看起来很相似,都有什么区别呢?什么时候用boolfilter?什么时候用AND filter呢?事实上,bool filter和AND 、OR、NOT filter 是完全不同,在查询性能上面的影响是非常大的。

首先咱们需要了解的是filter里面都是怎么工作的,其中核心的一个东西叫BitSet,可以理解为一个很大的bit数组,数组里面的每个元素有2个状态:0和1(bloom filter知道么?),而filter大家都知道,只处理文档是否匹配与否,不涉及文档评分操作。如果一个文档和filter查询匹配,那么其对应的bit位就设置为1,匹配不上则设置为0。

es在执行filter查询过滤的时候,会打开lucene的每个segment段文件,然后去判断里面的文档符合该filter与否,这个匹配的结果我们就可以用bitset来存储起来,下次同样的filter查询过来,我们就直接使用内存里面的bitset来进行判断就行了,而不需要再打开lucene的segment文件了,避免了io的操作,这样就可以大大提高查询处理的速度,这也是为什么filter这么高效的原因。

因为lucene的segment段文件是不变的,lucene会产生新段,但是旧段是不变的,所以bitset是重复利用的,根据不同的filter条件和不同的段,会产生相应的bitset,另外不同的查询可能会涉及到多个bitset的做交集,计算机对这种bit位处理过程是非常拿手的,速度很快。

另外,如果filter的结果如果是空的,那么里面的bitset位都是0,es以后在处理该filter的时候,会把该bitset整个忽略掉,提高性能。

前面说完了基础内容,咱们再看看bool filter和AND filter这些的区别吧
bool filter会使用到前面提到过的bitset数据结构(bitset派),而AND \OR\ NOTfilter则不能利用到bitset(non-bitset派),为什么呢?

AND、OR、NOT filter是doc by doc的逐个文档的处理,es逐个加载文档里面的字段内容,然后检查字段的内容是否满足查询条件,不满足的文档就排除在结果集之外,依次迭代进行,直到过完一遍所有的文档,这中间的过程用不到前面提到过的bitset,也就不能重复利用缓存资源

如果你有多个filter条件,即一个AND、OR、NOT里面包含多个filter过滤条件(支持数组的方式),那么处理的逻辑就是每个filter会将依次将生成的结果集传到下一个filter,理论上处理的文档数会越来越少,因为只会过滤减少,不会增加,这样依次过滤,所以一般限制条件比较苛刻的可以放前面执行,这样后面的filter需要处理的文档数就会很小,这样可以大大提高整体处理的速度,另外除了数量上的考虑外,还需要考虑filter的效率问题,一些filter执行效率很低,如Geo filter(大量计算)或者script based filter(动态脚本),建议将这些性能开销比较大的查询放最后执行来提高整体的处理速度。

好了,现在应该有这么一个概念了,AND、OR、NOT是文档by文档,依次处理,如果你的结果集很大,即一个很宽松的查询,命中很多,那么你使用AND、OR、NOT filter是不合适的,但是有些filter是必须文档by文档处理的,如下面的这几个filter:
* Geo* filters
* Scripts
* Numeric_range
所以除了上面那几个没有办法的,其它的filter应该一律使用bool filter来提高查询性能。
如果你的查询里面需要同时使用到bitset和non-bitset类型的filter,则可以组合起来使用bool filter和AND\OR\NOT filter,
前面说了,AND 是结果集依次向后传递,所以我们把性能比较好的放前面,non-bitset放AND的filter的后面,如下面一个包含多个filter类型的复杂的filter

{
  "and" : [
    {
      "bool" : {
        "must" : [
          { "term" : {} },
          { "range" : {} },
          { "term" : {} }
        ]
      }
    },
    {
      "or" : [
        { "custom_script" : {} },
        { "geo_distance" : {} }
      ]
    }
  ]
}

and 在最外层做wrapper,第一个filter是一个bool filter,里面有3个must的子filter,处理完了之后,得到文档结果集,然后再执行一个or的子filter,OR里面两个查询会分别进行,最终的文档结果集就是我们的搜索结果了。
总之,filter使用的时候,一定要优先使用bitset流,然后还要考虑filter顺序和组合的问题
Geo, Script or Numeric_range filter: 使用 And/Or/Not Filters
所有其它的: 使用 Bool Filter
掌握了以上这些,就不难写出高性能的查询了。

相关的3个链接:
All about Elasticsearch Filter BitSets : http://euphonious-intuition.com/2013/05/all-about-elasticsearch-filter-bitsets/
Filter execution order : https://groups.google.com/d/msg/elasticsearch/2SusmSoShlo/qlOAbWmDRqwJ
Bool vs And/Or/Not : https://groups.google.com/d/msg/elasticsearch/PS12RcyNSWc/I1PX1r0RfFcJ





转载:http://blog.csdn.net/oryjk/article/details/50750850

must的性能要低一些,为什么?因为他要进行打分评估,也就是说要进行_score,而filter则不会。

下面讲讲我一般使用的场景
一般来说,我是先使用filter把不需要的过滤掉,
例如现在有一个电子商务的网站,我要查询一个category的id为1下面的所有产品,
那么我首先会使用filter把category id等于1的产品过滤出来,也就是查出来,
因为然后我再这个category下面查询name为“五子弥勒”的产品,这个时候我就会使用query,
为什么呢,因为可能有的产品的name完全match 这个“五子弥勒”的关键字,
但是有的产品可能只会match其中的一个词汇,所以,如果我需要把有相似性的查出来,
这个是query是具备这个功能的,因为query的本质不是筛选,而是查询,他会给结果打分,
然后按照分数进行一个排序,如果命中的比较多,分数自然就很高,那么就会排在前面。那么这里存在一个打分的概念,
个人认为这个打分主要还是看分词器对他的命中,然后给一个评估,关于分词器,我会在后面的博客中提到。

所以,这个时候,大家应该知道filter额query的主要区别了,
另外关于性能的我在提一下,elasticsearch·中分为filter和query,所有的filter是不进行打分的,因为她只是一个筛选,对不感兴趣的直接筛选掉,所以他没必要对不感兴趣的东西进行一个打分,
而query刚好相反,他实际上你可以理解成,他是一个命中率的概念,是一个率,所以打分是有必要的,
作为一个搜索引擎,另外如果你不想看到打分,你可以通过参数去控制,但是实际上,对性能的提升不大

posted @ 2017-06-28 12:10  0xcafedaddy  阅读(756)  评论(0编辑  收藏  举报