向量检索是面向非结构化向量数据的检索功能,可以帮助您快速查找相似数据。如果您更熟悉基于Java语言的应用开发,可以根据自己的使用习惯选择合适的客户端,并参考本文提供的相关操作来实现不同的向量检索功能。
前提条件
创建向量索引
使用向量检索功能,要求索引的mappings中必须包含一个或多个向量类型字段,且所有向量字段必须显式定义。
以下示例创建一个索引,其中vector1
为向量类型字段、field1
为普通类型字段。
Java Client
CreateIndexRequest createIndexRequest = CreateIndexRequest.of(request -> request
.index("vector_test")
.settings(settings -> settings
.index(index -> index
.numberOfShards("4")
.knn(true)
)
)
.mappings(mappings -> mappings
.properties("field1", field1 -> field1
.long_(f -> f)
)
.properties("vector1", vector1 -> vector1
.knnVector(knnVector -> knnVector
.dimension(3)
.method(method -> method
.name("hnsw")
.spaceType("l2")
.engine("lvector")
.parameters("ef_construction", JsonData.of(128))
.parameters("m", JsonData.of(24))
)
)
)
.source(source -> source
.excludes("vector1")
)
)
);
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest);
Java High Level Rest Client
CreateIndexRequest createIndexRequest = new CreateIndexRequest("vector_test");
Map<String, Object> mappings = new HashMap<>();
{
Map<String, Object> properties = new HashMap<>();
Map<String, Object> field1 = new HashMap<>();
field1.put("type", "long");
properties.put("field1", field1);
Map<String, Object> vector1 = new HashMap<>();
vector1.put("type", "knn_vector");
vector1.put("dimension", 3);
Map<String, Object> method = new HashMap<>();
method.put("name", "hnsw");
method.put("space_type", "l2");
method.put("engine", "lvector");
Map<String, Object> parameters = new HashMap<>();
parameters.put("m", 24);
parameters.put("ef_construction", 128);
method.put("parameters", parameters);
vector1.put("method", method);
properties.put("vector1", vector1);
mappings.put("properties", properties);
Map<String, Object> source = new HashMap<>();
source.put("excludes", Collections.singletonList("vector1"));
mappings.put("_source", source);
}
createIndexRequest.mapping(mappings);
Map<String, Object> settings = new HashMap<>();
{
Map<String, Object> index = new HashMap<>();
index.put("knn",true);
index.put("number_of_shards", 4);
settings.put("index", index);
}
createIndexRequest.settings(settings);
CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
向量列参数的详细介绍,请参见向量列参数说明。
数据写入
向量索引的数据写入方式与普通索引的数据写入方式一致。向量字段的数据以数组的形式写入。
单条写入
Java Client
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{1.2f,1.3f,1.4f});
IndexRequest<JsonData> indexRequest = new IndexRequest.Builder<JsonData>()
.index("vector_test")
.id("1")
.document(JsonData.of(fieldMap))
.build();
IndexResponse response = client.index(indexRequest);
Java High Level Rest Client
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{1.2f,1.3f,1.4f});
IndexRequest indexRequest = new IndexRequest("vector_test");
indexRequest.id("1");
indexRequest.source(fieldMap);
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
批量写入
Java Client
JavaBulkRequest.Builder bulkRequest = new BulkRequest.Builder();
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{2.2f,2.3f,2.4f});
bulkRequest.operations(operations -> operations
.index(index -> index
.index(indexName)
.id("2")
.document(fieldMap)
)
);
}
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{2.2f,2.3f,2.4f});
bulkRequest.operations(operations -> operations
.index(index -> index
.index(indexName)
.id("2")
.document(fieldMap)
)
);
}
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 2);
fieldMap.put("vector1", new float[]{1.2f,1.3f,4.4f});
bulkRequest.operations(operations -> operations
.index(index -> index
.index(indexName)
.id("3")
.document(fieldMap)
)
);
}
{
bulkRequest.operations(operations -> operations
.delete(delete -> delete
.index(indexName)
.id("2")
)
);
}
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 3);
fieldMap.put("vector1", new float[]{2.2f,3.3f,4.4f});
bulkRequest.operations(operations -> operations
.update(update -> update
.index(indexName)
.id("1")
.document(fieldMap)
)
);
}
bulkRequest.refresh(Refresh.True);
BulkResponse bulkResponse = client.bulk(bulkRequest.build());
Java High Level Rest Client
BulkRequest bulkRequest = new BulkRequest();
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{2.2f,2.3f,2.4f});
IndexRequest indexRequest = new IndexRequest("vector_test");
indexRequest.id("1");
indexRequest.source(fieldMap);
bulkRequest.add(indexRequest);
}
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 1);
fieldMap.put("vector1", new float[]{2.2f,2.3f,2.4f});
IndexRequest indexRequest = new IndexRequest("vector_test");
indexRequest.id("2");
indexRequest.source(fieldMap);
bulkRequest.add(indexRequest);
}
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 2);
fieldMap.put("vector1", new float[]{1.2f,1.3f,4.4f});
IndexRequest indexRequest = new IndexRequest("vector_test");
indexRequest.id("3");
indexRequest.source(fieldMap);
bulkRequest.add(indexRequest);
}
{
DeleteRequest deleteRequest = new DeleteRequest("vector_test", "2");
bulkRequest.add(deleteRequest);
}
{
Map<String, Object> fieldMap = new HashMap<>();
fieldMap.put("field1", 3);
fieldMap.put("vector1", new float[]{2.2f,3.3f,4.4f});
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.index("vector_test");
updateRequest.id("1");
updateRequest.doc(fieldMap);
bulkRequest.add(updateRequest);
}
BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
数据查询
查询向量数据时需要在查询请求中加入knn
结构,并通过ext
结构提供相关查询参数。knn
、ext
结构细节及其参数说明,请参见参数说明。
使用Java Client查询时,可直接使用
knn
和ext
结构。使用Java High Level REST Client查询数据时,可通过
wrapper
查询传递knn
结构,通过SearchExtBuilder
父类传递ext
结构。
纯向量数据查询
只查询向量字段的数据,可直接使用knn
结构的基本形式。以下示例中查询vector1
字段中与向量[2.3, 3.3, 4.4]
相关的前10条数据,并要求最小得分为0.8。
Java Client
Map<String, Object> ext = new HashMap<>();
ext.put("min_score", "0.8");
SearchResponse<JsonData> searchResponse = client.search(request -> request
.index("vector_test")
.query(query -> query
.knn(knn -> knn
.field("vector1")
.vector(2.3f, 3.3f, 4.4f)
.k(10)
)
)
.ext("lvector", JsonData.of(ext))
, JsonData.class
);
Java High Level Rest Client
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
Map<String, Object> knn = new HashMap<>();
Map<String, Object> vector1 = new HashMap<>();
vector1.put("vector", new float[]{2.2f,3.3f,4.4f});
vector1.put("k", 10);
knn.put("vector1", vector1);
queryBody.put("knn", knn);
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = new HashMap<>();
ext.put("min_score", "0.8");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
融合查询
向量数据的查询可与普通数据的查询条件结合,并返回综合的查询结果。
Pre-Filter近似查询
在knn
查询结构内添加filter
结构,并指定filter_type参数为pre_filter
,可实现先过滤普通数据,再查询向量数据。
Java Client
Map<String, Object> ext = new HashMap<>();
ext.put("filter_type", "pre_filter");
SearchResponse<JsonData> searchResponse = client.search(request -> request
.index(indexName)
.query(query -> query
.knn(knn -> knn
.field("vector1")
.vector(2.3f, 3.3f, 4.4f)
.k(10)
.filter(Query.of(filter -> filter
.range(range-> range
.field("field1")
.gte(JsonData.of(0))
)
))
)
)
.ext("lvector", JsonData.of(ext))
, JsonData.class
);
Java High Level Rest Client
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
Map<String, Object> knn = new HashMap<>();
Map<String, Object> vector1 = new HashMap<>();
vector1.put("vector", new float[]{2.2f,3.3f,4.4f});
vector1.put("k", 10);
Map<String, Object> filter = new HashMap<>();
Map<String, Object> range = new HashMap<>();
Map<String, Object> field1 = new HashMap<>();
field1.put("gte", 0);
range.put("field1", field1);
filter.put("range", range);
vector1.put("filter", filter);
knn.put("vector1", vector1);
queryBody.put("knn", knn);
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = new HashMap<>();
ext.put("filter_type", "pre_filter");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
Post-Filter近似查询
在knn
查询结构内添加filter
结构,并指定filter_type参数为post_filter
,可实现先查询向量数据,再过滤普通数据。
Java Client
Map<String, Object> ext = new HashMap<>();
ext.put("filter_type", "post_filter");
SearchResponse<JsonData> searchResponse = client.search(request -> request
.index(indexName)
.query(query -> query
.knn(knn -> knn
.field("vector1")
.vector(2.3f, 3.3f, 4.4f)
.k(10)
.filter(Query.of(filter -> filter
.range(range-> range
.field("field1")
.gte(JsonData.of(0))
)
))
)
)
.ext("lvector", JsonData.of(ext))
, JsonData.class
);
Java High Level Rest Client
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
{
Map<String, Object> knn = new HashMap<>();
Map<String, Object> vector1 = new HashMap<>();
vector1.put("vector", new float[]{2.2f,3.3f,4.4f});
vector1.put("k", 10);
Map<String, Object> filter = new HashMap<>();
Map<String, Object> range = new HashMap<>();
Map<String, Object> field1 = new HashMap<>();
field1.put("gte", 0);
range.put("field1", field1);
filter.put("range", range);
vector1.put("filter", filter);
knn.put("vector1", vector1);
queryBody.put("knn", knn);
}
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
Map<String, String> ext = new HashMap<>();
ext.put("filter_type", "post_filter");
searchSourceBuilder.ext(Collections.singletonList(new LVectorExtBuilder("lvector", ext)));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
您也可以通过Post Filter结构添加过滤条件,实现Post-Filter近似查询。
Java Client
SearchResponse<JsonData> searchResponse = client.search(request -> request
.index(indexName)
.query(query -> query
.knn(knn -> knn
.field("vector1")
.vector(2.3f, 3.3f, 4.4f)
.k(10)
)
)
.postFilter(filter -> filter
.range(range-> range
.field("field1")
.gte(JsonData.of(0))
)
)
, JsonData.class
);
Java High Level Rest Client
SearchRequest searchRequest = new SearchRequest();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String, Object> queryBody = new HashMap<>();
Map<String, Object> knn = new HashMap<>();
Map<String, Object> vector1 = new HashMap<>();
vector1.put("vector", new float[]{2.2f,3.3f,4.4f});
vector1.put("k", 10);
knn.put("vector1", vector1);
queryBody.put("knn", knn);
searchSourceBuilder.query(QueryBuilders.wrapperQuery(new Gson().toJson(queryBody)));
searchSourceBuilder.postFilter(QueryBuilders.rangeQuery("field1").gte(0));
searchRequest.source(searchSourceBuilder);
searchRequest.indices("vector_test");
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
删除向量索引
向量索引的删除方式与普通索引的删除方式一致。
Java Client
DeleteIndexRequest deleteIndexRequest = DeleteIndexRequest.of(request -> request
.index("vector_test")
);
DeleteIndexResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest);
Java High Level Rest Client
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
AcknowledgedResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);