Juconcurrent 学而不思则罔,思而不学则殆。

Elasticsearch学习笔记(16) - Query & Filter


前言

Elasticsearch有Query和Filter两种不同的Context。

  1. Query Context,会进行相关性算分
  2. Filter Context,不会进行相关性算分,这种方式可利用缓存来提高检索的速度和性能。

Bool查询

Bool查询是一种复合查询,是一个或多个查询子句的组合。Bool查询总共包含4种子句。其中,两种会影响算分,另外两种不影响算分。

子句 类型 影响结果
must Query Context 必须匹配。贡献算分
shoud Query Context 选择性匹配,至少满足一条。贡献算分
must_not Filter Context 过滤子句,必须不能匹配,但不贡献算分
filter Filter Context 过滤子句,必须匹配,但不贡献算分

Bool查询语法有以下特点

  1. 子查询可以任意顺序出现
  2. 可以嵌套多个查询,包括bool查询
  3. 如果bool查询中没有must条件,should中必须至少满足一条才会返回结果。
POST /products/_bulk
{ "index": { "_id": 1 }}
{ "price" : 10,"avaliable":true,"date":"2018-01-01", "productID" : "XHDK-A-1293-#fJ3" }
{ "index": { "_id": 2 }}
{ "price" : 20,"avaliable":true,"date":"2019-01-01", "productID" : "KDKE-B-9947-#kL5" }
{ "index": { "_id": 3 }}
{ "price" : 30,"avaliable":true, "productID" : "JODL-X-1937-#pV7" }
{ "index": { "_id": 4 }}
{ "price" : 30,"avaliable":false, "productID" : "QQPX-R-3956-#aD8" }

# 基本语法
POST /products/_search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "price" : "30" }
      },
      "filter": {
        "term" : { "avaliable" : "true" }
      },
      "must_not" : {
        "range" : {
          "price" : { "lte" : 10 }
        }
      },
      "should" : [
        { "term" : { "productID.keyword" : "JODL-X-1937-#pV7" } },
        { "term" : { "productID.keyword" : "XHDK-A-1293-#fJ3" } }
      ],
      "minimum_should_match" :1
    }
  }
}

数组的精确匹配

在前面章节,我们在查询数组的时候遇到了一个问题,即:默认的查询行为是包含就返回,而不是相等。那么,有没有一种方式可以实现相等的这种场景呢?

答案是:有的。解决思路就是增加一个count字段用于标识数组内元素的个数,然后通过Bool查询来实现。

# 改变数据模型,增加字段。解决数组包含而不是精确匹配的问题
POST /newmovies/_bulk
{ "index": { "_id": 1 }}
{ "title" : "Father of the Bridge Part II","year":1995, "genre":"Comedy","genre_count":1 }
{ "index": { "_id": 2 }}
{ "title" : "Dave","year":1993,"genre":["Comedy","Romance"],"genre_count":2 }

# Query。must,有算分
POST /newmovies/_search
{
  "query": {
    "bool": {
      "must": [
        {"term": {"genre.keyword": {"value": "Comedy"}}},
        {"term": {"genre_count": {"value": 1}}}
      ]
    }
  }
}

# Filter。不参与算分,结果的score是0
POST /newmovies/_search
{
  "query": {
    "bool": {
      "filter": [
        {"term": {"genre.keyword": {"value": "Comedy"}}},
        {"term": {"genre_count": {"value": 1}}}
        ]
    }
  }
}

特别注意:Filter的两种方式,返回的_score都是0,而Query的两种却不是0。

Bool嵌套查询

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

查询语句结构的影响

查询语句的结构,也会对相关度算分产生影响。

  1. 同一层级下的竞争字段,具有相同的权重
  2. 通过嵌套bool查询,可以改变对算分的影响
POST /animals/_search
{
  "query": {
    "bool": {
      "should": [
        { "term": { "text": "brown" }},
        { "term": { "text": "red" }},
        { "term": { "text": "quick"   }},
        { "term": { "text": "dog"   }}
      ]
    }
  }
}

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

Boosting

# 删除并创建索引
DELETE news
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" }

# 默认的查询,3的记录排在第一
POST news/_search
{
  "query": {
    "bool": {
      "must": {
        "match":{"content":"apple"}
      }
    }
  }
}

# must_not的方式,将3的记录强制排除掉
POST news/_search
{
  "query": {
    "bool": {
      "must": {
        "match":{"content":"apple"}
      },
      "must_not": {
        "match":{"content":"pie"}
      }
    }
  }
}

# 通过Boosting的方式,将3的记录也纳入结果集,只是排名会靠后。
# positive表示正向激励
# negative表示负向激励,negative_boost表示激励的比重
POST news/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "content": "apple"
        }
      },
      "negative": {
        "match": {
          "content": "pie"
        }
      },
      "negative_boost": 0.5
    }
  }
}

总结

  1. 我们简单地讨论了query contextfilter context,了解了他们的差异。
  2. 我们还学习了bool查询,它可以包含多个子句。
  3. 查询结构的调整会对相关性算分产生影响。
  4. 我们再次通过一个例子学习了boosting,可使用Boosting和Boosting Query的方式对查询的结果进行更精确地控制。

Content