elasticsearch 搜索

版权声明:转载请注明出处 https://blog.csdn.net/Lee_Suoer/article/details/88376200

首先,elasticsearch支持随时添加 field。

对于type=text,默认会设置两个field,一个是field本身,比如articleID,就是分词的;还有一个的话,就是field.keyword,articleID.keyword,默认不分词,会最多保留256个字符

对于term filter/query:对搜索文本不分词,直接拿去倒排索引中匹配。否则会对搜索条件分词,分别去倒排索引中查询。

articleID.keyword:内置建立的field,就是不分词的。所以一个articleID过来的时候,会建立两次索引,一次是自己本身,是要分词的,分词后放入倒排索引;另外一次是基于articleID.keyword,不分词,保留256个字符最多,直接一个字符串放入倒排索引中。所以term filter,对text过滤,可以考虑使用内置的field.keyword来进行匹配。但是有个问题,默认就保留256个字符。所以尽可能还是自己去手动建立索引,指定not_analyzed吧。在最新版本的es中,不需要指定not_analyzed也可以,将type=keyword即可。

bitset:

在搜索的时候,会对搜索到的每个document进行记录,形成一个 bitset,比如 [0, 0, 0, 1, 0, 1],0 不符合要求,1符合。这样就可以用很小的空间来记录很多的信息。

对于多个filter的搜索,每个filter都会对应有一个bitset,之后会先遍历比较稀疏的bitset,就可以先过滤掉尽可能多的数据遍历所有的bitset,找到匹配所有filter条件的doc,同时在最近256个query中超过一定次数的过滤条件,会缓存其bitset。filter比query的好处就在于会caching,filter bitset缓存起来。下次不用扫描倒排索引了。query:是会计算doc对搜索条件的relevance score,还会根据这个score去排序,filter:只是简单过滤出想要的数据,不计算relevance score,也不排序,如果document有新增或修改,那么cached bitset会被自动更新

select *from forum.article
where (post_date='2017-01-01' or article_id='XHDK-A-1293-#fJ3') and post_date!='2017-01-02'

select *from forum.article
where article_id='XHDK-A-1293-#fJ3' or (article_id='JODL-X-1937-#pV7' and post_date='2017-01-01')

对于多个值得搜索:select * from tbl where col in ("value1", "value2")

范围查找:

按照时间范围查找:

控制查询精度:

搜索标题中包含java或elasticsearch的blog

match query,是负责进行全文检索的。当然,如果要检索的field,是not_analyzed类型的,那么match query也相当于term query。

搜索标题中包含java和elasticsearch的blog:

用and,可以实现单纯match query无法实现的效果

搜索包含java,elasticsearch,spark,hadoop,4个关键字中,至少3个的blog:

使用bool过滤:

如果没有must,也可以使用should来筛选:

match在底层就是 bool + term:

比如: 

{
    "match": { "title": "java elasticsearch"}
}

会转换成:

{
  "bool": {
    "should": [
      { "term": { "title": "java" }},
      { "term": { "title": "elasticsearch"   }}
    ]
  }
}

搜索条件的权重,boost,可以将某个搜索条件的权重加大,此时当匹配这个搜索条件和匹配另一个搜索条件的document,计算relevance score时,匹配权重更大的搜索条件的document,relevance score会更高,当然也就会优先被返回回来

多个shard的情况下 相关度分数计算不准确问题:

原因:每个shard计算相关度分数的时候只会再本地服务器中计算。每个shard的上的document数量不均匀由IDF算法计算导致不同shard计算的结果不一样。

解决方案:生产环境数据量大的时候尽量保持数据路由到各个shard上的数量是相同的。测试环境就尽量使用一个shard,如果是多个,可以携带 search_type=dfs_query_then_fetch 参数。生产环境不建议使用,性能不好

搜索title或content中包含java或solution的帖子:

这里是使用了多字段搜索:

这可能导致如果每一个字段同时包含了两个字段但是相关度分数却不是最高的。计算每个document的relevance score:每个query的分数,乘以matched query数量,除以总query数量

best fields策略,就是说,搜索到的结果,应该是某一个field中匹配到了尽可能多的关键词,被排在前面;而不是尽可能多的field匹配到了少数的关键词,排在了前面

dis_max语法,直接取多个query中,分数最高的那一个query的分数即可

dis_max只取某一个query最大的分数,完全不考虑其他query的分数

使用tie_breaker将其他query的分数也考虑进去

tie_breaker参数的意义,在于说,将其他query的分数,乘以tie_breaker,然后综合与最高分数的那个query的分数,综合在一起进行计算
除了取最高分以外,还会考虑其他的query的分数
tie_breaker的值,在0~1之间,是个小数,就ok

GET /forum/article/_search
{
    "query": {
        "dis_max": {
            "queries": [
                { "match": { "title": "java beginner" }},
                { "match": { "body":  "java beginner" }}
            ],
            "tie_breaker": 0.3
        }
    }
}

案例:

minimum_should_match,主要是用来去掉长尾,long tail,长尾,比如你搜索5个关键词,但是很多结果是只匹配1个关键词的,其实跟你想要的结果相差甚远,这些结果就是长尾,minimum_should_match,控制搜索结果的精准度,只有匹配一定数量的关键词的数据,才能返回

从best-fields换成most-fields策略
best-fields策略,主要是说将某一个field匹配尽可能多的关键词的doc优先返回回来
most-fields策略,主要是说尽可能返回更多field匹配到某个关键词的doc,优先返回回来

sub_title用的是enligsh analyzer,所以还原了单词

为什么,因为如果我们用的是类似于english analyzer这种分词器的话,就会将单词还原为其最基本的形态,stemmer
learning --> learn
learned --> learn
courses --> course

与best_fields的区别

(1)best_fields,是对多个field进行搜索,挑选某个field匹配度最高的那个分数,同时在多个query最高分相同的情况下,在一定程度上考虑其他query的分数。简单来说,你对多个field进行搜索,就想搜索到某一个field尽可能包含更多关键字的数据

优点:通过best_fields策略,以及综合考虑其他field,还有minimum_should_match支持,可以尽可能精准地将匹配的结果推送到最前面
缺点:除了那些精准匹配的结果,其他差不多大的结果,排序结果不是太均匀,没有什么区分度了

实际的例子:百度之类的搜索引擎,最匹配的到最前面,但是其他的就没什么区分度了

(2)most_fields,综合多个field一起进行搜索,尽可能多地让所有field的query参与到总分数的计算中来,此时就会是个大杂烩,出现类似best_fields案例最开始的那个结果,结果不一定精准,某一个document的一个field包含更多的关键字,但是因为其他document有更多field匹配到了,所以排在了前面;所以需要建立类似sub_title.std这样的field,尽可能让某一个field精准匹配query string,贡献更高的分数,将更精准匹配的数据排到前面

优点:将尽可能匹配更多field的结果推送到最前面,整个排序结果是比较均匀的
缺点:可能那些精准匹配的结果,无法推送到最前面

实际的例子:wiki,明显的most_fields策略,搜索结果比较均匀,但是的确要翻好几页才能找到最匹配的结果

简单来说就是一个query 更能尽量的匹配document的一个field还是多个field。

只是找到尽可能多的field匹配的doc,而不是某个field完全匹配的doc,most_fields,没办法用minimum_should_match去掉长尾数据,就是匹配的特别少的结果,TF/IDF算法,比如Peter Smith和Smith Williams,搜索Peter Smith的时候,由于first_name中很少有Smith的,所以query在所有document中的频率很低,得到的分数很高,可能Smith Williams反而会排在Peter Smith前面

使用copyto可以将多个field合并成一个新的field;

短语匹配:

整个短语是一个整体,用来进行搜索. 搜索结果是这个搜索短语没有被分割开。

分词。

短语匹配原理:查找短语中的每一个词在doc中的位置,要是位置相连,则符合要求。

近似匹配:proximity match

就是在短语匹配中添加了 slop,就是短语中两个单词之间间距最大相隔几个单词。

短语匹配和近似匹配原理是相同的,只不过是中间相隔的单词数量的多少而已  ---  slop

召回率:比如你搜索一个java spark,总共有100个doc,能返回多少个doc作为结果,就是召回率,recall

精准度:比如你搜索一个java spark,能不能尽可能让包含java spark,或者是java和spark离的很近的doc,排在最前面,precision

直接用match_phrase短语搜索,会导致必须所有term都在doc field中出现,而且距离在slop限定范围内,才能匹配上

match phrase,proximity match,要求doc必须包含所有的term,才能作为结果返回;如果某一个doc可能就是有某个term没有包含,那么就无法作为结果返回

使用match query 和 match phrase  结合使用效果才是最好的

使用了should,提高了相关度分数,排名就会靠前了。。

猜你喜欢

转载自blog.csdn.net/Lee_Suoer/article/details/88376200