Elasticsearch系列(12)Query之復合查詢

1. 前言

Elasticsearch提供了一個完整的基于JSON的查詢DSL(領(lǐng)域特定語言)來定義查詢。可以將查詢DSL看作查詢的AST(抽象語法樹),它由兩種類型的子句(clauses)組成:
(1)葉查詢子句(Leaf query clauses):特定字段中查找特定值,例如匹配(match)、詞條(term)或范圍(range)查詢。這些查詢可以單獨查詢使用。
(2)復合查詢子句(Compound query clauses):包裝其他葉查詢或復合查詢,并使用邏輯方式來組合多個查詢(如bool或dis_max查詢),或用于改變它們的行為(如constant_score查詢)。

查詢子句的行為取決于它們是在查詢上下文中使用還是在篩選上下文中使用。

允許昂貴查詢

某些類型的查詢通常執(zhí)行緩慢,這是因為它們的實現(xiàn)方式會影響集群的穩(wěn)定性,這些查詢分類如下:

  • 需要做線性掃描來識別匹配的查詢:
    (1)腳本查詢(script查詢)
  • 具有高前期成本的查詢:
    (1)模糊查詢(通配符字段除外)
    (2)正則表達式查詢(通配符字段除外)
    (3)前綴查詢(通配符字段或沒有index_prefixes的字段除外)
    (4)通配符查詢(通配符字段除外)
    (5)部分范圍查詢
  • join查詢
  • 對于每個文檔可能有較高成本的查詢:
    (1)腳本分數(shù)查詢
    (2)過濾查詢(percolate查詢)

可以通過設置參數(shù)allow_expensive_queries為false(默認為true)來阻止此類查詢的執(zhí)行。

2. 查詢和過濾器上下文

相關(guān)性得分

默認情況下,Elasticsearch根據(jù)相關(guān)性評分對匹配的搜索結(jié)果進行排序,相關(guān)性評分衡量每個文檔與查詢的匹配程度。相關(guān)性得分是一個正浮點數(shù),在搜索API的_score元數(shù)據(jù)字段中返回。_score字段值越高,文檔越相關(guān)。

查詢上下文

在查詢(query)上下文中,一個查詢子句回答了問題“這個文檔與這個查詢子句匹配得有多好?”,除了決定文檔是否匹配之外,查詢子句還會計算相關(guān)性分數(shù)保存在_score元數(shù)據(jù)字段中。

過濾器上下文

在過濾器(filter)上下文中,查詢子句回答問題“這個文檔與這個查詢子句匹配嗎?”,答案是簡單的“是”或“不是”—沒有計算分數(shù)。過濾器上下文主要用于過濾結(jié)構(gòu)化數(shù)據(jù)。

查詢和過濾器例子
PUT /my_index_01
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "store": true
      },
      "create_date": { "type": "date" },
      "id": {  "type": "keyword" },
      "user": {
        "properties": {
          "name": { "type": "keyword" },
          "age": { "type": "integer" }
        }
      },
      "status": {  "type": "keyword" }
    }
  }
}
POST /my_index_01/_doc/1
{"id":"00000001", "content":"Quick Brown Fox", "create_date": "2015-01-01", "user.name":"james", "user.age": 35, "status": "enable" }
POST /my_index_01/_doc/2
{"id":"00000002", "content":"Quick White Fox", "create_date": "2015-01-02", "user.name":"fake", "user.age": 26, "status": "disable" }
GET my_index_01/_search
{
    "query": {  //1
      "bool": {   //2
        "must":[
          {"match":{"content":"Fox"}},
          {"match":{"user.name":"james"}}
        ],
        "filter":[  //3
          {"term":{"status":"enable"}},
          {"range":{"create_date": {"gte":"2014-01-01"}}}
        ]
      }
  }
}

注釋1:query參數(shù)表示查詢上下文
注釋2:在查詢上下文中使用bool和兩個match子句,這意味著它們會對每個文檔的匹配程度進行評分。
注釋3:filter參數(shù)表示過濾器上下文,在過濾器上下文中使用term和range子句,它們將過濾掉不匹配的文檔,但不會影響匹配文檔的得分。

注意:在查詢上下文中為查詢計算的分數(shù)表示為單精度浮點數(shù);它們只有24位的精度。超過精度將被轉(zhuǎn)換為浮點數(shù)進行分數(shù)計算,從而丟失精度。

3. 復合查詢

首先創(chuàng)建索引my_index_01,并索引數(shù)據(jù):

PUT /my_index_01
{
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "store": true
      },
      "create_date": { "type": "date" },
      "id": {  "type": "keyword" },
      "user": {
        "properties": {
          "name": { "type": "keyword" },
          "age": { "type": "integer" }
        }
      },
      "status": {  "type": "keyword" }
    }
  }
}
POST /my_index_01/_doc/1
{"id":"00000001", "content":"Quick Brown Fox", "create_date": "2015-01-01", "user.name":"james jordan", "user.age": 35, "status": "enable" }
POST /my_index_01/_doc/2
{"id":"00000002", "content":"Quick White Fox", "create_date": "2015-01-02", "user.name":"fake li", "user.age": 26, "status": "disable" }

3.1 bool查詢

用于組合多個葉子或復合查詢子句的布爾值查詢,使用一個或多個布爾子句構(gòu)建的,每個子句都有一個有類型的,如must、should、must_not或filter子句。

查詢參數(shù)
  • must:子句(查詢)必須出現(xiàn)在匹配的文檔中,對文檔分數(shù)產(chǎn)生影響。
  • filter:子句(查詢)必須出現(xiàn)在匹配的文檔中,filter子句在Filter上下文中執(zhí)行,這意味著評分被忽略,如果只有該類型子句,那么文檔評分為0。
  • should:子句(查詢)應該出現(xiàn)在匹配的文檔中,對文檔分數(shù)產(chǎn)生影響。must和should子句的分數(shù)組合在一起,匹配的子句越多文檔分數(shù)越高。
  • must_no:子句(查詢)不能出現(xiàn)在匹配的文檔中,must_no子句在過濾器上下文中執(zhí)行,這意味著評分被忽略,如果只有該類型子句,那么文檔評分為0。

查詢示例如下:

POST my_index_01/_search
{
  "query": {
    "bool" : {
      "must" : {
        "term" : { "user.name" : "james jordan" }
      },
      "filter": {
        "term" : { "status" : "enable" }
      },
      "must_not" : {
        "range" : {
          "age" : { "gte" : 10, "lte" : 30 }
        }
      },
      "should" : [
        { "term" : { "id" : "00000001" } },
        { "term" : { "id" : "00000002" } }
      ],
      "minimum_should_match" : 1,
      "boost" : 1.0
    }
  }
}

使用minimum_should_match參數(shù)來指定返回的文檔必須匹配的should子句的數(shù)量或百分比。如果布爾查詢包含should子句,并且沒有must或filter子句,則默認值為1,否則默認值為0。

命名查詢

每個查詢可在其頂級定義一個_name??梢允褂妹樵儊砀櫰ヅ浞祷氐奈臋n。如果使用了命名查詢,則響應對于每次命中都包含一個matched_queries屬性。示例如下:

POST my_index_01/_search
{
  "query": {
    "bool": {
      "should": {
        "match": {
          "user.name": { "query": "james jordan", "_name": "custom_value" }
        }
      }
    }
  }
}

返回結(jié)果如下

3.2 boosting查詢

boosting查詢包含兩部分:positive查詢和negative查詢。

查詢參數(shù)
  • positive:(必需的,object類型)任何返回的文檔都必須匹配此查詢。
  • negative:(必需的,object類型)用來降低匹配文檔的相關(guān)性得分的查詢,不過濾匹配的文檔。
    如果返回的文檔匹配positive查詢和negative查詢,boosting查詢將計算該文檔的最終相關(guān)性得分,如下所示:
    (1)從正查詢中取原始的相關(guān)性分數(shù)。
    (2)將分數(shù)乘以negative_boost參數(shù)值。
  • negative_boost:(必需的、float類型)0到1.0之間的浮點數(shù),用于降低與negative查詢匹配的文檔的相關(guān)性得分。

示例如下:

POST my_index_01/_search
{
  "query": {
    "boosting": {
      "positive": {
        "match": {
          "content": "Fox"
        }
      },
      "negative": {
        "match": {
          "content": "White"
        }
      },
      "negative_boost": 10
    }
  }
}

返回結(jié)果片段如下:

3.3 constant_score查詢

包裝一個過濾器(filter)查詢,并返回每個文檔的相關(guān)性分數(shù)為常量boost參數(shù)值。

查詢參數(shù)
  • filter:(必需的,object類型)任何返回的文檔都必須匹配此查詢。過濾查詢不計算相關(guān)性分數(shù)。為了提高性能,Elasticsearch會自動緩存經(jīng)常使用的過濾查詢。
  • boost:(可選的、float類型)用來設置返回文檔的常量相關(guān)性分數(shù),默認為1.0。

示例如下:

POST my_index_01/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "match": {  "content": "Fox" }
      },
      "boost": 1.2
    }
  }
}

3.4 dis_max查詢

dis_max查詢包含一個或多個查詢子句,如果返回的文檔匹配了多個查詢子句,dis_max查詢將找到匹配子句中最高相關(guān)性分數(shù), 將其分配給文檔,而且為任何其他匹配子查詢加上一個離線增量。

查詢參數(shù)
  • queries:(必需的,object數(shù)組)包含一個或多個查詢子句。返回的文檔必須匹配一個或多個這些查詢。如果一個文檔匹配多個查詢,Elasticsearch使用最高的相關(guān)性得分。
  • tie_breaker:(可選的,float類型)0到1.0之間的浮點數(shù),用于增加匹配查詢子句的文檔的相關(guān)性得分。默認為0.0。此值越大,文檔的相關(guān)性得分越高。如果一個文檔匹配多個子句,dis_max查詢將計算該文檔的相關(guān)性得分,如下所示:
    (1)從得分最高的匹配子句中取相關(guān)度分數(shù)。
    (2)將來自任何其他匹配子句的分數(shù)乘以tie_breaker值。
    (3)將最高的分數(shù)與相乘的分數(shù)相加得到最終文檔的相關(guān)性得分。
    如果tie_breaker值大于0.0,那么所有匹配的子句都被計算在內(nèi),但是得分最高的子句被計算的最多。

示例如下:

POST my_index_01/_search
{
  "query": {
     "dis_max": {
        "queries": [
          { "term" : { "user.name" : "fake li" } },
          { "term" : { "id" : "00000002" } }
        ],
        "tie_breaker": 0.5
      }
  }
}

返回結(jié)果片段如下:

"max_score" : 0.76246184,
"hits" : [
  {
    "_index" : "my_index_01",
    "_type" : "_doc",
    "_id" : "2",
    "_score" : 0.76246184,
    "_source" : {
      "id" : "00000002",
      "content" : "Quick White Fox",
      "create_date" : "2015-01-02",
      "user.name" : "fake li",
      "user.age" : 26,
      "status" : "disable"
    }
  }
]

3.5 function_score查詢

function_score查詢可以修改查詢返回的文檔相關(guān)性分數(shù),需要定義一個查詢和若干個函數(shù),用這些函數(shù)為查詢返回的每個文檔計算一個新分數(shù)。

示例如下:

POST my_index_01/_search
{
  "query": {
     "function_score": {
        "query": { "match_all": {} },
        "boost": "5", 
        "functions": [
          {
            "filter": { "match": { "content": "Brown" } },
            "random_score": {}, 
            "weight": 23
          },
          {
            "filter": { "match": { "content": "White" } },
            "weight": 42
          }
        ],
        "max_boost": 42,
        "score_mode": "max",
        "boost_mode": "multiply",
        "min_score": 30
    }
  }
}
  • 參數(shù)score_mode:每個文檔由定義的函數(shù)評分。參數(shù)score_mode指定計算的分數(shù)是如何組合的。
score_mode
參數(shù)值
參數(shù)說明
multiply 分數(shù)相乘(默認)
sum 分數(shù)之和
avg 分數(shù)平均
first 第一個函數(shù)的分數(shù)
max 最大分數(shù)值
min 最小分數(shù)值
  • 參數(shù)weight:每個函數(shù)的分數(shù)可以根據(jù)用戶定義的權(quán)重進行調(diào)整。權(quán)重可以在functions數(shù)組中為每個函數(shù)定義,并與各自函數(shù)計算的分數(shù)相乘。如果權(quán)重是在沒有任何其他函數(shù)聲明的情況下給出的,那么權(quán)重就充當一個函數(shù),它只是返回權(quán)重。在score_mode設置為avg的情況下,單個分數(shù)將通過加權(quán)平均合并。例如,如果兩個函數(shù)返回score 1和2,它們各自的權(quán)重為3和4,那么它們的得分將被合并為(1*3+2*4)/(3+4)。
  • 參數(shù)max_boost:通過設置max_boost參數(shù),可以限制新計算分數(shù)不超過某個限制。max_boost的默認值是FLT_MAX。
  • 參數(shù)boost_mode:通過設置boost_mode參數(shù),用來結(jié)合文檔的函數(shù)分數(shù)與查詢分數(shù)。
boost_mode
參數(shù)值
參數(shù)說明
multiply 函數(shù)分數(shù)與查詢分數(shù)相乘(默認)
replace 只使用函數(shù)分數(shù),忽略查詢分數(shù)
sum 函數(shù)分數(shù)與查詢分數(shù)之和
avg 函數(shù)分數(shù)與查詢分數(shù)平均
max 函數(shù)分數(shù)與查詢分數(shù)之間最大值
min 函數(shù)分數(shù)與查詢分數(shù)之間最小值
script_score

除了自定義函數(shù),還可以使用腳本函數(shù),使用script_score函數(shù)可以包裝另一個查詢,并使用腳本表達式從文檔中的其他數(shù)值字段值來定制它的評分。示例如下:

POST my_index_01/_search
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "script_score": {
        "script": {
          "source": "Math.log(2 + doc['user.age'].value)"
        }
      }
    }
  }
}

腳本支持參數(shù)形式,示例如下:

POST my_index_01/_search
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "script_score": {
        "script": {
          "params": {
            "a": 5,
            "b": 1.2
          },
          "source": "params.a / Math.pow(params.b, doc['user.age'].value)"
        }
      }
    }
  }
}
其他得分函數(shù)
  • 隨機函數(shù)(random_score):random_score生成從0到1(不包括1)均勻分布的分數(shù)。默認情況下,它使用內(nèi)部Lucene文檔id作為隨機性的來源。
  • 衰減函數(shù):衰減函數(shù)為文檔計算得分,該函數(shù)根據(jù)文檔的數(shù)值字段值與給定起點的距離衰減。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容