Lindorm向量引擎支持向量數據檢索功能,兼容Elasticsearch協議,同時支持標量、向量、全文混合檢索功能。本文介紹如何通過curl命令連接并使用向量引擎。
前提條件
算法說明
您可以參考各個算法的特點、適用的數據量等,創建適合業務場景的向量索引。
算法 | 數據量 | 資源占用 | 算法特點 | 注意事項 |
flat | [0,1萬) | 純內存。 | 暴力檢索,使用簡單,適合小數據集。 | 檢索性能會隨著數據量增加而降低。 |
hnsw | [1萬, 100萬) | 純內存,資源占用較高。 | 在線索引,適合數據集中等規模,用法相對簡單。 | CPU占用量與number_of_shards(索引分片數量)的值相關,其值通常設置為向量引擎節點數。如果索引數量較多,且每個索引數據量較少,將number_of_shards設置為 |
ivfpq | 100萬以上 | 磁盤索引,默認1:8壓縮,即內存大小為原始數據的1/8。 | 離線索引,需要先寫入一定量的數據再構建索引,適合大數據集,成本較低。 | 發起索引構建時需確保寫入的數據量充足,必須大于256條且超過nlist的30倍。 建議在離線數據導入完成后再觸發索引構建。索引構建完成后,您可以正常進行KNN查詢和寫入操作。 說明 nlist參數的說明,請參見參數說明。 |
創建向量索引
創建向量索引,其中vector1
為向量列、field1
為普通列。向量列及其相關參數必須在創建索引時通過mappings結構顯式指定。
hnsw類型索引
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPUT "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_test?pretty" -d '
{
"settings" : {
"index": {
"number_of_shards": 2,
"knn": true
}
},
"mappings": {
"_source": {
"excludes": ["vector1"]
},
"properties": {
"vector1": {
"type": "knn_vector",
"dimension": 3,
"data_type": "float",
"method": {
"engine": "lvector",
"name": "hnsw",
"space_type": "l2",
"parameters": {
"m": 24,
"ef_construction": 200
}
}
},
"field1": {
"type": "long"
}
}
}
}'
ivfpq類型索引
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPUT "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_ivfpq_test?pretty" -d '
{
"settings": {
"index": {
"number_of_shards": 4,
"knn": true,
"knn.offline.construction": true
}
},
"mappings": {
"_source": {
"excludes": ["vector1"]
},
"properties": {
"vector1": {
"type": "knn_vector",
"dimension": 3,
"data_type": "float",
"method": {
"engine": "lvector",
"name": "ivfpq",
"space_type": "cosinesimil",
"parameters": {
"m": 3,
"nlist": 10000,
"centroids_use_hnsw": true,
"centroids_hnsw_m": 48,
"centroids_hnsw_ef_construct": 500,
"centroids_hnsw_ef_search": 200
}
}
},
"field1": {
"type": "long"
}
}
}
}
'
創建ivfpq類型索引,您必須注意以下事項:
ivfpq中knn.offline.construction務必設置為
true
,后續需要寫入一定量的數據才能發起構建索引。使用ivfpq算法請將dimension替換業務真實向量維度,并將m值設置為與dimension相同的值。
稀疏向量索引
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPUT "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_sparse_test?pretty" -d '
{
"settings" : {
"index": {
"number_of_shards": 2,
"knn": true
}
},
"mappings": {
"_source": {
"excludes": ["vector1"]
},
"properties": {
"vector1": {
"type": "knn_vector",
"data_type": "sparse_vector",
"method": {
"engine": "lvector",
"name": "sparse_hnsw",
"space_type": "innerproduct",
"parameters": {
"m": 24,
"ef_construction": 200
}
}
},
"field1": {
"type": "long"
}
}
}
}'
參數說明
連接參數說明
參數 | 是否必填 | 示例值 | 說明 |
URL | 是 | ld-bp106782jm96****-proxy-search-vpc.lindorm.aliyuncs.com:30070 | 搜索引擎的Elasticsearch兼容連接地址。如何獲取,請參見Elasticsearch兼容地址。 |
username | 是 | xltest | 訪問向量引擎的用戶名和密碼。 默認用戶名和密碼的獲取方式:在控制臺的左側導航欄,選擇數據庫連接,單擊搜索引擎頁簽,在搜索引擎頁簽可獲取。 |
password | 是 | test |
向量列參數說明
通用參數
參數 | 是否必填 | 說明 |
type | 是 | 索引列的類型。對于向量列,固定為 |
dimension | 是 | 向量數據的維度。取值范圍:[1,32768]。 |
data_type | 否 | 向量數據的類型。目前支持以下類型:
|
method.name | 是 | 向量數據的索引算法。取值如下:
|
method.space_type | 否 | 向量數據的距離算法。取值如下:
|
HNSW算法參數
參數 | 是否必填 | 說明 |
method.parameters.m | 否 | 每一層圖的最大出邊數量。 取值范圍:[1,100]。默認值為 |
method.parameters.ef_construction | 否 | 索引構建時動態列表的長度。 取值范圍:[1,1000]。默認值為 |
IVFPQ算法參數
參數 | 是否必填 | 說明 |
method.parameters.m | 否 | 量化中子空間的數量。取值范圍:[2,32768]。默認值為 重要 創建ivfpq類型索引時,該參數值必須與通用參數dimension的值相同。 |
method.parameters.nlist | 否 | 聚類中心的數量。 取值范圍:[2, 1000000]。默認值為 |
method.parameters.centroids_use_hnsw | 否 | 是否在聚類中心搜索時使用HNSW算法。 取值如下:
|
method.parameters.centroids_hnsw_m | 否 | 若在聚類中心搜索時使用HNSW算法,設定HNSW算法的每一層圖的最大出邊數量。 取值范圍:[1,100]。默認值為 |
method.parameters.centroids_hnsw_ef_construct | 否 | 若在聚類中心搜索時使用HNSW算法,設定HNSW算法在索引構建時動態列表的長度。 取值范圍:[1,1000]。默認值為 |
method.parameters.centroids_hnsw_ef_search | 否 | 若在聚類中心搜索時使用HNSW算法,設定HNSW算法在查詢時動態列表的長度。 取值范圍:[1,1000]。默認值為 |
假設向量索引名為vector_test
,返回結果如下:
{"acknowledged":true,"shards_acknowledged":true,"index":"vector_test"}
數據寫入
包含向量列的索引與普通索引的數據寫入方式一致,以向量數組(Float數組)格式寫入,例如[1.2, 1.3, 1.4]
。
單條寫入
curl -u <username>:<password> -H 'Content-Type: application/json' -XPOST "<URL>/<索引名稱>/_doc/1?pretty" -d '
{"field1": 1, "vector1": [1.2, 1.3, 1.4]}'
以索引vector_test
為例,返回結果如下:
{"_index":"vector_test","_type":"_doc","_id":"1","_version":1,"result":"created","_shards":{"total":1,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}
批量寫入
curl -u <username>:<password> -H 'Content-Type: application/json' -XPUT "<URL>/_bulk?pretty" -d '
{ "index" : { "_index" : "vector_test", "_id" : "2" } }
{ "field1" : 1, "vector1": [2.2, 2.3, 2.4]}
{ "index" : { "_index" : "vector_test", "_id" : "3" } }
{ "field1" : 2, "vector1": [1.2, 1.3, 4.4]}
{ "delete" : { "_index" : "vector_test", "_id" : "2" } }
{ "update" : {"_id" : "1", "_index" : "vector_test"} }
{ "doc" : {"field1" : 3, "vector1": [2.2, 3.3, 4.4]} }
'
插入寫
若目標數據已存在,則不允許寫入。
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPOST "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/_bulk?pretty" -d '
{ "create" : { "_index" : "vector_test", "_id" : "1" } }
{ "field1" : 1, "vector1": [2.2, 2.3, 2.4]}
{ "create" : { "_index" : "vector_test", "_id" : "2" } }
{ "field1" : 2, "vector1": [1.2, 1.3, 4.4]}
'
更新寫
若目標數據已存在,則執行更新操作;若目標數據不存在,寫入數據。
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPOST "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/_bulk?pretty" -d '
{ "index" : { "_index" : "vector_test", "_id" : "3" } }
{ "field1" : 1, "vector1": [2.2, 2.3, 2.4]}
{ "index" : { "_index" : "vector_test", "_id" : "4" } }
{ "field1" : 2, "vector1": [1.2, 1.3, 4.4]}
'
稀疏向量寫入
寫入方式與上述方式相同,但需要修改vector1的格式。共支持兩種格式:JSON STRING和JSON Object。前者性能更優,后者格式更友好。
JSON STRING
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPUT "http://ld-t4n1ui****.lindorm.aliyuncs.com:30070/vector_sparse_test/_doc/1?pretty" -d '{
"field1": 1,
"vector1": {"indices": [10, 12, 16], "values": [0.5, 0.5, 0.2]}
}'
JSON Object
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPUT "http://ld-t4n56631ui****.lindorm.aliyuncs.com:30070/vector_sparse_test/_doc/1?pretty" -d '{
"field1": 2,
"vector1": "{\"indices\": [10, 14, 16], \"values\": [0.5, 0.5, 0.2]}"
}'
索引構建
除ivfpq索引,其他類型索引創建時index.knn.offline.construction默認為
false
,即在線索引,無需手動構建。在觸發ivfpq索引構建前需注意:在創建ivfpq索引時,需將index.knn.offline.construction顯式指定為
true
,且在發起構建時務必確保已寫入足夠的數據量,必須大于256條且超過nlist的30倍。手動觸發索引構建完成后,后續可正常寫入和查詢,無需再次構建索引。
觸發構建
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPOST "http://ld-t4n56****.lindorm.aliyuncs.com:30070/_plugins/_vector/index/build" -d '
{
"indexName": "vector_ivfpq_test",
"fieldName": "vector1",
"removeOldIndex": "true"
}'
參數說明
參數 | 是否必填 | 說明 |
indexName | 是 | 表名稱,例如 |
fieldName | 是 | 針對哪個字段構建索引,例如 |
removeOldIndex | 是 | 構建索引時,是否刪除舊的索引。取值如下:
|
返回結果如下:
{
"payload": ["default_vector_ivfpq_test_vector1"]
}
返回結果為索引構建生成的taskId
。
查看索引狀態
您可以通過以下方式查看索引構建狀態。
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t****.lindorm.aliyuncs.com:30070/_plugins/_vector/index/tasks" -d '{
"indexName": "vector_ivfpq_test",
"fieldName": "vector1",
"taskIds": "[\"default_vector_ivfpq_test_vector1\"]"
}'
其中,taskIds為觸發構建時生成的taskId
,可以填寫空的數組,例如"taskIds": "[]"
,效果與上述已填寫taskIds的效果一致。
返回結果如下:
{
"payload": ["task: default_vector_ivfpq_test_vector1, stage: FINISH, innerTasks: xxx, info: finish building"]
}
其中,stage表示構建狀態,共包含以下幾種狀態:START(開始構建)、TRAIN(訓練階段)、BUILDING(構建中)、ABORT(終止構建)、FINISH(構建完成)和FAIL(構建失敗)。
ABORT通常調用/index/abort接口來終止索引構建。
終止構建
終止索引的構建流程。狀態為FINISH
的索引不支持調用該方法。
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPOST "http://ld-t**.lindorm.aliyuncs.com:30070/_plugins/_vector/index/tasks/abort" -d '{
"indexName": "vector_ivfpq_test",
"fieldName": "vector1",
"taskIds": "[\"default_vector_ivfpq_test_vector1\"]"
}'
數據查詢
純向量數據查詢
純向量數據的查詢可以通過knn結構實現。
curl -u <username>:<password> -H 'Content-Type: application/json' -XGET "<URL>/<索引名稱>/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.3, 3.3, 4.4],
"k": 10
}
}
},
"ext": {"lvector": {"min_score": "0.8"}}
}'
參數說明
參數結構 | 參數 | 是否必填 | 說明 |
knn | vector | 是 | 查詢時使用的向量。 |
k | 是 | 返回最相似的K個數據。 重要 在純向量檢索場景中,建議將size和k設置為相同的值。 | |
ext | lvector.min_score | 否 | 相似度閾值,要求返回的向量得分大于該值。返回的向量得分范圍為[0,1]。 取值范圍:[0,+inf]。默認值為 |
lvector.filter_type | 否 | 融合查詢使用的模式。取值如下:
默認值為空。 | |
lvector.ef_search | 否 | HNSW算法中,索引構建時動態列表的長度。只能用于HNSW算法。 取值范圍:[1,1000]。默認值為 | |
lvector.nprobe | 否 | 要查詢的聚類單元(cluster units)的數量。請根據您的召回率要求,對該參數的值進行調整已達到理想效果。值越大,召回率越高,搜索性能越低。 取值范圍:[1,method.parameters.nlist]。無默認值。 重要 僅適用于ivfpq算法。 | |
lvector.reorder_factor | 否 | 使用原始向量創建重排序(reorder)。ivfpq算法計算的距離為量化后的距離,會有一定的精度損失,需要使用原始向量進行重排序。比例為 取值范圍:[1,200]。默認值為 重要
|
以索引vector_test
為例,返回結果如下:
{
"took" : 30,
"timed_out" : false,
"terminated_early" : false,
"num_reduce_phases" : 0,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "vector_test",
"_id" : "2",
"_score" : 1.0
},
{
"_index" : "vector_test",
"_id" : "1",
"_score" : 0.25
},
{
"_index" : "vector_test",
"_id" : "3",
"_score" : 0.14285715
}
]
}
}
返回指定字段
如果需要在查詢時返回指定字段,可以指定 "_source": ["field1", "field2"]
或使用"_source": true
返回非向量的全部字段。使用方法如下:
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_test/_search?pretty" -d '
{
"size": 10,
"_source": ["field1"],
"query": {
"knn": {
"vector1": {
"vector": [2.2, 2.3, 2.4],
"k": 10
}
}
},
"ext": {"lvector": {"min_score": "0.01"}}
}'
返回結果如下:
{
"took" : 35,
"timed_out" : false,
"terminated_early" : false,
"num_reduce_phases" : 0,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "vector_test",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"field1" : 1
}
},
{
"_index" : "vector_test",
"_id" : "1",
"_score" : 0.25,
"_source" : {
"field1" : 1
}
},
{
"_index" : "vector_test",
"_id" : "3",
"_score" : 0.14285715,
"_source" : {
"field1" : 2
}
}
]
}
}
hsnw算法查詢
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_test/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.2, 2.3, 2.4],
"k": 10
}
}
},
"ext": {"lvector": {"ef_search": "100"}}
}'
ivfpq算法查詢
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t68xk31ui****.lindorm.aliyuncs.com:30070/vector_ivfpq_test/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.2, 2.3, 2.4],
"k": 10
}
}
},
"ext": {"lvector": {"nprobe": "60", "reorder_factor": "5"}}
}'
如果k值相對較大,如大于100,將reorder_factor的值設置為
1
即可。當nlist的值為
10000
時,可以先將nprobe設置為60
,查看檢索效果。如果想繼續提升召回率,可適當增加nprobe的值,如80、100、120、140、160,該值引起的性能損耗遠小于reorder_factor,但也不適宜設置過大。
稀疏向量查詢
查詢方式與上述方式相同,但需要修改vector1的格式。共支持兩種格式:JSON STRING和JSON Object。前者性能更優,后者格式更友好。
JSON STRING
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t631ui****.lindorm.aliyuncs.com:30070/vector_sparse_test/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": {"indices": [10, 45, 16], "values": [0.5, 0.5, 0.2]},
"k": 10
}
}
}
}'
JSON Object
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t631ui****.lindorm.aliyuncs.com:30070/vector_sparse_test/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": "{\"indices\": [10, 45, 16], \"values\": [0.5, 0.5, 0.2]}",
"k": 10
}
}
}
}'
融合查詢
向量列的查詢可與普通列的查詢條件結合,并返回綜合的查詢結果。在實際業務使用時, Post_Filter近似查詢通常能獲取更相似的檢索結果。
Pre-Filter近似查詢
通過在knn查詢結構內部添加過濾器filter,并指定filter_type參數的值為pre_filter
,可實現先過濾結構化數據,再查詢向量數據。
目前結構化過濾數據的上限為10,000條。
curl -u <username>:<password> -H 'Content-Type: application/json' -XGET "<URL>/<索引名稱>/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.3, 3.3, 4.4],
"filter": {
"range": {
"field1": {
"gte": 0
}
}
},
"k": 10
}
}
},
"ext": {"lvector": {"filter_type": "pre_filter"}}
}'
Post-Filter近似查詢
通過在knn查詢結構內部添加過濾器filter,并指定filter_type參數的值為post_filter
,可實現先查詢向量數據,再過濾結構化數據。
在使用Post_Filter近似查詢時,可以適當將k的值設置大一些,以便獲取更多的向量數據再進行過濾。
curl -u <username>:<password> -H 'Content-Type: application/json' -XGET "<URL>/<索引名稱>/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.3, 3.3, 4.4],
"filter": {
"range": {
"field1": {
"gte": 0
}
}
},
"k": 10
}
}
},
"ext": {"lvector": {"filter_type": "post_filter"}}
}'
在使用Post_Filter近似查詢時需要適當放大k的值,在使用ivfpq算法的情況下需要調整reorder_factor的值,具體使用如下:
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XGET "http://ld-t4n8xk31ui****.lindorm.aliyuncs.com:30070/vector_ivfpq_test/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.2, 2.3, 2.4],
"filter": {
"range": {
"field1": {
"gte": 0
}
}
},
"k": 1000
}
}
},
"ext": {"lvector": {"filter_type": "post_filter","nprobe": "60", "reorder_factor": "1"}}
}'
在Post_Filter近似查詢場景中,可以將k值放大至10,000、最大控制在20,000之內,從而將處理時延控制在百毫秒之內。如果k值相對較大,將reorder_factor的值設置為
1
即可。當nlist的值為
10000
時,可以先將nprobe設置為60,查看檢索效果。如果檢索效果不理想,可適當增加nprobe的值,如80、100、120、140、160,該值引起的性能損耗遠小于reorder_factor,但也不適宜設置過大。
您也可以通過post_filter添加過濾條件,實現Post-Filter近似查詢。
curl -u <username>:<password> -H 'Content-Type: application/json' -XGET "<URL>/<索引名稱>/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.3, 3.3, 4.4],
"k": 10
}
}
},
"post_filter": {
"range": {
"field1": {
"gte": 0
}
}
}
}'
常規用法
常規用法提供索引基礎的查詢、刪除等使用方法。
查詢所有索引及其數據量。
curl -u <username>:<pasword> -XGET "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/_cat/indices?v"
返回結果:
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size green open vector_test vector_test 2 0 2 0 6.8kb 6.8kb
查詢指定索引的數據量。以查詢
vector_test
為例。curl -u <username>:<pasword> -XGET "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_test/_count?pretty"
返回結果:
{ "count" : 2, "_shards" : { "total" : 2, "successful" : 2, "skipped" : 0, "failed" : 0 } }
查看索引創建信息。
curl -u <username>:<pasword> -XGET "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_test?pretty"
返回結果:
{ "vector_test" : { "aliases" : { }, "mappings" : { "_source" : { "excludes" : [ "vector1" ] }, "properties" : { "field1" : { "type" : "long" }, "vector1" : { "type" : "knn_vector", "dimension" : 3, "data_type" : "float", "method" : { "engine" : "lvector", "space_type" : "l2", "name" : "hnsw", "parameters" : { "ef_construction" : 200, "m" : 24 } } } } }, "settings" : { "index" : { "search" : { "slowlog" : { "level" : "DEBUG", "threshold" : { "fetch" : { "warn" : "1s", "trace" : "200ms", "debug" : "500ms", "info" : "800ms" }, "query" : { "warn" : "10s", "trace" : "500ms", "debug" : "1s", "info" : "5s" } } } }, "indexing" : { "slowlog" : { "level" : "DEBUG", "threshold" : { "index" : { "warn" : "10s", "trace" : "500ms", "debug" : "2s", "info" : "5s" } } } }, "number_of_shards" : "2", "provided_name" : "vector_test", "knn" : "true", "creation_date" : "1727169417350", "number_of_replicas" : "0", "uuid" : "vector_test", "version" : { "created" : "136287927" } } } } }
刪除整個索引。
curl -u <username>:<pasword> -XDELETE "http://ld-t4n5668xk31ui****.lindorm.aliyuncs.com:30070/vector_test"
通過查詢刪除。
curl -u <username>:<pasword> -H 'Content-Type: application/json' -XPOST "http://ld-31ui****.lindorm.aliyuncs.com:30070/vector_test/_delete_by_query" -d ' { "query": { "term": { "field1": 1 } } }'