Elasticsearch(八)搜尋優化
Elasticsearch: 6.4.2
1. 理解欄位分析過程
一個常被問到的問題是,為什麼指定的文件沒有被搜尋到。很多情況下,這都歸因於對映的定義和分析例程的配置存在問題。針對分析過程的除錯,Elasticsearch提供了專用的REST API。
GET /_analyze
{
"analyzer": "standard", # 可以替換成自定義的analyzer
"text": "crime and publishment"
}
# 使用一個分詞器和兩個過濾器
GET _analyze
{
"tokenizer" : "keyword",
"filter" : [ "lowercase"],
"char_filter" : ["html_strip"],
"text" : "this is a <b>test</b>"
}
2. 解釋查詢
給出有關文件相關度得分計算的詳細資訊,以解釋為什麼會匹配成功。
# 針對特定文件的分析
GET /cars/doc/8/_explain?q=jeep
# 針對文字資訊的分析
GET _analyze
{
"tokenizer" : "standard",
"filter" : ["snowball"],
"text" : "detailed output",
"explain" : true,
"attributes" : ["keyword"]
}
3. 用加權查詢影響得分
Boost(權值):在計算得分過程中使用的附加權值,可在如下位置使用:
- 查詢:告訴搜尋引擎指定的查詢比其他查詢更重要
- 欄位:指定文件中某些欄位對使用者很重要
- 文件:某些文件很重要
3.1 在查詢中使用權值
例如:
# 欄位重要程度:from、to、subject
GET /emails/doc/_search
{
"query": {
"query_string": {
"fields": ["from^5", "to^3", "subject"],
"query" : "Bourne"
}
}
}
3.2 修改得分
constant_score
包裝另一個查詢子句,為每個文件返回得分等於boost值。
GET /cars/doc/_search
{
"query": {
"constant_score": {
"filter": {
"match": {
"name": "bmw jeep"
}
},
"boost": 1.2
}
}
}
Boosting查詢
Boosting查詢與Bool查詢中的NOT的不同:後者過濾掉滿足NOT查詢語句的文件,而前者仍然選擇不被期望的文件,只是講它們的得分降低。
GET /cars/doc/_search
{
"query": {
"boosting": {
"positive": {
"match_all": {}
},
"negative": {
"term": {
"name": {
"value": "jeep"
}
}
},
"negative_boost": 0.2
}
}
}
Function查詢
boost引數設定每個文件的得分,然後對於滿足functions引數中子查詢條件的文件根據boost_mode、boost、weight計算新得分;
當存在多個function且某個文件滿足多個function時該文件的得分為:先計算滿足各個function後的每個得分,然後由score_mode引數計算最終等分。其中score_mode取值:multiply、sum、avg、first、max、min。
GET /cars/doc/_search
{
"query": {
"function_score": {
"boost": 5,
"max_boost": 50,
"score_mode": "max",
"boost_mode": "multiply",
"query": {
"match_all": {}
},
"functions": [
{
"filter": {
"match": {"name": "jeep"}
},
"weight": 4
}
]
}
}
}
4. 具有相同含義的詞
4.1 同義詞(synonym)過濾器
基於陣列定義
PUT /test_index
{
"settings": {
"index" : {
"analysis" : {
"analyzer" : {
"synonym" : {
"tokenizer" : "standard",
"filter" : ["my_stop", "synonym"]
}
},
"filter" : {
"synonym" : {
"type" : "synonym",
"lenient": true,
"synonyms" : ["foo, bar => baz"]
}
}
}
}
}
}
基於檔案定義:檔案路徑是相對於Elasticsearch安裝目錄下config目錄的。
PUT /test_index
{
"settings": {
"index" : {
"analysis" : {
"analyzer" : {
"synonym" : {
"tokenizer" : "whitespace",
"filter" : ["synonym"]
}
},
"filter" : {
"synonym" : {
"type" : "synonym",
"synonyms_path" : "analysis/synonym.txt"
}
}
}
}
}
}
4.2 同義詞定義規則
預設使用Apache solr的同義詞方案。
同義詞顯式定義
i-pod, i pod => ipod,
sea biscuit, sea biscit => seabiscuit
同義詞等式定義
ipod, i-pod, i pod
foozball , foosball
universe , cosmos
lol, laughing out loud
擴充套件同義詞
如果同義詞過濾器中屬性expand=true,則所有同義詞被擴充套件為所有單詞全部等價的形式。
ipod, i-pod, i pod => ipod, i-pod, i pod
5. 跨度查詢
跨度是指在一個欄位中開始和結束的詞條位置。
span_term
GET /_search
{
"query": {
"span_term" : { "user" : "kimchy" }
}
}
span_multi
包裝一個term、range、prefix、wildcard、regexp或fuzzy查詢。
GET /_search
{
"query": {
"span_multi":{
"match":{
"prefix" : { "user" : { "value" : "ki" } }
}
}
}
}
span_first
只允許返回在欄位的前幾個位置上匹配查詢條件的文件。
# 查詢在user欄位前三個位置出現kimchy的文件
GET /_search
{
"query": {
"span_first" : {
"match" : {
"span_term" : { "user" : "kimchy" }
},
"end" : 3
}
}
}
span_near
可以在有多個其他跨度彼此接近時對文件進行搜尋,該查詢也是一個能將其他跨度查詢包裝起來的複合查詢。
# slop:控制在跨度之間允許的詞項的數量
# in_order: 限制匹配順序;true時按照查詢定義的順序匹配文件
# 該示例查詢message欄位包含world everyone的文件。
GET /_search
{
"query": {
"span_near" : {
"clauses" : [
{ "span_term" : { "message" : "world" } },
{ "span_term" : { "message" : "everyone" } }
],
"slop" : 0,
"in_order" : true
}
}
}
span_or
# 獲取在message欄位前兩個位置處有world或者離everyone不超過一個位置處含有world的文件。
GET /_search
{
"query": {
"span_near": {
"clauses": [
{
"span_first": {
"match": {
"span_term": {
"message": {
"value": "world"
}
}
},
"end": 2
}
},
{
"span_near": {
"clauses": [
{
"span_term": {
"message": {
"value": "world"
}
}
},
{
"span_term": {
"message": {
"value": "everyone"
}
}
}
],
"slop": 1,
"in_order": true
}
}
],
"slop": 0,
"in_order": true
}
}
}
span_not
include引數指定了哪個跨度查詢應該被匹配;exclude引數指定了不與include部分重疊的跨度查詢。
# 返回在message欄位中匹配了由breaks詞項構造的span_term查詢的所有文件,然後再定義一個匹配了world和everyone並且最大位置間距為1的跨度,當該跨度與第一個跨度查詢重疊時,排除掉所有重疊部分的文件。
GET /_search
{
"query": {
"span_not": {
"include": {
"span_term": {
"message": {
"value": "breaks"
}
}
},
"exclude": {
"span_near": {
"clauses": [
{
"span_term": {
"message": {
"value": "world"
}
}
},
{
"span_term": {
"message": {
"value": "everyone"
}
}
}
],
"slop": 1
}
}
}
}
}
span_containing
查詢內部有big和little兩個字查詢,僅返回big匹配的結果中包含little匹配結果的文件;從大到小包含
GET /_search
{
"query": {
"span_containing" : {
"little" : {
"span_term" : { "field1" : "foo" }
},
"big" : {
"span_near" : {
"clauses" : [
{ "span_term" : { "field1" : "bar" } },
{ "span_term" : { "field1" : "baz" } }
],
"slop" : 5,
"in_order" : true
}
}
}
}
}
span_within
與span_containing類似,從小到大包含。
GET /_search
{
"query": {
"span_within" : {
"little" : {
"span_term" : { "field1" : "foo" }
},
"big" : {
"span_near" : {
"clauses" : [
{ "span_term" : { "field1" : "bar" } },
{ "span_term" : { "field1" : "baz" } }
],
"slop" : 5,
"in_order" : true
}
}
}
}
}