Elasticsearch 向量搜尋

使用者bPEIr6發表於2022-04-16

Elasticsearch 向量搜尋

本文將會介紹 Elasticsearch 向量搜尋的兩種方式。

向量搜尋

提到向量搜尋,我想你一定想知道:

  1. 向量搜尋是什麼?
  2. 向量搜尋的應用場景有哪些?
  3. 向量搜尋與全文搜尋有何不同?

ES 的全文搜尋簡而言之就是將文字進行分詞,然後基於詞通過 BM25 演算法計算相關性得分,從而找到與搜尋語句相似的文字,其本質上是一種 term-based(基於詞)的搜尋。

全文搜尋的實際使用已經非常廣泛,核心技術也非常成熟。但是,除了文字內容之外,現實生活中還有非常多其它的資料形式,例如:圖片、音訊、視訊等等,我們能不能也對這些資料進行搜尋呢?

答案是 Yes !

隨著機器學習和人工智慧等技術的發展,萬物皆可 Embedding。換句話說就是,我們可以對文字、圖片、音訊、視訊等等一切資料通過 Embedding 相關技術將其轉換成特徵向量,而一旦向量有了,向量搜尋的需求隨之也越發強烈,向量搜尋的應用場景也變得一望無際、充滿想象力。

圖片來源 damo.alibaba.com/events/112

ES 向量搜尋說明

ES 向量搜尋目前有兩種方式:

  • script_score
  • _knn_search

script_score 精確搜尋

ES 7.6 版本對新增的欄位型別 dense_vector 確認了穩定性保證,這個欄位型別就是用來表示向量資料的。

資料建模示例:

PUT my-index
{
  "mappings": {
    "properties": {
      "my_vector": {
        "type": "dense_vector",
        "dims": 128
      },
      "my_text" : {
        "type" : "keyword"
      }
    }
  }
}

如上圖所示,我們在索引中建立了一個 dims 維度為 128 的向量資料欄位。

script_score 搜尋示例:

{
  "script_score": {
    "query": {"match_all": {}},
    "script": {
      "source": "cosineSimilarity(params.query_vector, 'my_vector') + 1.0",
      "params": {"query_vector": query_vector}
    }
  }
}

上圖所示的含義是使用 ES 7.3 版本之後內建的 cosineSimilarity 餘弦相似度函式計算向量之間的相似度得分。

需要注意的是,script_score 這種搜尋方式是先執行 query ,然後對匹配的文件再進行向量相似度算分,其隱含的含義是:

  • 資料建模時向量欄位可以與其它欄位型別一起使用,也就是支援混合查詢(先進行全文搜尋,再基於搜尋結果進行向量搜尋)。
  • script_score 是一種暴力計算,資料集越大,效能損耗就越大。

_knn_search 搜尋

由於 script_score 的效能問題,ES 在 8.0 版本引入了一種新的向量搜尋方法 _knn_search(目前處於試驗性功能)。

所謂的 _knn_search 其實就是一種 approximate nearest neighbor search (ANN) 即 近似最近鄰搜尋。這種搜尋方式在犧牲一定準確性的情況下優先追求搜尋效能。

為了使用 _knn_search 搜尋,在資料建模時有所不同。

示例:

PUT my-index-knn
{
  "mappings": {
    "properties": {
      "my_vector": {
        "type": "dense_vector",
        "dims": 128,
        "index": true,
        "similarity": "dot_product"
      }
    }
  }
}

如上所示,我們必須額外指定:

  • index 為 true 。
  • similarity 指定向量相似度演算法,可以是 l2_normdot_productcosine 其中之一。

額外指定 index 為 true 是因為,為了實現 _knn_search,ES 必須在底層構建一個新的資料結構(目前使用的是 HNSW graph )。

_knn_search 搜尋示例:

GET my-index-knn/_knn_search
{
  "knn": {
    "field": "my_vector",
    "query_vector": [0.3, 0.1, 1.2, ...],
    "k": 10,
    "num_candidates": 100
  },
  "_source": ["name", "date"]
}

使用 _knn_search 搜尋的優點就是搜尋速度非常快,缺點就是精確度不是百分百,同時無法與 Query DSL 一起使用,即無法進行混合搜尋。

參考文件

相關文章