简介
disjunction max query 简称 dis_max,是分离最大化查询的意思。注意这个名字中的两个重点:分离、最大化。
- disjunction(分离)的含义是:表示把同一个文档中的每个字段上的查询都分开,分别进行算分操作。
- max(最大化): 是将多个字段查询的得分的最大值作为最终评分返回。
所以 disjunction max query 的效果是:将所有与任一查询匹配的文档作为结果返回,但是只将最佳匹配的得分作为查询的算分结果进行返回。不过其他匹配的字段可以使用 “tie_breaker” 参数来进行“维权”。
准备数据
- 为帖子数据增加content字段 ```json DELETE /article
POST /article/_bulk { “create”: { “_id”: “1”} } {“title” : “elasticsearch” } { “create”: { “_id”: “2”} } {“title” : “java”} { “create”: { “_id”: “3”} } {“title” : “elasticsearch”} { “create”: { “_id”: “4”} } {“title” : “hadoop”} { “create”: { “_id”: “5”} } {“title” : “spark”}
POST /article/_bulk { “update”: { “_id”: “1”} } { “doc” : {“content” : “i like to write best elasticsearch article”} } { “update”: { “_id”: “2”} } { “doc” : {“content” : “i think java is the best programming language”} } { “update”: { “_id”: “3”} } { “doc” : {“content” : “i am only an elasticsearch beginner”} } { “update”: { “_id”: “4”} } { “doc” : {“content” : “elasticsearch and hadoop are all very good solution, i am a beginner”} } { “update”: { “_id”: “5”} } { “doc” : {“content” : “spark is best big data solution based on scala ,an programming language similar to java”} }
2. 搜索title或content中包含java或solution的帖子
下面这个就是multi-field搜索,多字段搜索
```json
GET /article/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"title": "java solution"
}
},
{
"match": {
"content": "java solution"
}
}
]
}
}
}
# 输出
{
"took" : 35,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 2.4211318,
"hits" : [
{
"_index" : "article",
"_type" : "_doc",
"_id" : "2",
"_score" : 2.4211318,
"_source" : {
"title" : "java",
"content" : "i think java is the best programming language"
}
},
{
"_index" : "article",
"_type" : "_doc",
"_id" : "5",
"_score" : 1.4233949,
"_source" : {
"title" : "spark",
"content" : "spark is best big data solution based on scala ,an programming language similar to java"
}
},
{
"_index" : "article",
"_type" : "_doc",
"_id" : "4",
"_score" : 0.79423964,
"_source" : {
"title" : "hadoop",
"content" : "elasticsearch and hadoop are all very good solution, i am a beginner"
}
}
]
}
}
分析
- 结果分析
期望的是doc5排在了前面,结果是doc2排在了前面
算一下doc2的分数
{ “match”: { “title”: “java solution” }},针对doc2,是有一个分数的
{ “match”: { “content”: “java solution” }},针对doc2,也是有一个分数的
所以是两个分数加起来,比如说,1.0 + 1.3 = 2.3
算一下doc5的分数
{ “match”: { “title”: “java solution” }},针对doc5,是没有分数的
{ “match”: { “content”: “java solution” }},针对doc5,是有一个分数的
处理
- 解决
如果不是简单将每个字段的评分结果加在一起, 最佳匹配 字段的评分作为查询的整体评分,结果会怎样?这样返回的结果可能是: 同时 包含 而是将 java 和 solution 的单个字段比反复出现相同词语的 多个不同字段有更高的相关度。
- best_fields策略,就是说,搜索到的结果,应该是某一个field中匹配到了尽可能多的关键词,被排 在前面;而不是尽可能多的field匹配到了少数的关键词,排在了前面
- dis_max语法,直接取多个query中,分数最高的那一个query的分数即可 ```json { “match”: { “title”: “java solution” }},针对doc2,是有一个分数的,1.0 { “match”: { “content”: “java solution” }},针对doc2,也是有一个分数的,1.3 取最大分数,1.3
{ “match”: { “title”: “java solution” }},针对doc5,是没有分数的 { “match”: { “content”: “java solution” }},针对doc5,是有一个分数的,1.4 取最大分数,1.4
然后doc2的分数 = 1.3 < doc5的分数 = 1.4,所以doc5就可以排在更前面的地方,符合我们的需要
```json
GET /article/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"title": "java solution"
}
},
{
"match": {
"content": "java solution"
}
}
]
}
}
}
其他字段作为辅助
GET /article/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"title": "java solution"
}
},
{
"match": {
"content": "java solution"
}
}
],
"tie_breaker": 0.2
}
}
}
- 获得最佳匹配语句的评分 score。
- 将其他匹配语句的评分与 tie breaker相乘
- 对以上评分求和并规范化
tier breaker是一个介于0-1之间的浮点数。
- 0 代表使用最佳匹配
- 1代表所有语句同等重要
而这个例子中的tie_breaker会重新让dis_max考虑到其他field的得分影响,比如下面的0.4,表示最终的doc得分会考虑其他match的影响,但是它的影响会被弱化成原来的0.4。
GET /your_index/your_type/_search
{
# 基于 tie_breaker 优化dis_max
# tie_breaker可以使dis_max考虑其它field的得分影响
"query": {
# 直接取下面多个query中得分最高的query当成最终得分
# 这也是best field策略
"dis_max": {
"queries":[
{"match":{"name":"关注"}},
{"match":{"content":"白日梦"}}
],
"tie_breaker":0.4
}
}
}
多字段查询使用
GET /book/_search
{
"query": {
"multi_match": {
"type": "best_fields",
"tie_breaker": 0.2,
"query": "elasticsearch",
"minimum_should_match": "20%",
"fields": ["description","name"]
}
}
}
简单例子
POST books/_search
{
"query": {
"dis_max": {
"queries": [
{
"term": {
"name": {
"value": "linux"
}
}
},
{
"term": {
"intro": {
"value": "kernel"
}
}
}
],
"tie_breaker": 0.9
}
}
}
如上示例,我们查询书名中出现 “linux” 或者书本简介中出现 “kernel” 的文档,而最终返回的相关性评分将以匹配 “linux” 或者匹配 “kernel” 中最大的那个评分为准。
在介绍 mutil-match 的时候也有一个 tie_breaker 参数,其作用跟本实例中的一样,今天我们来复习一下。 当指定 “tie_breaker” 的时候,算分结果将会由以下算法来决定:
- 令算分最高的字段的得分为 s1
- 令其他匹配的字段的算分 * tie_breaker 的和为 s2
- 最终算分为:s1 + s2
“tie_breaker” 的取值范围为:[0.0, 1.0]。当其为 0.0 的时候,按照上述公式来计算,表示使用最佳匹配字段的得分作为相关性算分。当其为 1.0 的时候,表示所有字段的得分同等重要。当其在 0.0 到 1.0 之间的时候,代表其他字段的得分也需要参与到总得分的计算当中去。通俗来说就是其他字段可以使用 “tie_breaker” 来进行“维权” 。