本文介绍了标量属性下推的方法,将标量过滤集成到向量检索的算法内部,以解决传统混合查询“先过滤、后搜索”的低效问题,从而提升查询速度。
前提条件
准备工作
在使用高级特性前,请先通过curl命令连接搜索引擎。具体操作及连接参数说明,请参见连接搜索引擎。
创建索引
目前属性下推支持 ivfpq、ivfbq(推荐)、hnswq(推荐) 三个算法。下方以hnswq + filter为例说明整体使用流程。
{
"settings" : {
"index": {
"number_of_shards": 2,
"knn": true
}
},
"mappings": {
"_source": {
"excludes": ["vector1"]
},
"properties": {
"vector1": {
"type": "knn_vector",
"dimension": 3,
"meta": {"offline.construction": "true"},
"method": {
"engine": "lvector",
"name": "hnswq",
"space_type": "l2",
"parameters": {
"m": 24,
"ef_construction": 200
}
}
},
"field1": {
"type": "integer",
"meta": {
"_vector_filter": "true"
}
}
}
}
}"meta": { "_vector_filter": "true" }代表启动属性下推功能,目前支持的下推属性有 integer、long、keyword、double、float、boolean。
数据写入
包含向量列的索引与普通索引的数据写入方式一致,以向量数组(Float数组)格式写入,例如[1.2, 1.3, 1.4]。
单条写入
curl -u <username>:<password> -H 'Content-Type: application/json' -XPOST "http://<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 "http://<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>:<password> -H 'Content-Type: application/json' -XPOST "http://<URL>/_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>:<password> -H 'Content-Type: application/json' -XPOST "http://<URL>/_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>:<password> -H 'Content-Type: application/json' -XPUT "http://<URL>/vector_sparse_test/_doc/1?pretty" -d '{
"field1": 2,
"vector1": "{\"indices\": [10, 14, 16], \"values\": [0.5, 0.5, 0.2]}"
}'JSON Object
curl -u <username>:<password> -H 'Content-Type: application/json' -XPUT "http://<URL>/vector_sparse_test/_doc/1?pretty" -d '{
"field1": 1,
"vector1": {"indices": [10, 12, 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>:<password> -H 'Content-Type: application/json' -XPOST "http://<URL>/_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>:<password> -H 'Content-Type: application/json' -XGET "http://<URL>/_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(构建失败)。
通常调用/index/abort接口来终止索引构建,索引构建终止后状态为ABORT。
终止构建
终止索引的构建流程。状态为FINISH的索引不支持终止构建操作。
curl -u <username>:<password> -H 'Content-Type: application/json' -XPOST "http://<URL>/_plugins/_vector/index/tasks/abort" -d '{
"indexName": "vector_ivfpq_test",
"fieldName": "vector1",
"taskIds": "[\"default_vector_ivfpq_test_vector1\"]"
}'查询
通过在knn查询中内嵌filter条件,并结合ext参数中的"filter_type": "efficient_filter",实现了在向量检索过程中进行高效的实时过滤。这种方式避免了传统的“先过滤、再搜索”带来的性能瓶颈,能够大幅提升在海量数据中进行复杂条件筛选下的向量查询速度和准确性。
curl -u <username>:<password> -H 'Content-Type: application/json' -XGET "http://<URL>/<索引名称>/_search?pretty" -d '
{
"size": 10,
"query": {
"knn": {
"vector1": {
"vector": [2.2, 2.3, 2.4],
"filter": {
"range": {
"field1": {
"gte": 0
}
}
},
"k": 10
}
}
},
"ext": {"lvector": {"filter_type": "efficient_filter", "ef_search":"
100"}}
}'参数说明
参数结构 | 参数 | 是否必填 | 说明 |
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]。默认值为 重要
| |
lvector.client_refactor | 否 | 是否不在每个分片(Shard)内进行重排序,而是在系统上层进行重排序,进而提升系统性能。取值如下:
| |
lvector. k_expand_scope | 否 | Efficient_Filter近似查询场景下,服务端如果选择了post_filter模式,将使用该值替换k值,用来实现放大k值的效果。默认值为 |