ElasticSearch 复合查询,理解 Es 中的文档评分策略!

2年前 (2022) 程序员胖胖胖虎阿
217 0 0

松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->松哥要升级 SpringBoot 视频了,看看新增了哪些内容!

ElasticSearch 系列已经整到第 21 篇啦,今天我们来学习 Es 中的复合查询,复合查询这块我打算通过三个视频来和小伙伴们分享,今天我们先来看前两个。

constant_score query & bool query:

dis_max query:

如果大家觉得视频风格还能接受,也可以看看松哥的付费视频:Spring Boot+Vue+微人事视频教程

以下是视频笔记:

注意,笔记只是视频内容的一个简要记录,因此笔记内容比较简单,完整的内容可以查看视频。

17.ElasticSearch 复合查询

17.1 constant_score query

当我们不关心检索词项的频率(TF)对搜索结果排序的影响时,可以使用 constant_score 将查询语句或者过滤语句包裹起来。

GET books/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "name""java"
        }
      },
      "boost": 1.5
    }
  }
}

17.2 bool query

bool query 可以将任意多个简单查询组装在一起,有四个关键字可供选择,四个关键字所描述的条件可以有一个或者多个。

  • must:文档必须匹配 must 选项下的查询条件。
  • should:文档可以匹配 should 下的查询条件,也可以不匹配。
  • must_not:文档必须不满足 must_not 选项下的查询条件。
  • filter:类似于 must,但是 filter 不评分,只是过滤数据。

例如查询 name 属性中必须包含 java,同时书价不在 [0,35] 区间内,info 属性可以包含 程序设计 也可以不包含程序设计:

GET books/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "name": {
              "value""java"
            }
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "price": {
              "gte": 0,
              "lte": 35
            }
          }
        }
      ],
      "should": [
        {
          "match": {
            "info""程序设计"
          }
        }
      ]
    }
  }
}

这里还涉及到一个关键字,minmum_should_match 参数。

minmum_should_match 参数在 es 官网上称作最小匹配度。在之前学习的 multi_match 或者这里的 should 查询中,都可以设置 minmum_should_match 参数。

假设我们要做一次查询,查询 name 中包含 语言程序设计 关键字的文档:

GET books/_search
{
  "query": {
    "match": {
      "name""语言程序设计"
    }
  }
}

在这个查询过程中,首先会进行分词,分词结果如下:

ElasticSearch 复合查询,理解 Es 中的文档评分策略!
image-20201116160012407

分词后的 term 会构造成一个 should 的 bool query,每一个 term 都会变成一个 term query 的子句。换句话说,上面的查询和下面的查询等价:

GET books/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "name": {
              "value""语言"
            }
          }
        },
        {
          "term": {
            "name": {
              "value""程序设计"
            }
          }
        },
        {
          "term": {
            "name": {
              "value""程序"
            }
          }
        },
        {
          "term": {
            "name": {
              "value""设计"
            }
          }
        }
      ]
    }
  }
}

在这两个查询语句中,都是文档只需要包含词项中的任意一项即可,文档就回被返回,在 match 查询中,可以通过 operator 参数设置文档必须匹配所有词项。

如果想匹配一部分词项,就涉及到一个参数,就是 minmum_should_match,即最小匹配度。即至少匹配多少个词。

GET books/_search
{
  "query": {
    "match": {
      "name": {
        "query""语言程序设计",
        "operator""and"
      }
    }
  }
}

GET books/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "name": {
              "value""语言"
            }
          }
        },
        {
          "term": {
            "name": {
              "value""程序设计"
            }
          }
        },
        {
          "term": {
            "name": {
              "value""程序"
            }
          }
        },
        {
          "term": {
            "name": {
              "value""设计"
            }
          }
        }
      ],
      "minimum_should_match""50%"
    }
  },
  "from": 0,
  "size": 70
}

50% 表示词项个数的 50%。

如下两个查询等价(参数 4 是因为查询关键字分词后有 4 项):

GET books/_search
{
  "query": {
    "match": {
      "name": {
        "query""语言程序设计",
        "minimum_should_match": 4
      }
    }
  }
}
GET books/_search
{
  "query": {
    "match": {
      "name": {
        "query""语言程序设计",
        "operator""and"
      }
    }
  }
}

17.3 dis_max query

假设现在有两本书:

PUT blog
{
  "mappings": {
    "properties": {
      "title":{
        "type""text",
        "analyzer""ik_max_word"
      },
      "content":{
        "type""text",
        "analyzer""ik_max_word"
      }
    }
  }
}

POST blog/_doc
{
  "title":"如何通过Java代码调用ElasticSearch",
  "content":"松哥力荐,这是一篇很好的解决方案"
}

POST blog/_doc
{
  "title":"初识 MongoDB",
  "content":"简单介绍一下 MongoDB,以及如何通过 Java 调用 MongoDB,MongoDB 是一个不错 NoSQL 解决方案"
}

现在假设搜索 Java解决方案 关键字,但是不确定关键字是在 title 还是在 content,所以两者都搜索:

GET blog/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title""java解决方案"
          }
        },
        {
          "match": {
            "content""java解决方案"
          }
        }
      ]
    }
  }
}

搜索结果如下:

ElasticSearch 复合查询,理解 Es 中的文档评分策略!
image-20201116210227090

肉眼观察,感觉第二个和查询关键字相似度更高,但是实际查询结果并非这样。

要理解这个原因,我们需要来看下 should query 中的评分策略:

  1. 首先会执行 should 中的两个查询
  2. 对两个查询结果的评分求和
  3. 对求和结果乘以匹配语句总数
  4. 在对第三步的结果除以所有语句总数

反映到具体的查询中:

前者

  1. title 中 包含 java,假设评分是 1.1
  2. content 中包含解决方案,假设评分是 1.2
  3. 有得分的 query 数量,这里是 2
  4. 总的 query 数量也是 2

最终结果:(1.1+1.2)*2/2=2.3

后者

  1. title 中 不包含查询关键字,没有得分
  2. content 中包含解决方案和 java,假设评分是 2
  3. 有得分的 query 数量,这里是 1
  4. 总的 query 数量也是 2

最终结果:2*1/2=1

在这种查询中,title 和 content 相当于是相互竞争的关系,所以我们需要找到一个最佳匹配字段。

为了解决这一问题,就需要用到 dis_max query(disjunction max query,分离最大化查询):匹配的文档依然返回,但是只将最佳匹配的评分作为查询的评分。

GET blog/_search
{
  "query": {
    "dis_max": {
      "queries": [
        {
          "match": {
            "title""java解决方案"
          }
        },
        {
          "match": {
            "content""java解决方案"
          }
        }
        ]
    }
  }
}

查询结果如下:

ElasticSearch 复合查询,理解 Es 中的文档评分策略!
image-20201116211505751

在 dis_max query 中,还有一个参数 tie_breaker(取值在0~1),在 dis_max query 中,是完全不考虑其他 query 的分数,只是将最佳匹配的字段的评分返回。但是,有的时候,我们又不得不考虑一下其他 query 的分数,此时,可以通过 tie_breaker 来优化 dis_max query。tie_breaker 会将其他 query 的分数,乘以 tie_breaker,然后和分数最高的 query 进行一个综合计算。

ElasticSearch 系列其他文章:

  1. 打算出一个 ElasticSearch 教程,谁赞成,谁反对?
  2. ElasticSearch 从安装开始
  3. ElasticSearch 第三弹,核心概念介绍
  4. ElasticSearch 中的中文分词器该怎么玩?
  5. ElasticSearch 索引基本操作
  6. ElasticSearch 文档的添加、获取以及更新
  7. ElasticSearch 文档的删除和批量操作
  8. ElasticSearch 文档路由,你的数据到底存在哪一个分片上?
  9. ElasticSearch 并发的处理方式:锁和版本控制
  10. ElasticSearch 中的倒排索引到底是什么?
  11. ElasticSearch 动态映射与静态映射
  12. ElasticSearch 四种字段类型详解
  13. ElasticSearch 中的地理类型和特殊类型
  14. ElasticSearch 23 种映射参数详解
  15. ElasticSearch 如何配置某个字段的权重?
  16. ElasticSearch 23 种映射参数详解【3】
  17. ElasticSearch 映射模版
  18. ElasticSearch 搜索入门
  19. ElasticSearch 全文搜索怎么玩?
  20. ElasticSearch 打错字还能搜索到?试试 fuzzy query!






往期推荐
0
1

50+ 需求文档免费下载!

0
2

Spring Security 教程合集

0
3

接了两个私活,都是血汗钱

ElasticSearch 复合查询,理解 Es 中的文档评分策略!

本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

相关文章

暂无评论

暂无评论...