【Elastic Engineering】Elasticsearch:如何在搜索中实现 should_not 过滤器

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: Elasticsearch:如何在搜索中实现 should_not 过滤器

作者:刘晓国


Elasticsearch 中,我们可以使用 bool query 来说实现一种组合的查询。它可以具有如下的一种形式的搜索:

POST _search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user.id" : "kimchy" }
      },
      "filter": {
        "term" : { "tags" : "production" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 20 }
        }
      },
      "should" : [
        { "term" : { "tags" : "env1" } },
        { "term" : { "tags" : "deployed" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

在上面,我看到了 must 和 must_not 这样的组合,他们表示必须满足以及禁止满足的意思。我们也同时看到了 should 这个 clause,它表示如果满足就可以增加分数,但是我们看到没有 should_not 这样的表达方法。在我们的实际的搜索中这个其实也是蛮有用的,比如我想对某些不满足一定条件的查询进行加分。


在今天的文章中,我们用一个例子来展示如何实现 shoud_not 这样的查询。


我们首先以我们之前的用过的数据来进行展示:

POST _bulk
{ "index" : { "_index" : "twitter", "_id": 1} }
{"user":"双榆树-张三","message":"今儿天气不错啊,出去转转去","uid":2,"age":20,"city":"北京","province":"北京","country":"中国","address":"中国北京市海淀区","location":{"lat":"39.970718","lon":"116.325747"}}
{ "index" : { "_index" : "twitter", "_id": 2 }}
{"user":"东城区-老刘","message":"出发,下一站云南!","uid":3,"age":30,"city":"北京","province":"北京","country":"中国","address":"中国北京市东城区台基厂三条3号","location":{"lat":"39.904313","lon":"116.412754"}}
{ "index" : { "_index" : "twitter", "_id": 3} }
{"user":"东城区-李四","message":"happy birthday!","uid":4,"age":30,"city":"北京","province":"北京","country":"中国","address":"中国北京市东城区","location":{"lat":"39.893801","lon":"116.408986"}}
{ "index" : { "_index" : "twitter", "_id": 4} }
{"user":"朝阳区-老贾","message":"123,gogogo","uid":5,"age":35,"city":"北京","province":"北京","country":"中国","address":"中国北京市朝阳区建国门","location":{"lat":"39.718256","lon":"116.367910"}}
{ "index" : { "_index" : "twitter", "_id": 5} }
{"user":"朝阳区-老王","message":"Happy BirthDay My Friend!","uid":6,"age":50,"city":"北京","province":"北京","country":"中国","address":"中国北京市朝阳区国贸","location":{"lat":"39.918256","lon":"116.467910"}}
{ "index" : { "_index" : "twitter", "_id": 6} }
{"user":"虹桥-老吴","message":"好友来了都今天我生日,好友来了,什么 birthday happy 就成!","uid":7,"age":90,"city":"上海","province":"上海","country":"中国","address":"中国上海市闵行区","location":{"lat":"31.175927","lon":"121.383328"}}

打入上面的 _bulk 指令,我们就创建了一个叫做 twitter 的索引。


我们首先来测试如下的搜索:

GET twitter/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "age": {
              "gte": 40
            }
          }
        }
      ],
      "should": [
        {
          "match": {
            "city": "上海"
          }
        }
      ]
    }
  }
}

上面的搜索表示的意思是:搜索出年龄大于 40 岁的文档,而且来自上海的文档的排名靠前。搜索的结果就是:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 2.5404449,
    "hits" : [
      {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 2.5404449,
        "_source" : {
          "user" : "虹桥-老吴",
          "message" : "好友来了都今天我生日,好友来了,什么 birthday happy 就成!",
          "uid" : 7,
          "age" : 90,
          "city" : "上海",
          "province" : "上海",
          "country" : "中国",
          "address" : "中国上海市闵行区",
          "location" : {
            "lat" : "31.175927",
            "lon" : "121.383328"
          }
        }
      },
      {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "user" : "朝阳区-老王",
          "message" : "Happy BirthDay My Friend!",
          "uid" : 6,
          "age" : 50,
          "city" : "北京",
          "province" : "北京",
          "country" : "中国",
          "address" : "中国北京市朝阳区国贸",
          "location" : {
            "lat" : "39.918256",
            "lon" : "116.467910"
          }
        }
      }
    ]
  }
}

从上面的搜索的结果,我们可以看出来 _id 为 6 的来自上海的文档排名靠前。


假如现在我们的问题变为:我们想搜索年龄大于 49 岁,但是不来自上海的排名得分靠前,我们该如何实现这个目的呢?按照这个要求,我们实现如下的 should_not 方法:

GET twitter/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "age": {
              "gte": 40
            }
          }
        }
      ],
      "should": [
        {
          "bool": {
            "must_not": [
              {
                "match": {
                  "city": "上海"
                }
              }
            ]
          }
        }
      ]
    }
  }
}

请注意上面的 should 部分的写法。它使用了另外一个 bool query 来表达一个来自非上海的查询。上面的查询的结果是:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "user" : "朝阳区-老王",
          "message" : "Happy BirthDay My Friend!",
          "uid" : 6,
          "age" : 50,
          "city" : "北京",
          "province" : "北京",
          "country" : "中国",
          "address" : "中国北京市朝阳区国贸",
          "location" : {
            "lat" : "39.918256",
            "lon" : "116.467910"
          }
        }
      },
      {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "6",
        "_score" : 1.0,
        "_source" : {
          "user" : "虹桥-老吴",
          "message" : "好友来了都今天我生日,好友来了,什么 birthday happy 就成!",
          "uid" : 7,
          "age" : 90,
          "city" : "上海",
          "province" : "上海",
          "country" : "中国",
          "address" : "中国上海市闵行区",
          "location" : {
            "lat" : "31.175927",
            "lon" : "121.383328"
          }
        }
      }
    ]
  }
}

显然这次的结果,我们并没有改变所返回的数据的数量,但是我们确实改变了返回数据的次序,虽然在本例子中分数还是 1.0(这是因为 must_not 不影响分数)。在这次的查询中,我们可以看到来自北京的文档的排名提前了。


相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
27天前
|
存储 人工智能 自然语言处理
阿里云Elasticsearch AI场景语义搜索最佳实践
本文介绍了如何使用阿里云Elasticsearch结合搜索开发工作台搭建AI语义搜索。
16614 67
因为一个问题、我新学了一门技术 ElasticSearch 分布式搜索
这篇文章讲述了作者因为一个检索问题而学习了ElasticSearch技术,并分享了排查和解决ElasticSearch检索结果与页面展示不符的过程。
因为一个问题、我新学了一门技术 ElasticSearch 分布式搜索
|
1天前
|
SQL JSON 大数据
ElasticSearch的简单介绍与使用【进阶检索】 实时搜索 | 分布式搜索 | 全文搜索 | 大数据处理 | 搜索过滤 | 搜索排序
这篇文章是Elasticsearch的进阶使用指南,涵盖了Search API的两种检索方式、Query DSL的基本语法和多种查询示例,包括全文检索、短语匹配、多字段匹配、复合查询、结果过滤、聚合操作以及Mapping的概念和操作,还讨论了Elasticsearch 7.x和8.x版本中type概念的变更和数据迁移的方法。
ElasticSearch的简单介绍与使用【进阶检索】 实时搜索 | 分布式搜索 | 全文搜索 | 大数据处理 | 搜索过滤 | 搜索排序
|
20天前
|
数据采集 人工智能 安全
阿里云Elasticsearch 企业级AI搜索方案发布
本文从AI搜索落地的挑战、阿里云在RAG场景的实践、效果提升三个方面,深度解读阿里云Elasticsearch 企业级AI搜索方案。
181 8
|
18天前
|
数据采集 人工智能 自然语言处理
阿里云Elasticsearch AI语义搜索:解锁未来搜索新纪元,精准洞察数据背后的故事!
【8月更文挑战第2天】阿里云Elasticsearch AI场景语义搜索最佳实践
82 5
|
1月前
|
运维 监控 Java
在大数据场景下,Elasticsearch作为分布式搜索与分析引擎,因其扩展性和易用性成为全文检索首选。
【7月更文挑战第1天】在大数据场景下,Elasticsearch作为分布式搜索与分析引擎,因其扩展性和易用性成为全文检索首选。本文讲解如何在Java中集成Elasticsearch,包括安装配置、使用RestHighLevelClient连接、创建索引和文档操作,以及全文检索查询。此外,还涉及高级查询、性能优化和故障排查,帮助开发者高效处理非结构化数据。
41 0
|
2月前
|
缓存 监控 索引
Elasticsearch中的post_filter后置过滤器技术
Elasticsearch中的post_filter后置过滤器技术
|
2月前
|
缓存 自然语言处理 监控
elasticsearch过滤器filter:原理及使用
elasticsearch过滤器filter:原理及使用
|
2月前
|
缓存 Java API
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
在生产环境中部署Elasticsearch:最佳实践和故障排除技巧——聚合与搜索(三)
|
2月前
|
存储 自然语言处理 NoSQL
D7 Elasticsearch-Mongodb(搜索记录)
D7 Elasticsearch-Mongodb(搜索记录)
20 0

热门文章

最新文章

相关产品

  • 检索分析服务 Elasticsearch版