复合查询

说明:该博客对于的Elasticsearch 的版本为7.3。

复合查询有bool query(布尔查询)、boosting query(提高查询)、constant_score (固定分数查询)、dis_max(最佳匹配查询)、function_score(函数查询)。

一、bool query(布尔查询)

1、概念

定义 可以理解成通过布尔逻辑将较小的查询组合成较大的查询。

Bool查询语法有以下特点

  1. 子查询可以任意顺序出现
  2. 可以嵌套多个查询,包括bool查询
  3. 如果bool查询中没有must条件,should中必须至少满足一条才会返回结果。

bool查询包含四种操作符,分别是must,should,must_not,query。他们均是一种数组,数组里面是对应的判断条件。

must:    必须匹配。贡献算分
must_not:过滤子句,必须不能匹配,但不贡献算分
should: 选择性匹配,至少满足一条。贡献算分
filter: 过滤子句,必须匹配,但不贡献算分

2、官方例子

看下官方举例

POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}

在filter元素下指定的查询对评分没有影响 , 评分返回为0。分数仅受已指定查询的影响。

官方例子

GET _search
{
"query": {
"bool": {
"filter": {
"term": {
"status": "active"
}
}
}
}
}

这个例子查询查询为所有文档分配0分,因为没有指定评分查询。

官方例子

GET _search
{
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": {
"term": {
"status": "active"
}
}
}
}
}

此bool查询具有match_all查询,该查询为所有文档指定1.0分。

3、Bool嵌套查询

# 嵌套,实现了 should not 逻辑
POST /products/_search
{
"query": {
"bool": {
"must": {
"term": {
"price": "30"
}
},
"should": [
{
"bool": {
"must_not": {
"term": {
"avaliable": "false"
}
}
}
}
],
"minimum_should_match": 1
}
}
}

二、boosting query

1、概念

在上面的复合查询我们可以通过must_not+must 先剔除不想匹配的文档,再获取匹配的文档,但是有一种场景就是我并不需要完全剔除,而是把需要剔除的那部分文档的

分数降低。这个时候就可以使用boosting query。下面会举例说明。

2、举例

1)、创建索引并添加数据

# 创建索引并添加数据
POST /news/_bulk
{ "index": { "_id": 1 }}
{ "content":"Apple Mac" }
{ "index": { "_id": 2 }}
{ "content":"Apple iPad" }
{ "index": { "_id": 3 }}
{ "content":"Apple employee like Apple Pie and Apple Juice" }

2)、 bool must复合查询

#查询结果3->1->2
POST news/_search
{
"query": {
"bool": {
"must": {
"match":{"content":"apple"}
}
}
}
}

3)、bool must_not复合查询

我们需要的是文档中需要包含 apple,但是文档中不包含 pie,那么我们可以这么做

#must_not的方式,将3的记录强制排除掉 (结果 1->2)
POST news/_search
{
"query": {
"bool": {
"must": {
"match":{"content":"apple"}
},
"must_not": {
"match":{"content":"pie"}
}
}
}
}

3)、 boosting query

上面第二种比较粗暴,可能我实际开发过程中,如果出现 pie,我并不想把这条记录完全过滤掉,而是希望降低他的分数,让它也出现在列表中,只是查询结果可能比较靠后。

# 通过Boosting的方式,将3的记录也纳入结果集,只是排名会靠后。(结果 1->2->3)
POST news/_search
{
"query": {
"boosting": {
"positive": {
"match": {
"content": "apple"
}
},
"negative": {
"match": {
"content": "pie"
}
},
"negative_boost": 0.5
}
}
}

说明boosting需要搭配三个关键字 positive , negative , negative_boost

只有匹配了 positive查询 的文档才会被包含到结果集中,但是同时匹配了negative查询 的文档会被降低其相关度,通过将文档原本的_score和negative_boost参数进行

相乘来得到新的_score。因此,negative_boost参数一般小于1.0。在上面的例子中,任何包含了指定负面词条的文档的_score都会是其原本_score的一半。

3、思考boosting query应用场景

场景举例 我们通过去索引中搜索 '苹果公司' 相关的信息,然后我们在查询中的信息为 '苹果'

1)那么我们查询的条件是:must = '苹果'。也就是文档中必须包含'苹果'

但是我们需要的结果是苹果公司相关信息,如果你的文档是 '苹果树','苹果水果',那么其实此苹果非彼苹果如果匹配到其实没有任何意义。

2)那么我们修改查询条件为: must = '苹果' AND must_not = '树 or 水果'

就是说就算文档包含了苹果,但因为包含了树或者水果那么我们也会过滤这条文档信息,因为我们要查的苹果公司相关信息,如果你是苹果树那对我来讲确实是不匹配,

所以直接过滤掉,看是没啥问题。

但是你想,这样做是不是太粗暴了,因为一个文档中包含'苹果'和'树'那不代表一定是苹果树,而可能是 '苹果公司组织员工一起去种树' 那么这条文档理应出现

而不是直接过滤掉,所以我们就可以用boosting query。就像上面这个例子一样。

三、constant_score(固定分数查询)

定义 常量分值查询,目的就是返回指定的score,一般都结合filter使用,因为filter context忽略score。

举例

(结果 1->2->3 同时分数都为2.5)
POST news/_search
{
"query": {
"constant_score": {
"filter": {
"match": {
"content":"apple"
}
},
"boost": 2.5
}
}
}

运行结果

可以看出分数都是2.5

四、dis_max(最佳匹配查询)

1、概念

dis_max : 只是取分数最高的那个query的分数而已。

看下官方例子

GET /_search
{
"query": {
"dis_max" : {
"queries" : [
{ "term" : { "title" : "Quick pets" }},
{ "term" : { "body" : "Quick pets" }}
],
"tie_breaker" : 0.7
}
}
}

解释

假设一条文档的'title'查询得分是 1,'body'查询得分是1.6。那么总得分为:1.6+1*0.7 = 2.3。

如果我们去掉 "tie_breaker" : 0.7 ,那么tie_breaker默认为0,那么这条文档的得分就是 1.6 + 1*0 = 1.6

2、举例

1)创建数据

#1、创建索引
PUT /dismax
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"title": {
"type":"text"
},
"content": {
"type":"text"
}
}
}
} #2、创建数据
PUT /dismax/_doc/1
{
"title" : "i like java",
"content" : "the weather is nice today"
}
PUT /dismax/_doc/2
{
"title" : "It will rain tomorrow",
"content" : "Development beginner"
}
PUT /dismax/_doc/3
{
"title" :"i like java is very much",
"content" :"I am a development beginner"
}

2)、should查询

#should查询查询 (结果 3->2->1
GET /dismax/_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "java beginner" }},
{ "match": { "content": "java beginner" }}
]
}
}
}

运行结果

should计算分值:1)、运行should子句中的两个查询 2)、相加查询返回的分值

doc1:title: 0.53 + content: 0 = 0.53

doc2:title:0 + content:0.59 = 0,59

doc3:title:0.41 + content:0.42 = 0.83

所有最终运行结果: 3 – 2 – 1

2)dis_max查询(不带tie_breaker)

#运行结果(2-1-3)
GET /dismax/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "java beginner" }},
{ "match": { "content": "java beginner" }}
]
}
}
}

运行结果

我们可以很明显看出: 只是取分数最高的那个query的分数排序。

doc1:title: 0.53 ; content: 0 = 0.53

doc2:title:0 ; content:0.59 = 0,59

doc3:title:0.41 ; content:0.42 = 0.42

所以这里的排序为 2 – 1 – 3

3)dis_max查询(不带tie_breaker)

#运行结果 3-2-1
GET /dismax/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "java beginner" }},
{ "match": { "content": "java beginner" }}
],
"tie_breaker" : 0.5
}
}
}

这里可以看出看出: 取分数最高的那个query的分数,同时其它子查询查询的分数乘以tie_breaker

doc1:title: 0.53 + content: 0 = 0.53

doc2:title:0 + content:0.59 = 0,59

doc3:title:0.41 + content:0.42*0.5 = 0.62

所以这里的排序为 3 – 2 – 1

五、function_score(函数查询)

1、概念

定义 function_score是处理分值计算过程的终极工具。它让你能够对所有匹配了主查询的每份文档调用一个函数来调整甚至是完全替换原来的_score。

注意 要使用function_score,用户必须定义一个查询和一个或多个函数,这些函数计算查询返回的每个文档的新分数。

它拥有几种预先定义好了的函数:

weight 对每份文档适用一个简单的提升,且该提升不会被归约:当weight为2时,结果为2 * _score。

field_value_factor 使用文档中某个字段的值来改变_score,比如将受欢迎程度或者投票数量考虑在内。

random_score 使用一致性随机分值计算来对每个用户采用不同的结果排序方式,对相同用户仍然使用相同的排序方式。

衰减函数(Decay Function) - linear,exp,gauss

将像publish_date,geo_location或者price这类浮动值考虑到_score中,偏好最近发布的文档,邻近于某个地理位置(译注:其中的某个字段)的文档或者价格

(译注:其中的某个字段)靠近某一点的文档。

script_score

使用自定义的脚本来完全控制分值计算逻辑。如果你需要以上预定义函数之外的功能,可以根据需要通过脚本进行实现。

2)使用场景

有关function_score如果要深入讲,估计一篇博客都不够,所以这里说下在现实中可能会用的场景,如果你有这些场景,那么就可以考虑用function_score。

1)假设我们又一个资讯类APP我们希望让人阅读量高的文章出现在结果列表的头部,但是主要的排序依据仍然是全文搜索分值。

2)当用户搜索酒店,它的要求是 1、离他目前位置1Km内 2、价格在500元内。如果我们只是使用一个 filter 排除所有市中心方圆 1KM以外的酒店,
再用一个filter排除每晚价格超过500元的酒店,这种作法太过强硬,可能有一间房在2K米,但是超级便宜一晚只要100元,用户可能会因此愿意妥协住这间房。

有关function_score例子这里就不写了,具体的可以参考官方文档:Function score query

参考

1、Elasticsearch核心技术与实战---阮一鸣(eBay Pronto平台技术负责人

2、ES7.3版官方复合查询API

3、Elasticsearch学习笔记—Boosting query

4、ElasticSearch - function_score

 我相信,无论今后的道路多么坎坷,只要抓住今天,迟早会在奋斗中尝到人生的甘甜。抓住人生中的一分一秒,胜过虚度中的一月一年!(11)

Elasticsearch(7) --- 复合查询的更多相关文章

  1. Elasticsearch实现复合查询,高亮结果等技巧

    一.Es的配置 实现es的全文检索功能的第一步,首先从与es进行连接开始,这里我使用的是es的5.x java api语法. public TransportClient esClient() thr ...

  2. java使用elasticsearch进行模糊查询-已在项目中实际应用

    java使用elasticsearch进行模糊查询 使用环境上篇文章本人已书写过,需要maven坐标,ES连接工具类的请看上一篇文章,以下是内容是笔者在真实项目中运用总结而产生,并写的是主要方法和思路 ...

  3. Elasticsearch——QueryBuilder简单查询

    elasticsearch中存储的全部文档 1.matchAllQuery() matchAllQuery()方法用来匹配全部文档 public class QueryTest {       pub ...

  4. Elasticsearch(5) --- Query查询和Filter查询

    Elasticsearch(5) --- Query查询和Filter查询 这篇博客主要分为 :Query查询和Filter查询.有关复合查询.聚合查询也会单独写篇博客. 一.概念 1.概念 一个查询 ...

  5. 014-elasticsearch5.4.3【五】-搜索API【三】复合查询boolQuery、constantScoreQuery、disMaxQuery

    一.概述 复合查询包装其他复合或叶子查询,以组合其结果和分数,更改其行为,或从查询切换到筛选器上下文. 1.1.constantScoreQuery 包含另一个查询但在过滤器上下文中执行的查询.所有匹 ...

  6. elasticsearch GIS空间查询问题解决

    在GIS行业的应用越来越广泛,GIS最常用根据区域进行空间数据查询     我定义了两个方法,一起来看一下: /** * geodistance filter * 一个过滤器来过滤基于一个特定的距离从 ...

  7. Hibernate的几种查询方式-HQL,QBC,QBE,离线查询,复合查询,分页查询

    HQL查询方式 这一种我最常用,也是最喜欢用的,因为它写起来灵活直观,而且与所熟悉的SQL的语法差不太多.条件查询.分页查询.连接查询.嵌套查询,写起来与SQL语法基本一致,唯一不同的就是把表名换成了 ...

  8. Elasticsearch文档查询

    简单数据集 到目前为止,已经了解了基本知识,现在我们尝试用更逼真的数据集,这儿已经准备好了一份虚构的JSON,关于客户银行账户信息的.每个文档的结构如下: { , , "firstname& ...

  9. Elasticsearch(GEO)空间检索查询

    Elasticsearch(GEO)空间检索查询python版本 1.Elasticsearch ES的强大就不用多说了,当你安装上插件,搭建好集群,你就拥有了一个搜索系统. 当然,ES的集群优化和查 ...

随机推荐

  1. 在Linux和Windows系统中输出目录结构

    前言 一直以来就想在写文章时,能以文本形式(而不是截图)附上项目的目录结构,今天终于知道怎么操作了,在这分享一下. Linux 首先说下Linux上输出目录结构的方法. yum安装tree 需要支持t ...

  2. RabbitMQ的基本介绍及与Spring整合

    一,场景回顾 ​ 最近做电商购物项目,在分布式中搜索服务,商品详情服务都是独立的模块.那么有一个问题就是: 商品的原始数据保存在数据库中,增删改查都在数据库中完成. 搜索服务数据来源是索引库,如果数据 ...

  3. Spring系列(四):Spring AOP详解

    一.AOP是什么 AOP(面向切面编程),可以说是一种编程思想,其中的Spring AOP和AspectJ都是现实了这种编程思想.相对OOP(面向过程编程)来说,提供了另外一种编程方式,对于OOP过程 ...

  4. 搭建nuget 服务器

    前言 搭建nuget服务器,这是上家公司进行类库管理的方式,其实优点很明显, 1.代码保密 2.代码重复利用效率高,这样不管任何项目只要知道nuget服务器地址就能直接调用 3.可进行版本任意切换提高 ...

  5. Java网络编程与NIO详解2:JAVA NIO 一步步构建I/O多路复用的请求模型

    微信公众号[黄小斜]作者是蚂蚁金服 JAVA 工程师,专注于 JAVA 后端技术栈:SpringBoot.SSM全家桶.MySQL.分布式.中间件.微服务,同时也懂点投资理财,坚持学习和写作,相信终身 ...

  6. 外观/门面模式(Facade)

    2015/4/28 外观/门面模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. #include <vector> ...

  7. redux 源码阅读

    目录 [目录结构] [utils] actionTypes.js isPlainObject.js warning.js [逻辑代码] index.js createStore.js compose. ...

  8. JAVA 异常汇总

    1  java.lang.ArithmeticException: / by zero 原因:当我们定义的被除数为整型时(short.int.long)会抛出此异常, 被除数为整型时不可为零.解决办法 ...

  9. python 35 多线程

    目录 多线程 1. 线程 2. 线程vs进程 3. 开启线程的两种方法. 4. 线程的特性 5. 线程的相关方法 6. join 阻塞 7. 守护线程 daemon 8. 互斥锁 多线程 1. 线程 ...

  10. java设计模式4.适配器模式、装饰器模式

    适配器模式 把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够工作. 1. 类的适配器模式 目标角色:期望的接口,对于类的适配器模式,此角色不可以是具体类 ...