全部產品
Search
文件中心

Elasticsearch:使用Elasticsearch的向量近鄰檢索(kNN)功能

更新時間:Jun 30, 2024

Elasticsearch 8.0及以上版本新增向量近鄰檢索k-nearest neighbor(kNN)search功能,能夠協助您快速實現Image Search、視頻指紋採樣、Face Service、語音辨識和商品推薦等向量檢索情境的需求。本文介紹如何使用kNN search功能。

背景資訊

關於Elasticsearch向量近鄰檢索k-nearest neighbor(kNN)search的詳細說明,請參見k-nearest neighbor(kNN)search

前提條件

  • 建立Elasticsearch 8.x版本執行個體,本文以Elasticsearch 8.5.1版本為例介紹。建立執行個體的方法,請參見建立Elasticsearch執行個體
  • 將業務資料轉換成有意義的向量值(根據相似性設計向量,文檔的向量與查詢向量越接近,向量相似性匹配越好),並將向量資料存放區在dense_vector類型的欄位下。

注意事項

  • 需使用dense_vector類型的索引欄位儲存向量值,且dense_vector類型不支援aggregations和sorting。
  • nesetd欄位類型下不支援近似kNN查詢。
  • Elasticsearch ccs情境使用kNN檢索時,不支援ccs_minimize_roundtrips參數。
  • kNN預設使用dfs_query_then_fetch查詢類型,執行kNN查詢時,不能顯式設定search_type。

kNN檢索方式說明

kNN支援兩種檢索方式:近似kNN精確kNN,兩者區別如下。
檢索方式查詢介面是否全記憶體mapping要求特點
近似kNN通過search API指定kNN參數查詢向量欄位下index參數需要設定為true,才能開啟近似kNN查詢。
說明 近似kNN搜尋是在8.0版本新增的,在此之前,dense_vector類型的欄位不支援在mapping中設定index為true。如果低於8.0版本的叢集升級到Elasticsearch 8.5版本,並且要使用kNN檢索,需要確保建立的索引包含dense_vector類型的欄位。為了支援近似kNN搜尋,還需要重建索引並且設定新索引mapping中的index為true。
近似kNN以較慢的索引速度和較低的準確性為代價來降低延遲。
精確kNN帶向量函數的script_score查詢。向量欄位下index參數設定false或不要指定,可提高檢索效率。script_score查詢將掃描每個匹配的文檔來計算向量函數,會導致搜尋速度變慢。可以通過query限制傳遞給向量函數的文檔數改善延遲。

近似kNN

調整效能

通過近似kNN檢索,您可以高效地找到與查詢向量最近的K個向量,其搜尋方式與其他查詢存在差異,因此對叢集效能有特殊要求,可參考以下方式調整:
  • Elasticsearch將每個segment的密集向量值以HNSW圖來儲存,因此索引向量資料時主要耗時在HNSW圖的構建過程中,建議您增加用戶端逾時時間且使用bulk請求寫入資料。
  • 降低索引segment數或將所有segment合并為1個來提高檢索效率。
  • 資料節點的記憶體空間大於所有向量資料和索引結構所佔空間。
  • 避免在kNN檢索期間大量寫入或更新資料。

建立索引

建立近似kNN時,索引mapping必須設定indextrue,並指定similarity參數值。
PUT image-index
{
  "mappings": {
    "properties": {
      "image-vector": {
        "type": "dense_vector",
        "dims": 3,
        "index": true,
        "similarity": "l2_norm"
      },
      "title": {
        "type": "text"
      },
      "file-type": {
        "type": "keyword"
      }
    }
  }
}
向量參數說明如下,更多參數說明,請參見dense-vector
參數說明
type用來儲存浮點數的密集向量。需要設定為dense_vector。
dims向量的維度大小。當indextrue時,不能超過1024;當indexfalse時,不能超過2048 。
index是否為kNN產生新的索引。實現近似kNN查詢時,需要將index設定為true,預設為false。
similarity文檔間的相似性演算法。indextrue時,此值必須設定。可選值:
  • l2_norm:計算向量間歐式距離。_score公式:1 / (1 + l2_norm(query, vector)^2)
  • dot_product:計算兩個向量點積,_score計算依賴element_type參數值。
    • element_typefloat,所有向量需歸一化為單位長度。_score公式:(1 + dot_product(query, vector)) / 2
    • element_typebyte,所有向量需要有相同的長度,否則結果不準確。_score公式:0.5 + (dot_product(query, vector) / (32768 * dims))
  • cosine:計算向量間的餘弦相似性。最有效cosine使用方式是將所有向量歸一化為單位長度代替dot_product。_score公式:(1 + cosine(query, vector)) / 2
    重要 餘弦相似性演算法不允許向量資料為0。

寫入資料

POST image-index/_bulk?refresh=true
{ "index": { "_id": "1" } }
{ "image-vector": [1, 5, -20], "title": "moose family", "file-type": "jpg" }
{ "index": { "_id": "2" } }
{ "image-vector": [42, 8, -15], "title": "alpine lake", "file-type": "png" }
{ "index": { "_id": "3" } }
{ "image-vector": [15, 11, 23], "title": "full moon", "file-type": "jpg" }

向量檢索

近似向量檢索需要通過search API調用knn參數
說明 knn_search API在Elasticsearch 8.4版本之後被廢棄,請通過在search API中配置knn參數的方式進行向量檢索。
POST image-index/_search
{
  "knn": {
    "field": "image-vector",
    "query_vector": [-5, 9, -12],
    "k": 10,
    "num_candidates": 100
  },
  "fields": [ "title", "file-type" ]
}
knn參數說明如下,詳細說明請參見search-api-knn
參數是否必選說明
field要檢索的向量欄位名稱。
query_vector查詢向量,必須與field指定的向量資料具有相同的維度。
k返回的最近鄰對象的數量。k的值需要小於num_candidates
num_candidates每個分區上需尋找的最近鄰候選對象的個數,不能超過10000。
說明 增加num_candidates的值可提高最終K值的準確性,但相應搜尋速度會變慢。
filter通過DSL語句過濾文檔。kNN從過濾後的文檔中返回前K個文檔,如果不指定過濾器,將對所有文檔做kNN近似計算。

精確kNN

建立索引

PUT zl-index
{
  "mappings": {
    "properties": {
      "product-vector": {
        "type": "dense_vector",
        "dims": 5,
        "index": false
      },
      "price": {
        "type": "long"
      }
    }
  }
}
定義向量欄位部分參數說明如下,更多參數說明請參見dense-vector
參數說明
type用來儲存浮點數的密集向量,需要設定為dense_vector
dim向量的維度大小。
index是否為kNN產生新的索引檔案。預設值為false。使用精確kNN檢索,可不配置index參數或將其設定為false,可提高精確kNN的檢索效率。

寫入資料

POST zl-index/_bulk?refresh=true
{ "index": { "_id": "1" } }
{ "product-vector": [230.0, 300.33, -34.8988, 15.555, -200.0], "price": 1599 }
{ "index": { "_id": "2" } }
{ "product-vector": [-0.5, 100.0, -13.0, 14.8, -156.0], "price": 799 }
{ "index": { "_id": "3" } }
{ "product-vector": [0.5, 111.3, -13.0, 14.8, -156.0], "price": 1099 }

查詢向量

以下樣本在script_score查詢中指定向量函數cosineSimilarity,並使用script_score.query指定過濾器限制傳遞給vector文檔數來降低搜尋延遲。
POST zl-index/_search
{
  "query": {
    "script_score": {
      "query" : {
        "bool" : {
          "filter" : {
            "range" : {
              "price" : {
                "gte": 1000
              }
            }
          }
        }
      },
      "script": {
        "source": "cosineSimilarity(params.queryVector, 'product-vector') + 1.0",
        "params": {
          "queryVector": [-0.5, 90.0, -10, 14.8, -156.0]
        }
      }
    }
  }
}
script_score支援以下向量函數,更多說明請參見向量訪問
函數名說明
cosineSimilarity計算查詢向量和文檔向量的餘弦相似性。
dotProduct計算查詢向量和文檔向量之間的點乘距離。
l1norm計算查詢向量和文檔向量之間的L1距離(曼哈頓距離)。
l2norm計算查詢向量和文檔向量之間的L2距離(歐式距離)。