Elasticsearch(7) --- 复合查询

Elasticsearch(7) ---复合查询

复合查询有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)

原文地址:https://www.cnblogs.com/qdhxhz/p/11529107.html

时间: 2024-11-05 18:43:15

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

ElasticSearch结构化查询

ElasticSearch结构化查询 Elasticsearch 提供了丰富的查询过滤语句,而有一些是我们较常用到的. 现在我们快速的介绍一下 这些最常用到的查询过滤语句. term 过滤 term主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed的字符串(未经分析的文本数据类型): { "term": { "age": 26 }} { "term": { "date": "2014-09-0

第三百六十五节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的查询

第三百六十五节,Python分布式爬虫打造搜索引擎Scrapy精讲-elasticsearch(搜索引擎)的查询 elasticsearch(搜索引擎)的查询 elasticsearch是功能非常强大的搜索引擎,使用它的目的就是为了快速的查询到需要的数据 查询分类: 基本查询:使用elasticsearch内置的查询条件进行查询 组合查询:把多个查询条件组合在一起进行复合查询 过滤:查询同时,通过filter条件在不影响打分的情况下筛选数据

Elasticsearch 常用基本查询

安装启动很简单,参考官网步骤:https://www.elastic.co/downloads/elasticsearch 为了介绍Elasticsearch中的不同查询类型,我们将对带有下列字段的文档进行搜索:title(标题),authors(作者),summary(摘要),release date(发布时间)以及number of reviews(评论数量),首先,让我们创建一个新的索引,并通过bulk API查询文档: 为了展示Elasticsearch中不同查询的用法,首先在Elast

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

HQL查询方式 这一种我最常用,也是最喜欢用的,因为它写起来灵活直观,而且与所熟悉的SQL的语法差不太多.条件查询.分页查询.连接查询.嵌套查询,写起来与SQL语法基本一致,唯一不同的就是把表名换成了类或者对象.其它的,包括一些查询函数(count(),sum()等).查询条件的设定等,全都跟SQL语法一样. 示例: Session session = SessionFactory.getCurrentSession(); User user = null; Transaction ts = s

thinkphp 区间查询 组合查询 复合查询 动态查询 SQL查询

区间查询 默认使用AND 在最后面元素加上OR  SELECT * FROM `weibo_user` WHERE ( `id` > 1 OR `id` < 3 ) $map['id']=array(   array('gt',1),   array('lt',3),     'OR' ); 组合查询  SELECT * FROM `weibo_user` WHERE `id` = 1 OR ( username = "bnbbs" AND email like "

grails的criteria实现复合查询并实现结果分页

def search = {         if(!params.max) params.max = 10         if(!params.offset) params.offset = 0         def searchClosure =  {             if(params.categoryName) {                 category{                     eq('categoryName', params.categoryN

利用kibana插件对Elasticsearch进行bool查询

#bool查询#老版本的filtered查询已经被bool代替#用 bool包括 must should must_not filter来完成 ,格式如下:#bool:{#  "filter":[],#  "must":[],#  "should":[],#  "must_not"[],#}#must 数组内的所有查询都必须满足#should 数组内只需要满足一个#must_not 一个都不能满足 #建立测试数据 POST l

随便说说Spring Data JPA(包含分页,复合查询)

最近没事做,闲着也是闲着,随便写写,自己说说,不提供参考价值. Spring Data JPA是Spring Data家族的一部分,可以轻松实现基于JPA的存储库. 此模块处理对基于JPA的数据访问层的增强支持. 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易. 在相当长的一段时间内,实现应用程序的数据访问层一直很麻烦. 必须编写太多样板代码来执行简单查询以及执行分页和审计. Spring Data JPA旨在通过减少实际需要的工作量来显著改善数据访问层的实现. 作为开发人员,您

Elasticsearch (DSL 布尔查询 过滤器 排序 高亮显示

es 可以组合查询 must:查询必须匹配搜素条件 比如数据库中的and should :查询 至少 满足条件 比如数据库中的or must_not: 不匹配查询条件,一个都不要满足 must must_not should 至少要包含一个条件 复合查询 原文地址:https://www.cnblogs.com/loujiang/p/12701596.html