elasticsearch高亮之highlight原理

無風聽海發表於2022-03-17

一、highlight簡介

highlight是提升使用者體驗的重要手段,搜尋引擎通過高亮突出命中關鍵字等方式,方便使用者通過關鍵字周圍的資訊快速的確認是否是自己希望的結果;

highlight功能通常包含以下三個主要的處理過程
1.將欄位文字拆分為小的片段;
2.找出最相關的片段;
3.高亮查詢關鍵字;

二、elasticsearch的highlight功能

elasticsearch提供了專門的高亮請求引數highlight,返回的記過中也會包含對應的高亮資訊;

在查詢語句中,我們要求對text欄位進行高亮處理;

GET /twitter/_search
{
  "query": {
    "match": {
      "text": "Another"
    }
  },
  "highlight": {
    "fields": {
      "text": {}
    }
  }
}

elasticsearch預設使用em對命中關鍵字進行包裹處理;

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.6931472,
    "hits" : [
      {
        "_index" : "twitter",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.6931472,
        "_source" : {
          "fullname" : "Jane Doe",
          "text" : "Another twitter test ..."
        },
        "highlight" : {
          "text" : [
            "<em>Another</em> twitter test ..."
          ]
        }
      }
    ]
  }
}

高亮處理需要使用原始的欄位值文字,所以elasticsearch需要儲存欄位的值,我們可以在欄位的mapping中設定store為true,否則只能從_source欄位中load對應欄位值;

三、elasticsearch提供的三種highlighter

elasticsearch提供了以下三種highlighter

Unified highlighter

這個unified highlighter是elasticsearch的預設highlighter,其使用的是Lucene Unified Highlighter,它會將文字分割為句子片段,然後使用BM25演算法計算每個句子片段的相似性得分;改highlighter支援phrase、fuzzy、prefix等查詢的高亮處理;

Plain highlighter

這個plain Highlighter使用的是標準的lucene Highlighter,其通過關鍵字的重要性及關鍵字的位置資訊,嘗試儘量的體現查詢的匹配邏輯;

為了更加準確的體現查詢的邏輯,Plain Highlighter需要針對具體的查詢和命中文件的每個欄位進行實時的計算,其會在記憶體中建立一個小型的index,然後通過查詢計劃重新執行一遍查詢,從而獲得高亮需要使用底層的匹配資訊,所以其比較適合小型的欄位;

Fast vector highlighter

這個fvh Highlighter使用的是Lucene Fast Vector Highlighter,其基於term_vector的資料結構,需要在mapping中將相應的欄位設定為with_positions_offsets;其比較適合對大文字欄位進行高亮處理;

四、Highlighter的高亮處理過程

Highlighter的主要工作就是通過傳入的查詢和命中的文件,找到能夠最好反應匹配相關性的高亮片段;其主要需要完成以下三個工作;

1.將文字查分為小的高亮片段
本階段主要將欄位值文字拆分為小的高亮片段,三種Highlighter的處理過程如下

Plain Highlighter首先使用欄位對應的analyzer對文字進行分詞處理,然後通過得到的每個分詞的起止字元位置,依次擷取fragment_size的文字段;由於根據固定的片段長度拆分,得到的片段效果往往很不理想;

Unified和fvh Highlighter都通過Java的BreakIterator進行拆分高亮片段,配合fragment_size可以得到比較完整的句子;

2.找到最相關的高亮片段;

本階段主要通過實際命中記錄的查詢關鍵字,對得到的高亮片段進行打分,從而找到跟查詢最相關的高亮片段;

要計算高亮片段的匹配情況,有兩種主要的方式

  1. 高亮處理的時候實時計算匹配情況,這樣就需要針對每個高亮片段建立臨時索引,並執行查詢語句來獲取匹配資訊;
  2. index的時候進行相關分詞起止字元的統計資訊處理和儲存;
  • postings list,在欄位mapping的時候,可以通過index_options來控制記錄到倒排索引中的分詞統計資訊,通過設定offsets可以儲存記錄分詞的起止資訊;
  • term vector,elasticsearch提供的term_vector也記錄了分詞過程中產生的分詞的起止資訊,也是在欄位mapping的時候進行設定,需要設定為with_positions_offsets;

三種Highlighter的處理過程如下

Plain Highlighter首先會利用高亮片段生成的分詞在記憶體中建立一個index,並通過lucene查詢計劃執行原始的查詢,然後通過命中資訊獲得匹配的分詞,通過計算高亮片段的包含的不同查詢分詞的數量計算相關性得分;這裡直接使用查詢分詞的boost(預設值)進行計算;

fvh Highlighter直接利用index的時候建立的term vector來得到高亮片段匹配的查詢分詞,其對高亮片段的評分演算法跟Plain Highlighter類似,只不過這裡會將命中的所有查詢分詞(包括重複的查詢分詞)計算在內;

unified Highlighter會嘗試優先使用term vectors,index中的postings list,否則只能跟plain Highlighter相同的方式進行實時計算;其使用BM25演算法計算高亮片段的相似度;

3.Highlight高亮片段;

本階段主要進行輸出前的編碼和格式化,最後使用pre-tags、post-tags來包裹高亮片段中的查詢關鍵字;

相關文章