ES入门(四)Elasticsearch之单字符串多字段查询

    科技2025-08-03  20

    ES入门(四)Elasticsearch之单字符串多字段查询

    Dis Max Query

    数据准备,索引my_index002

    { "name" : "C++", "dec" : "i like writing artcle" }, { "name" : "java", "dec" : "i like writing solution artcle" }, { "name" : "solution", "dec" : "i think java is nice" }, { "name" : "php", "dec" : "i think php is nice" }, { "name" : "php", "dec" : "i think php is nice" }

    搜索name或dec中包含java或solution的document


    搜索: GET /my_index002/_search { "query": { "bool": { "should": [ {"match": { "name": "java solution" }}, {"match": { "dec": "java solution" }} ] } } } 返回结果: { "took" : 11, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 3, "max_score" : 2.2891216, "hits" : [ { "_index" : "my_index002", "_type" : "_doc", "_id" : "2", "_score" : 2.2891216, "_source" : { "name" : "java", "dec" : "i like writing solution artcle" } }, { "_index" : "my_index002", "_type" : "_doc", "_id" : "4", "_score" : 2.2891216, "_source" : { "name" : "solution", "dec" : "i think java is nice" } }, { "_index" : "my_index002", "_type" : "_doc", "_id" : "5", "_score" : 1.4628086, "_source" : { "name" : "c#", "dec" : "java is a good language, solution is goods" } } ] } }

    结果分析:

    期望_id=5的文档,但是_id=2和_id=4的文档排在来前面。

    计算_id=2的分数,{"match": {"name": "java solution"}},针对_id=2的文档有一个分数                               {"match": {"dec": "java solution"}},针对_id=2的文档有一个分数 所以这两个分数加起来:假设这两个分数分别是  1.1+1.2=2.3,matched query数量=2,总query数量=2,得分=2.3*2/2=2.3。

    计算_id=5的分数,{"match": {"name": "java solution"}},没有分数                               {"match": {"dec": "java solution"}},有一个分数

    所以说,只有一个query是有分数的,假设是2.3,matched query数量=1,总query数量=2,得分=2.3*1/2=1.15 < 2.3。

    如果期望_id=5的文档排在前面,可以使用best fields策略:dis_max


    GET /my_index002/_search { "query": { "dis_max": { "queries": [ {"match": { "name": "java solution" }}, {"match": { "dec": "java solution" }} ] } } }

    best fields策略,就是说,搜索到的结果,应该是某一个field中匹配到来尽可能多的关键词,被排在前面;而不是尽可能多的field匹配到来少数的关键词(best fields),排在来前面。dis_max语法直接取多个query中,分数最高的那一个query的分数即可。

    计算_id=2的分数,{"match": {"name": "java solution"}},针对_id=2的文档有一个分数 1.1                               {"match": {"dec": "java solution"}},针对_id=2的文档有一个分数 1.2 所以这两个分数加起来:假设这两个分数分别是  1.1+1.2=2.3,得分=max(1.1,1.2)=1.2

    计算_id=5的分数,{"match": {"name": "java solution"}},没有分数 0                               {"match": {"dec": "java solution"}},有一个分数 2.3

    所以_id=5的document的得分是max(0, 2.3)=2.3。

    tie_breaker

    考虑一下以下场景:

    某个商品,document1,name中包含java,dec中不包含java,solution任何一个关键字某个商品,document2,name中包含solution,dec中不包含任何一个关键字某个商品,document3,name中包含java,dec中包含solution最终搜索出来结果可能是:document1和document2排在document3前面,而不是我们期望的document3排在最前面

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

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

    tie_breaker参数的意义在于将其他query的分数,乘以tie_breaker,然后综合与最高分数的那个query的分数,综合在一起进行计算。


    GET /my_index002/_search { "query": { "dis_max": { "queries": [ {"match": { "name": "java solution" }}, {"match": { "dec": "java solution" }} ], "tie_breaker": 0.3 } } }

    multi_match查询

    multi_match查询语法如下:


    GET /my_index002/_search { "query": { "multi_match": { "query": "java solution", //查询关键词 "fields": ["name", "dec"], //查询字段 "type": "most_fields" //查询返回的得分策略 } } }

    most_fields与best_fields的区别:

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

    优点:通过best_fields策略,以及综合考虑其他field,还有minimum_should_match支持,可以尽可能精确地将匹配结果推送到最前面

    缺点:除了那些精确匹配的结果,其他差不多大的结果,排序结果不是太均匀,没有什么区分度来

    2. most_fields,综合多个field一起进行搜索,尽可能多的让所有field的query参与到总分数的计算中来,此时就是个大杂烩,结果不一定精确,某一个document的一个field包含更多的关键字,但是因为其他document有更过的field匹配到了,所以排在了前面

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

    缺点:可能那些精确匹配的结果,无法推送到最前面

    wiki明显使用的是most_fields策略,搜索结果比较均匀,但是要翻好几页才能找到最匹配的结果;而baidu使用的则是best_fields。

     

    Processed: 0.022, SQL: 8