1. 程式人生 > >Elasticsearch(八)搜尋優化

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
                }
            }
        }
    }
}