• Elasticsearch实战(七)---BestFields MostFields CrossFields 多字段搜索策略


    Elasticsearch实战- BestFields MostFields 搜索策略

    1.字段中心及词条中心查询

    说区别之前,先普及下概念

    • 字段中心查询式,就是以字段为中心,代表就是 BestFields和MostFields把所有的字段全都散列,然后从中去查询
      举个简单的例子,地址存储的时候 你不可能直接存储 ”湖北省武汉市东湖高新区“ 这样的字符串,所以一般存储的时候 省/市/区 分别是"provice", “city”, "area"三个字段,那我搜寻 湖北省 武汉市 东湖高新的时候,是不是会把所有 包含湖北省,武汉市 都搜出来,大量重复无用数据
    • 词条中心查询式,就是以词条为中心,代表就是 CrossFields,就是解决上面的问题的,以词条为中心搜索,关联多个字段

    本文我们着重讲一下 字段中心的 BestFields及MostFields

    2.Multi-match query 的目的多字段匹配策略

    • Best-fields策略 默认排序, 又叫最佳字段排序,可以理解为精确匹配
      搜索的Documemt文档中的某一个field,尽可能多的匹配搜索条件,比如我搜索了3个字段,其中一个字段相关度分数很高,哪个分数高就用哪一个返回,作为相关度分数对结果排序
      等价:BestFields 等价于dis_max查询
      优点:精确匹配的数据尽可能的排列到最前端,且可以通过minimum_should_match来去除长尾数据
      缺点:除了那些精准匹配的结果,其他结果没有区分度,排序结果相对不均匀
      案例:百度搜索,除了前几条精确匹配,后面几页都没有区分度

    • Most-fields策略,尽可能多的字段匹配到搜索条件
      综合多个field进行搜索,尽可能多地让所有field的query参与到总分数的计算中来,结果不一定精准,某一个document的多个field 匹配到更多的关键字 就会优先返回排在了前面;而且多个字段的分数是累加计算反馈到最终分的
      等价:MostFields等价于bool should查询
      优点:将尽可能匹配更多field的结果推送到最前面,整个排序结果是比较均匀的
      缺点:可能那些精准匹配的结果,无法推送到最前面
      案例:wiki搜索,尽可能多的字段匹配优先返回,最精准的结果可能在后面

    看起来懵逼么?下面用一个场景描述算分就明白了
    在这里插入图片描述

    2.1 准备数据

    empId:员工id, salary 表示薪资, deptName:部门, address:地址

    POST /testboost/_bulk
    {"index":{"_id": 1}}
    {"empId" : "111","name" : "员工1","age" : 20,"sex" : "男","mobile" : "19000001111","salary":1333,"deptName" : "技术部","address" : "湖北省武汉市洪山区光谷大厦","content" : "i like to write best elasticsearch article"}
    {"index":{"_id": 2}}
    {"empId" : "222","name" : "员工2","age" : 25,"sex" : "男","mobile" : "19000002222","salary":15963,"deptName" : "销售部","address" : "湖北省武汉市江汉路","content" : "i think java is the best programming language"}
    {"index":{"_id": 3}}
    { "empId" : "333","name" : "员工3","age" : 30,"sex" : "男","mobile" : "19000003333","salary":20000,"deptName" : "技术部","address" : "湖北省武汉市经济开发区","content" : "i am only an elasticsearch beginner"}
    {"index":{"_id": 4}}
    {"empId" : "444","name" : "员工4","age" : 20,"sex" : "女","mobile" : "19000004444","salary":5600,"deptName" : "销售部","address" : "湖北省武汉市沌口开发区","content" : "elasticsearch and hadoop are all very good solution, i am a beginner"}
    {"index":{"_id": 5}}
    { "empId" : "555","name" : "员工5","age" : 20,"sex" : "男","mobile" : "19000005555","salary":9665,"deptName" : "测试部","address" : "湖北省武汉市东湖隧道","content" : "spark is best big data solution based on scala ,an programming language similar to java"}
    {"index":{"_id": 6}}
    {"empId" : "666","name" : "员工6","age" : 30,"sex" : "女","mobile" : "19000006666","salary":30000,"deptName" : "技术部","address" : "湖北省武汉市江汉路","content" : "i like java developer"}
    {"index":{"_id": 7}}
    {"empId" : "777","name" : "员工7","age" : 60,"sex" : "女","mobile" : "19000007777","salary":52130,"deptName" : "测试部","address" : "湖北省黄冈市边城区","content" : "i like elasticsearch developer"}
    {"index":{"_id": 8}}
    {"empId" : "888","name" : "员工8","age" : 19,"sex" : "女","mobile" : "19000008888","salary":60000,"deptName" : "技术部","address" : "湖北省武汉市江汉大学","content" : "i like spark language"}
    {"index":{"_id": 9}}
    {"empId" : "999","name" : "员工9","age" : 40,"sex" : "男","mobile" : "19000009999","salary":23000,"deptName" : "销售部","address" : "河南省郑州市郑州大学","content" : "i like java developer"}
    {"index":{"_id": 10}}
    {"empId" : "101010","name" : "张湖北","age" : 35,"sex" : "男","mobile" : "19000001010","salary":18000,"deptName" : "测试部","address" : "湖北省武汉市东湖高新","content" : "i like java developer i also like  elasticsearch"}
    {"index":{"_id": 11}}
    {"empId" : "111111","name" : "王河南","age" : 61,"sex" : "男","mobile" : "19000001011","salary":10000,"deptName" : "销售部","address" : "河南省开封市河南大学","content" : "i am not like  java "}
    {"index":{"_id": 12}}
    {"empId" : "121212","name" : "张大学","age" : 26,"sex" : "女","mobile" : "19000001012","salary":1321,"deptName" : "测试部","address" : "河南省开封市河南大学","content" : "i am java developer  thing java is good"}
    {"index":{"_id": 13}}
    {"empId" : "131313","name" : "李江汉","age" : 36,"sex" : "男","mobile" : "19000001013","salary":1125,"deptName" : "销售部","address" : "河南省郑州市二七区","content" : "i like java and java is very best i like it do you like java "}
    {"index":{"_id": 14}}
    {"empId" : "141414","name" : "王技术","age" : 45,"sex" : "女","mobile" : "19000001014","salary":6222,"deptName" : "测试部","address" : "河南省郑州市金水区","content" : "i like c++"}
    {"index":{"_id": 15}}
    {"empId" : "151515","name" : "张测试","age" : 18,"sex" : "男","mobile" : "19000001015","salary":20000,"deptName" : "技术部","address" : "河南省郑州高新开发区","content" : "i think spark is good"}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    3 单个字段查询逻辑及算分

    3.1 单个Address地址查询算分

    现在想找 地址:湖北省 或者开封市 的人

    get /testfields/_search
    {
      "query":{
         //搜索 address 中包含 湖北省 或 开封市 的信息
              "match": {
                "address": {
                  "query": "湖北省 开封市",
                  "operator": "or"
                }
              }
          
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可以查看查询结果 ,address中 是湖北省 或者开封市 来判断的
    为什么开封市的考前,湖北省的靠后?
    开封市 只有3个文档相关,但是湖北省有10个文档相关,自然而然TFIDF计算权重的时候认为开封市 在所有的文档中 更有标识意义,所以开封市权重高,排在最前面,我用表格统计了下分数

    员工address说明分数
    员工11address 包含 开封市s core: 3.0543272
    员工12address 包含 开封市s core: 3.0543272
    员工3address 包含 湖北省s core: 2.1525636
    员工4address 包含 湖北省s core: 2.1525636
    员工5address 包含 湖北省s core: 1.3682688
    员工10address 包含 湖北省s core: 1.3682688
    员工2address 包含 湖北省s core:1.2228065
    员工6address 包含 湖北省s core: 1.2228065
    员工7address 包含 湖北省s core: 1.2228065
    员工8address 包含 湖北省s core: 1.1727825

    结果如图所示:
    在这里插入图片描述

    3.2 单个Content内容查询算分

    现在想找 content 中包含 elasticsearch 或 beginner的信息

    get /testfields/_search
    {
      "query":{
         //搜索 content 中包含 elasticsearch 或 beginner的信息
              "match": {
                "content": {
                  "query": "elasticsearch beginner",
                  "operator": "or"
                }
              }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    可以查看查询结果 ,content 中 是包含 elasticsearch 或 beginner的信息
    我用表格统计了下分数

    员工content 说明分数
    员工3content 包含 elasticsearch 和 beginner,两个都有 而且紧邻挨着 分数最高s core: 3.1380997
    员工4content 包含 elasticsearch 和 beginner 两个都有 但是两个单词 分开的s core: 2.2975376
    员工7content 包含 elasticsearchs core: 1.3051386
    员工1content 包含 elasticsearchs core: 1.0801146
    员工10content 包含 elasticsearchs core: 1.0214127

    结果如图所示:
    在这里插入图片描述

    4 BestFields 多字段查询

    4.1 BestFields 多字段查询返回某个字段精确匹配读最高的结果及算分

    现在想根据多字段匹配,采用BestFields策略去匹配某一个字段精确度最高的

    • address 地址包含 湖北省 或者 开封市 的人
    • content 中包含 elasticsearch 或 beginner的人
    get /testfields/_search
    {
      "query":{
            "multi_match": {
            "query":                "elasticsearch beginner 湖北省 开封市",
            "type":                 "best_fields",
            "fields":               [ "content", "address" ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    **可以查看查询结果 ,这个分数 就是单个字段 最高分匹配返回结果,BestFields,按照分数最高最匹配的返回

    员工分数计算逻辑
    员工33.13809973.1380997 = 员工3 第一步address 地址环节得分2.1525636 , 第二步 员工3 content环节计算 3.1380997 ~ 取最高匹配字段 content 返回 =3.1380997
    员工113.05432723.0543272 = 员工11 第一步address环节计算3.0543272 ,第二步员工11 content环节 不存在 0 分 ~取最高匹配字段 content 返回 =3.0543272
    员工123.05432725.29 = 员工12第一步address环节计算3.0543272 ,第二步员工12 content环节 不存在 0 分 ~取最高匹配字段 content 返回 =3.0543272

    查看结果:
    在这里插入图片描述

    所以 BestFields 就是 多个字段中返回 匹配度最高的那条记录 返回结果, 所以就是你看到的百度 前几条最匹配,后面的区分度不高

    4.2 BestFields 参数tie_breaker 设置让其他匹配结果也参与计算

    可以设置tie_breaker参数 [0~1]之间 ,然后 正常来说BestFields 是返回 最高分数,忽略 其他配条件的, 但是如果加上了 tie_breaker参数后, 就是其他条件 的得分 * tie_breaker 然后累加 ,也参与到 计算相关度总分 ,不给tie_breaker参数就是不参与即其他字段为0

    #采用  bestFields 查询 携带参数 tie_breaker 0.1 就是 如果其他字段也匹配到了 ,其他字段的得分 * 0.1 + 最高的得分 累加计算最终相关度总分
    get /testfields/_search
    {
      "query":{
        "multi_match": {
          "query": "elasticsearch beginner 湖北省 开封市",
          "type": "best_fields", 
          "fields": ["address","content"],
          "tie_breaker": 0.1
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    可以看到查询结果
    员工 3 分数 3.3533561 = 2.1525636 * 0.1 + 3.1380997

    • 原BestFields 分数 3.1380997 = 员工3 第一步address 地址环节得分2.1525636 , 第二步 员工3 content环节计算 3.1380997 ~ 取最高匹配字段 content 返回 =3.1380997
    • 现在 加了tie_breaker = 0.1 分数=3.3533561 = 员工3 第一步address 地址环节得分2.1525636 , 第二步 员工3 content环节计算 3.1380997 ~ 取最高匹配字段 3.1380997 + 其他字段分2.1525636 * 0.1 (tie_breaker配置) = 3.35最终分

    在这里插入图片描述

    4.3 BestFields 参数minimum_should_match 设置控制搜索的精确度

    可以设置minimum_should_match [x%] 来控制匹配多少个单词 的doc才能被匹配命中
    我们现在搜索了 4个参数 湖北省 开封市 elasticsearch beginner 如果不设置 该参数, 那就是任何一个单词匹配到 都会返回

    不加参数 查询

    get /testfields/_search
    {
      "query":{
        "multi_match": {
          "query": "elasticsearch beginner 湖北省 开封市",
          "type": "best_fields", 
          "fields": ["address","content"],
          "tie_breaker": 0.1
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    查询结果, 只要有一个字段匹配 就会命中,比如 address 湖北省 ,content中没有任何 elasticsearch beginner的记录也命中了,这明显不是我们要的结果,太多其他无用的结果了,如何提高精度
    在这里插入图片描述

    该如何控制 搜索的精度 ,比如 至少我要匹配三个 单词 ,才给我搜出来 ?如何实现 ? 用 minimum_should_match

    现在又 四个搜索字段, 设置 minimum_should_match :4 什么意思 ?控制分词条件在倒排索引中最少的数量,表示最少匹配倒排索引个数
    !!!!! 注意是 命中倒排索引的数量,要看你如何分词
    !!!!! 注意是 命中倒排索引的数量,要看你如何分词
    !!!!! 注意是 命中倒排索引的数量,要看你如何分词
    我这里没做分词,所以 湖北省 开封市 被拆成了 单个字 的倒排索引 ,“湖”,“北”,“省”,“开”,“封”,“市”
    所以你设置 minimum_should_match 1,2,3,4 能匹配4个字的 很多记录都命中
    如果设置 5 ,那就是 除了 “湖”,“北”,“省”, “市”/ 或者 “开”,“封”,“市”,"省"四个 命中外 ,还需要再 content中 再命中 一个,才能算 5个,这样搜索精度就提高了

    get /testfields/_search
    {
      "query":{
        "multi_match": {
          "query": "elasticsearch beginner 湖北省 开封市",
          "type": "best_fields", 
          "fields": ["address","content"],
          "tie_breaker": 0.1,
          //1,2,3,4 以下 全部匹配
          //因为 倒排索引是单个字分词的 湖 北 省  开 封 市 任何四个倒排匹配就命中
          "minimum_should_match": 5
        }
      }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    可以看到查询结果 ,只剩下 2条记录, 匹配后才命中,提高了查询 精确度
    在这里插入图片描述

    4.4 BestFields 等价于 Dis_mix查询方式
    #采用dix_max查询方式,等价于 bestFields
    get /testfields/_search
    {
      "query":{
        //dis_max查询方式等价于 bestFields
        "dis_max": {
          "queries": [
            {
              "match": {
                "address": {
                  "query": "湖北省 开封市",
                  "operator": "or"
                }
              }
            },
            {
              "match": {
                "content": {
                  "query": "elasticsearch beginner",
                  "operator": "or"
                }
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    可以看到查询结果和刚才BestFields 查询 的一摸一样,结果排序一样,结果分数一样
    在这里插入图片描述

    5 MostFields 多字段查询及算分

    5.1 MostFields最多字段匹配返回多字段匹配累计总分

    现在想根据多字段查找,采用MostFields策略去匹配最多字段符合要求的document 返回结果

    • address 地址包含 湖北省 或者 开封市 的人
    • content 中包含 elasticsearch 或 beginner的人
    //multi_match 多字段匹配查询 most_fields策略
    get /testfields/_search
    {
      "query":{
        "multi_match": {
          "query": "elasticsearch beginner 湖北省 开封市",
          "type": "most_fields", 
          "fields": ["address","content"]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    可以查看查询结果 ,这个分数 就是多字段匹配结果,按照分数最高 的返回, 但是分数怎么计算最高呢?累加而来

    员工分数计算逻辑
    员工35.29066325.29 = 员工3 第一步address环节计算2.1525636 + 第二步员工3 content环节计算 3.1380997 ~ 累加 =5.29
    员工44.4501014.45 = 员工4 第一步address环节计算2.1525636 + 第二步员工4 content环节计算 2.2975376 ~ 累加 =4.45
    员工113.05432723.05 = 员工11 第一步address环节计算3.0543272 + 第二步员工11 content环节 不存在 0 分 ~ 累加 =3.05
    员工123.05432725.29 = 员工12 第一步address环节计算3.0543272 + 第二步员工12 content环节 不存在 0 分 ~ 累加 =3.05

    在这里插入图片描述
    所以 最高的就是 第一步地址,第二步content内容搜索的 累加的总分 员工3的分数最高,排序最先返回
    这就是 MostFields ,会综合各个字段然后参与计算, 找出多个字段匹配的 结果,也就是wiki的搜索策略,尽可能多的匹配内容,但是最匹配的可能不是最优先返回的

    5.2 MostFields 等价bool should 查询方式

    现在想根据多字段查找,采用bool should的方式来实现查询,看下结果如何

    • address 地址包含 湖北省 或者 开封市 的人
    • content 中包含 elasticsearch 或 beginner的人
    get /testfields/_search
    {
      "query":{
        "bool": {
          "should": [
            {
              //搜索 content 中包含 java 或 developer的信息
              "match": {
                "content": {
                  "query": "elasticsearch beginner",
                  "operator": "or"
                }
              }
            },
                    {
              //搜索 address 中包含 开封市 或 湖北省 的信息
              "match": {
                "address": {
                  "query": " 湖北省 开封市",
                  "operator": "or"
                }
              }
            }
          ]
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    可以查看查询结果 ,是和Most Fields查询结果一致的,分数都是累加做排名的
    在这里插入图片描述


    至此 我们已经能够 讲解了 BestFields 及 MostFields 字段中心的查询处理方式, 下一篇,我们讲一下 字段中心带来的问题及解决方案 词条为中心

  • 相关阅读:
    【ES6】
    mysql索引原理
    网络安全之XSS漏洞
    从零开发小程序和公众号【第三期】
    Spring Boot 集成 MinIO 实现文件上传
    FileZilla Server 1.8.1内网搭建
    《Linux运维总结:基于快照模式迁移单节点elasticsearch数据(方案二)》
    【Linux学习笔记1】-【网络连接的三种模式:桥接模式、NAT模式、主机模式,克隆虚拟机,虚拟机快照,安装vmtools,设置共享文件夹】
    运动款蓝牙耳机哪个品牌好、运动蓝牙耳机推荐高性价比
    r9 5900hx和i9 12900h哪个好
  • 原文地址:https://blog.csdn.net/u010134642/article/details/125465426