Elasticsearch 复合查询——多字符串多字段查询

前言

有时我们在搜索电影的时候,包含了多个条件,比如主演是周星驰,打分8分以上,上映时间是1990年~2001年的,那么Elasticsearch又该如何帮我们做查询呢?这里我们可以用 bool 查询来实现需求。这种查询将多查询组合在一起,成为用户自己想要的 bool 查询。

bool 查询

一个 bool 查询,可以包含一个或多个查询语句进行组合。

有4种参数

  • must:文档必须匹配这些条件才能被包含进来。贡献算分。
  • should:文档选择性匹配,如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。贡献算分。
  • must_not:文档必须不匹配这些条件才能被包含进来。
  • filter:必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。不贡献算分。

基本语法

  • bool 里面的子查询继续嵌套 bool 查询
  • 子查询可以以任意顺序出现
  • 如果没有 must 语句,那么至少需要能够匹配其中的一条 should 语句。但如果存在至少一条 must 语句,则对 should 语句的匹配没有要求。
  • must等可以跟一个对象(“{}”),也可以跟数组(“[]”)
{
    "bool": {
        "must":     { "match": { "title": "how to make millions" }},
        "must_not": { "match": { "tag":   "spam" }},
        "should": [
            { "match": { "tag": "starred" }}
        ],
        "filter": {
          "bool": { 
              "must": [
                  { "range": { "date": { "gte": "2014-01-01" }}},
                  { "range": { "price": { "lte": 29.99 }}}
              ],
              "must_not": [
                  { "term": { "category": "ebooks" }}
              ]
          }
        }
    }
}

一个航班查询的例子,搜索去往美国的,当地天气是晴朗的,不从日本出发的,票价小于等于1000的航班。

GET kibana_sample_data_flights/_search
{
  "size": 5,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "DestCountry": "US"
          }
        },
        {
          "term": {
            "DestWeather": "Sunny"
          }
        }
      ],
      "must_not": {
        "term": {
            "OriginCountry": "JP"
          }
      }, 
      "filter": {
        "range": {
          "AvgTicketPrice": {
            "lte": 1000
          }
        }
      }
    }
  }
}

控制相关性

那么多个字段的查询,我们该如何影响其相关性的算分呢?

层级嵌套

同一层级下的字段是竞争关系,具有相同权重,可以通过嵌套改变对算分的影响。

GET animals/_search
{
  "query": {
    "bool": {
      "should": [
        {"term": {"text": "brown"}},
        {"term": {"text": "red"}},
        {"term": {"text": "quick"}},
        {"term": {"text": "dog"}}
      ]
    }
  }
}

GET animals/_search
{
  "query": {
    "bool": {
      "should": [
        {"term": {"text": "brown"}},
        {"term": {"text": "red"}},
        {"bool": {
            "should": [
                {"term": {"text": "quick"}},
                {"term": {"text": "dog"}}
            ]
          }
        }
      ]
    }
  }
}

boosting

控制字段的权重,可以使用boosting,默认值是1,可正可负。

  • 当boost>1时,打分的相关性相对提升
  • 当0
  • 当boost<0时,贡献负分

精简语法,可以在match里面指定boost,比如上面的航班信息DestCountry部分字段设置权重。

GET kibana_sample_data_flights/_search
{
  "explain": true,
  "size": 5,
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "DestCountry": {
              "query": "US",
              "boost": 10
            }
          }
        },
        {
          "term": {
            "DestWeather": "Sunny"
          }
        }
      ],
      "must_not": {
        "term": {
          "OriginCountry": "JP"
        }
      },
      "filter": {
        "range": {
          "AvgTicketPrice": {
            "lte": 1000
          }
        }
      }
    }
  }
}

完整boosting语法,positive正向作用,negative负向作用,negative_boost负向作用的权重,可以用来降级匹配的文档,不像“NOT”逻辑运算直接去除相关的文档

GET movies/_search
{
  //"explain": true, 
  "query": {
    "boosting": {
      "positive": {
        "term": {
          "title": {
            "value": "beautiful"
          }
        }
      },
      "negative": {
        "term": {
          "title": {
            "value": "mind"
          }
        }
      },
      "negative_boost": 0.2
    }
  }
}

constant_score 查询

尽管没有 bool 查询使用这么频繁,constant_score 查询也是我们工具箱里有用的查询工具。它将一个不变的常量评分应用于所有匹配的文档。它被经常用于你只需要执行一个 filter 而没有其它查询(例如,评分查询)的情况下。

GET movies/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "title": "beautiful"
        }
      }
    }
  }
}

参考资料

  • https://www.elastic.co/guide/cn/elasticsearch/guide/current/combining-queries-together.html
  • Elasticsearch核心技术与实战(阮一鸣--极客时间)

你可能感兴趣的:(Elasticsearch 复合查询——多字符串多字段查询)