当前位置: 首页 > article >正文

ElasticSearch7.x入门教程之全文搜索(七)

文章目录

  • 前言
  • 一、多条件查询:bool query
  • 二、更加精准查询:dis_max query
  • 总结


前言

这里再接着上一篇文章继续记录。非常感谢江南一点雨松哥的文章。
欢迎大家去查看,地址:http://www.javaboy.org


一、多条件查询:bool query

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

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

例如查询楼层大于20层小于25且为城市住宅,地址为草堂街道,或者不是光华街道的数据

GET /building_info/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "floor": {
              "gte": 20,
              "lte": 25
            }
          }
        },
        {
          "term": {
            "type": {
              "value": "城市住宅"
            }
          }
        }
      ],
      "should": [
        {
          "match": {
            "address": "草堂街道"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "address": "光华街道"
          }
        }
      ]
    }
  }
}

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

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

假设我们要做一次查询,查询 address 中包含 杜甫草堂街道 关键字的文档:

GET /building_info/_search  
{
  "query": {
    "match": {
      "address": {
        "query": "杜甫草堂街道"
      }
    }
  }
}

分词如下:

{
  "tokens" : [
    {
      "token" : "杜甫",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "CN_WORD",
      "position" : 0
    },
    {
      "token" : "草堂",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "CN_WORD",
      "position" : 1
    },
    {
      "token" : "街道",
      "start_offset" : 4,
      "end_offset" : 6,
      "type" : "CN_WORD",
      "position" : 2
    }
  ]
}

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

GET /building_info/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "address": {
              "value": "杜甫"
            }
          }
        },
        {
          "term": {
            "address": {
              "value": "草堂"
            }
          }
        },
        {
          "term": {
            "address": {
              "value": "街道"
            }
          }
        }
      ]
    }
  }
}

在这两个查询语句中,都是文档只需要包含词项中的任意一项即可,文档就回被返回,在 match 查询中,可以通过 operator 参数设置文档必须匹配所有词项。
如果想匹配一部分词项,就涉及到一个参数,就是 minmum_should_match,即最小匹配度。即至少匹配多少个词。

GET building_info/_search
{
  "query": {
    "match": {
      "address": {
        "query": "杜甫草堂北路",
        "operator": "and"
      }
    }
  }
}

GET building_info/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "address": {
              "value": "杜甫"
            }
          }
        },
        {
          "term": {
            "address": {
              "value": "草堂"
            }
          }
        },
        {
          "term": {
            "address": {
              "value": "街道"
            }
          }
        }
      ],
      "minimum_should_match": "50%"
    }
  },
  "from": 0,
  "size": 5
}

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

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

GET building_info/_search
{
  "query": {
    "match": {
      "address": {
        "query": "杜甫草堂街道",
        "minimum_should_match": 3
      }
    }
  }
}
# 关键字分词后有3个词
GET building_info/_search
{
  "query": {
    "match": {
      "name": {
        "query": "杜甫草堂街道",
        "operator": "and"
      }
    }
  }
}

二、更加精准查询: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解决方案"
          }
        }
      ]
    }
  }
}

搜索结果如下:
在这里插入图片描述
肉眼观察,感觉第二个和查询关键字相似度更高,但是实际查询结果并非这样。

要理解这个原因,我们需要来看下 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解决方案"
          }
        }
        ]
    }
  }
}

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


总结

这篇文章记录还算是比较有用的东西。


http://www.kler.cn/a/416942.html

相关文章:

  • 基于Pytorch的CIFAR100数据集上从ResNet50到VGG16的知识蒸馏实验记录
  • mac上的建议xftp 工具
  • Vue3组件通信的8种方式,完整源码带注释
  • 美国网络安全态势感知(4):威胁情报发展现状
  • [Java]微服务配置管理
  • Nginx:ssl
  • 深入理解 GitHub 高级应用:从分支管理到自动化工作流
  • 【大数据学习 | Spark调优篇】Spark之JVM调优
  • iOS开发之修改已有项目的项目名和类名前缀
  • Shell脚本小练习
  • GitLab: You cannot create a branch with a SHA-1 or SHA-256 branch name
  • java基础概念43:Lambda表达式
  • [Ubuntu] linux之Ubuntu18.04的下载及在虚拟机中详细安装过程(附有下载链接)
  • 计算机基础 原码反码补码问题
  • 大数据新视界 -- 大数据大厂之 Hive 数据质量监控:实时监测异常数据(下)(18/ 30)
  • 暴雨发布首款兆芯KX-7000信创笔记本
  • Android 12系统源码_RRO机制(一)Runtime Resource Overlay机制实践
  • RFID资产管理系统的应用与未来发展
  • 初学git报错处理 | 从IDEA远程拉取、创建分支中“clone failed”“couldn‘t checkout”
  • otter 高可用策略
  • 聚云科技×亚马逊云科技:打通生成式AI落地最后一公里
  • javaScript数据类型存储
  • 基于Java Springboot个人记账之财来财往微信小程序
  • django开发中html继承模板样式
  • Vue程序调试和排错技巧
  • Oracle 深入学习 Part 10: Managing Undo Data(管理Undo数据)