Elasticsearch 8.0及以上版本新增向量近鄰檢索k-nearest neighbor(kNN)search功能,能夠幫助您快速實(shí)現(xiàn)圖像搜索、視頻指紋采樣、人臉識(shí)別、語(yǔ)音識(shí)別和商品推薦等向量檢索場(chǎng)景的需求。本文介紹如何使用kNN search功能。
背景信息
關(guān)于Elasticsearch向量近鄰檢索k-nearest neighbor(kNN)search的詳細(xì)說(shuō)明,請(qǐng)參見k-nearest neighbor(kNN)search。
前提條件
- 創(chuàng)建阿里云Elasticsearch 8.x版本實(shí)例,本文以阿里云Elasticsearch 8.5.1版本為例介紹。創(chuàng)建實(shí)例的方法,請(qǐng)參見創(chuàng)建阿里云Elasticsearch實(shí)例。
- 將業(yè)務(wù)數(shù)據(jù)轉(zhuǎn)換成有意義的向量值(根據(jù)相似性設(shè)計(jì)向量,文檔的向量與查詢向量越接近,向量相似度匹配越好),并將向量數(shù)據(jù)存儲(chǔ)在dense_vector類型的字段下。
注意事項(xiàng)
- 需使用dense_vector類型的索引字段存儲(chǔ)向量值,且dense_vector類型不支持aggregations和sorting。
- nesetd字段類型下不支持近似kNN查詢。
- Elasticsearch ccs場(chǎng)景使用kNN檢索時(shí),不支持ccs_minimize_roundtrips參數(shù)。
- kNN默認(rèn)使用dfs_query_then_fetch查詢類型,執(zhí)行kNN查詢時(shí),不能顯式設(shè)置search_type。
kNN檢索方式說(shuō)明
kNN支持兩種檢索方式:近似kNN和精確kNN,兩者區(qū)別如下。
檢索方式 | 查詢接口 | 是否全內(nèi)存 | mapping要求 | 特點(diǎn) |
---|---|---|---|---|
近似kNN | 通過search API指定kNN參數(shù)查詢。 | 是 | 向量字段下index參數(shù)需要設(shè)置為true,才能開啟近似kNN查詢。 說(shuō)明 近似kNN搜索是在8.0版本新增的,在此之前,dense_vector類型的字段不支持在mapping中設(shè)置index為true。如果低于8.0版本的集群升級(jí)到阿里云Elasticsearch 8.5版本,并且要使用kNN檢索,需要確保創(chuàng)建的索引包含dense_vector類型的字段。為了支持近似kNN搜索,還需要重建索引并且設(shè)置新索引mapping中的index為true。 | 近似kNN以較慢的索引速度和較低的準(zhǔn)確性為代價(jià)來(lái)降低延遲。 |
精確kNN | 帶向量函數(shù)的script_score查詢。 | 是 | 向量字段下index參數(shù)設(shè)置false或不要指定,可提高檢索效率。 | script_score查詢將掃描每個(gè)匹配的文檔來(lái)計(jì)算向量函數(shù),會(huì)導(dǎo)致搜索速度變慢。可以通過query限制傳遞給向量函數(shù)的文檔數(shù)改善延遲。 |
近似kNN
調(diào)整性能
通過近似kNN檢索,您可以高效地找到與查詢向量最近的K個(gè)向量,其搜索方式與其他查詢存在差異,因此對(duì)集群性能有特殊要求,可參考以下方式調(diào)整:
- Elasticsearch將每個(gè)segment的密集向量值以HNSW圖來(lái)存儲(chǔ),因此索引向量數(shù)據(jù)時(shí)主要耗時(shí)在HNSW圖的構(gòu)建過程中,建議您增加客戶端超時(shí)時(shí)間且使用bulk請(qǐng)求寫入數(shù)據(jù)。
- 降低索引segment數(shù)或?qū)⑺衧egment合并為1個(gè)來(lái)提高檢索效率。
- 數(shù)據(jù)節(jié)點(diǎn)的內(nèi)存空間大于所有向量數(shù)據(jù)和索引結(jié)構(gòu)所占空間。
- 避免在kNN檢索期間大量寫入或更新數(shù)據(jù)。
創(chuàng)建索引
創(chuàng)建近似kNN時(shí),索引mapping必須設(shè)置index為true,并指定similarity參數(shù)值。
PUT image-index
{
"mappings": {
"properties": {
"image-vector": {
"type": "dense_vector",
"dims": 3,
"index": true,
"similarity": "l2_norm"
},
"title": {
"type": "text"
},
"file-type": {
"type": "keyword"
}
}
}
}
向量參數(shù)說(shuō)明如下,更多參數(shù)說(shuō)明,請(qǐng)參見dense-vector。參數(shù) | 說(shuō)明 |
---|---|
type | 用來(lái)存儲(chǔ)浮點(diǎn)數(shù)的密集向量。需要設(shè)置為dense_vector。 |
dims | 向量的維度大小。當(dāng)index為true時(shí),不能超過1024;當(dāng)index為false時(shí),不能超過2048 。 |
index | 是否為kNN生成新的索引。實(shí)現(xiàn)近似kNN查詢時(shí),需要將index設(shè)置為true,默認(rèn)為false。 |
similarity | 文檔間的相似度算法。index為true時(shí),此值必須設(shè)置。可選值:
|
寫入數(shù)據(jù)
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調(diào)用knn參數(shù)。
說(shuō)明 knn_search API在Elasticsearch 8.4版本之后被廢棄,請(qǐng)通過在search API中配置knn參數(shù)的方式進(jìn)行向量檢索。
POST image-index/_search
{
"knn": {
"field": "image-vector",
"query_vector": [-5, 9, -12],
"k": 10,
"num_candidates": 100
},
"fields": [ "title", "file-type" ]
}
knn參數(shù)說(shuō)明如下,詳細(xì)說(shuō)明請(qǐng)參見search-api-knn。參數(shù) | 是否必選 | 說(shuō)明 |
---|---|---|
field | 是 | 要檢索的向量字段名稱。 |
query_vector | 是 | 查詢向量,必須與field指定的向量數(shù)據(jù)具有相同的維度。 |
k | 是 | 返回的最近鄰對(duì)象的數(shù)量。k的值需要小于num_candidates。 |
num_candidates | 是 | 每個(gè)分片上需查找的最近鄰候選對(duì)象的個(gè)數(shù),不能超過10000。 說(shuō)明 增加num_candidates的值可提高最終K值的準(zhǔn)確性,但相應(yīng)搜索速度會(huì)變慢。 |
filter | 否 | 通過DSL語(yǔ)句過濾文檔。kNN從過濾后的文檔中返回前K個(gè)文檔,如果不指定過濾器,將對(duì)所有文檔做kNN近似計(jì)算。 |
精確kNN
創(chuàng)建索引
PUT zl-index
{
"mappings": {
"properties": {
"product-vector": {
"type": "dense_vector",
"dims": 5,
"index": false
},
"price": {
"type": "long"
}
}
}
}
定義向量字段部分參數(shù)說(shuō)明如下,更多參數(shù)說(shuō)明請(qǐng)參見dense-vector。
參數(shù) | 說(shuō)明 |
---|---|
type | 用來(lái)存儲(chǔ)浮點(diǎn)數(shù)的密集向量,需要設(shè)置為dense_vector。 |
dim | 向量的維度大小。 |
index | 是否為kNN生成新的索引文件。默認(rèn)值為false。使用精確kNN檢索,可不配置index參數(shù)或?qū)⑵湓O(shè)置為false,可提高精確kNN的檢索效率。 |
寫入數(shù)據(jù)
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查詢中指定向量函數(shù)cosineSimilarity,并使用script_score.query指定過濾器限制傳遞給vector文檔數(shù)來(lái)降低搜索延遲。
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支持以下向量函數(shù),更多說(shuō)明請(qǐng)參見向量訪問。
函數(shù)名 | 說(shuō)明 |
---|---|
cosineSimilarity | 計(jì)算查詢向量和文檔向量的余弦相似度。 |
dotProduct | 計(jì)算查詢向量和文檔向量之間的點(diǎn)乘距離。 |
l1norm | 計(jì)算查詢向量和文檔向量之間的L1距離(曼哈頓距離)。 |
l2norm | 計(jì)算查詢向量和文檔向量之間的L2距離(歐式距離)。 |