跳到主要内容

Elasticsearch 查询转换为 Milvus

Elasticsearch 基于 Apache Lucene 构建,是领先的开源搜索引擎。然而,它在现代 AI 应用中面临挑战,包括高更新成本、实时性能差、分片管理低效、非云原生设计以及过度的资源需求。作为云原生向量数据库,Milvus 通过解耦存储和计算、为高维数据提供高效索引以及与现代基础设施的无缝集成来克服这些问题。它为 AI 工作负载提供卓越的性能和可扩展性。

本文旨在促进您的代码库从 Elasticsearch 迁移到 Milvus,提供各种查询转换示例。

概述

在 Elasticsearch 中,查询上下文中的操作生成相关性分数,而过滤上下文中的操作则不会。类似地,Milvus 搜索产生相似性分数,而其类似过滤器的查询则不会。将代码库从 Elasticsearch 迁移到 Milvus 时,关键原则是将 Elasticsearch 查询上下文中使用的 field 转换为向量 field,以实现相似性分数生成。

下表概述了一些 Elasticsearch 查询模式及其在 Milvus 中的对应等价物。

Elasticsearch 查询

Milvus 等价物

备注

全文查询

Match 查询

全文搜索

两者提供类似的功能集。

Term 级查询

IDs

in 操作符

当这些 Elasticsearch 查询在过滤上下文中使用时,两者提供相同或类似的功能集。

Prefix 查询

like 操作符

Range 查询

比较操作符,如 ><>=<=

Term 查询

比较操作符,如 ==

Terms 查询

in 操作符

Wildcard 查询

like 操作符

Boolean 查询

逻辑操作符,如 AND

当在过滤上下文中使用时,两者提供类似的功能集。

向量查询

kNN 查询

搜索

Milvus 提供更高级的向量搜索功能。

倒数排名融合

混合搜索

Milvus 支持多种重排序策略。

全文查询

在 Elasticsearch 中,全文查询使您能够搜索分析的文本 field,例如电子邮件正文。查询字符串使用在索引期间应用于 field 的相同分析器进行处理。

Match 查询

在 Elasticsearch 中,match 查询返回匹配提供的文本、数字、日期或布尔值的文档。提供的文本在匹配前会被分析。

以下是带有 match 查询的 Elasticsearch 搜索请求示例。

resp = client.search(
query={
"match": {
"message": {
"query": "this is a test"
}
}
},
)

Milvus 通过全文搜索功能提供相同的能力。您可以将上述 Elasticsearch 查询转换为 Milvus,如下所示:

res = client.search(
collection_name="my_collection",
data=['How is the weather in Jamaica?'],
anns_field="message_sparse",
output_fields=["id", "message"]
)

在上述示例中,message_sparse 是从名为 message 的 VarChar field 派生的稀疏向量 field。Milvus 使用 BM25 嵌入模型将 message field 中的值转换为稀疏向量嵌入,并将它们存储在 message_sparse field 中。收到搜索请求时,Milvus 使用相同的 BM25 模型嵌入纯文本查询载荷,执行稀疏向量搜索并返回 output_fields 参数中指定的 idmessage field 以及相应的相似性分数。

要使用此功能,您必须在 message field 上启用分析器并定义一个函数来从中派生 message_sparse field。有关在 Milvus 中启用分析器和创建派生函数的详细说明,请参阅全文搜索

Term 级查询

在 Elasticsearch 中,term 级查询用于根据结构化数据中的精确值查找文档,例如日期范围、IP 地址、价格或产品 ID。本节概述了一些 Elasticsearch term 级查询在 Milvus 中的可能等价物。本节中的所有示例都适应在过滤上下文中操作,以与 Milvus 的功能保持一致。

IDs

在 Elasticsearch 中,您可以在过滤上下文中根据文档的 ID 查找文档,如下所示:

resp = client.search(
query={
"bool": {
"filter": {
"ids": {
"values": [
"1",
"4",
"100"
]
}
}
}
},
)

在 Milvus 中,您也可以根据 entity 的 ID 查找它们,如下所示:

# 使用 filter 参数
res = client.query(
collection_name="my_collection",
filter="id in [1, 4, 100]",
output_fields=["id", "title"]
)

# 使用 ids 参数
res = client.query(
collection_name="my_collection",
ids=[1, 4, 100],
output_fields=["id", "title"]
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中查询和获取请求以及过滤表达式的详细信息,请参阅查询过滤

Prefix 查询

在 Elasticsearch 中,您可以在过滤上下文中查找在提供的 field 中包含特定前缀的文档,如下所示:

resp = client.search(
query={
"bool": {
"filter": {
"prefix": {
"user": {
"value": "ki"
}
}
}
}
},
)

在 Milvus 中,您可以查找值以指定前缀开头的 entity,如下所示:

res = client.query(
collection_name="my_collection",
filter='user like "ki%"',
output_fields=["id", "user"]
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中 like 操作符的详细信息,请参阅使用 LIKE 进行模式匹配

Range 查询

在 Elasticsearch 中,您可以查找包含提供范围内术语的文档,如下所示:

resp = client.search(
query={
"bool": {
"filter": {
"range": {
"age": {
"gte": 10,
"lte": 20
}
}
}
}
},
)

在 Milvus 中,您可以查找特定 field 中的值在提供范围内的 entity,如下所示:

res = client.query(
collection_name="my_collection",
filter='10 <= age <= 20',
output_fields=["id", "user", "age"]
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中比较操作符的详细信息,请参阅比较操作符

Term 查询

在 Elasticsearch 中,您可以查找在提供的 field 中包含精确术语的文档,如下所示:

resp = client.search(
query={
"bool": {
"filter": {
"term": {
"status": {
"value": "retired"
}
}
}
}
},
)

在 Milvus 中,您可以查找指定 field 中的值与指定术语完全匹配的 entity,如下所示:

# 使用 ==
res = client.query(
collection_name="my_collection",
filter='status=="retired"',
output_fields=["id", "user", "status"]
)

# 使用 TEXT_MATCH
res = client.query(
collection_name="my_collection",
filter='TEXT_MATCH(status, "retired")',
output_fields=["id", "user", "status"]
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中比较操作符的详细信息,请参阅比较操作符

Terms 查询

在 Elasticsearch 中,您可以查找在提供的 field 中包含一个或多个精确术语的文档,如下所示:

resp = client.search(
query={
"bool": {
"filter": {
"terms": {
"degree": [
"graduate",
"post-graduate"
]
}
}
}
}
)

Milvus 没有完全等价的操作。但是,您可以查找指定 field 中的值是指定术语之一的 entity,如下所示:

# 使用 in
res = client.query(
collection_name="my_collection",
filter='degree in ["graduate", "post-graduate"]',
output_fields=["id", "user", "degree"]
)

# 使用 TEXT_MATCH
res = client.query(
collection_name="my_collection",
filter='TEXT_MATCH(degree, "graduate post-graduate")',
output_fields=["id", "user", "degree"]
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中范围操作符的详细信息,请参阅范围操作符

Wildcard 查询

在 Elasticsearch 中,您可以查找包含匹配通配符模式的术语的文档,如下所示:

resp = client.search(
query={
"bool": {
"filter": {
"wildcard": {
"user": {
"value": "ki*y"
}
}
}
}
},
)

Milvus 在其过滤条件中不支持通配符。但是,您可以使用 like 操作符实现类似的效果,如下所示:

res = client.query(
collection_name="my_collection",
filter='user like "ki%" AND user like "%y"',
output_fields=["id", "user"]
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中范围操作符的详细信息,请参阅范围操作符

Boolean 查询

在 Elasticsearch 中,boolean 查询是匹配其他查询的布尔组合的文档的查询。

以下示例改编自 Elasticsearch 文档中此页面的示例。查询将返回名字中包含 kimchy 且具有 production 标签的用户。

resp = client.search(
query={
"bool": {
"filter": {
"term": {
"user": "kimchy"
}
},
"filter": {
"term": {
"tags": "production"
}
}
}
},
)

在 Milvus 中,您可以执行类似的操作,如下所示:

filter = 

res = client.query(
collection_name="my_collection",
filter='user like "%kimchy%" AND ARRAY_CONTAINS(tags, "production")',
output_fields=["id", "user", "age", "tags"]
)

上述示例假设您在目标 collection 中有一个VarChar类型的 user field 和一个Array类型的 tags field。查询将返回名字中包含 kimchy 且具有 production 标签的用户。

向量查询

在 Elasticsearch 中,向量查询是在向量 field 上工作以高效执行语义搜索的专用查询。

Knn 查询

Elasticsearch 支持近似 kNN 查询和精确的暴力 kNN 查询。您可以通过任一方式找到查询向量的 k 个最近向量,通过相似性度量测量,如下所示:

resp = client.search(
index="my-image-index",
size=3,
query={
"knn": {
"field": "image-vector",
"query_vector": [
-5,
9,
-12
],
"k": 10
}
},
)

Milvus 作为专业的向量数据库,使用 index 类型来优化向量搜索。通常,它优先考虑高维向量数据的近似最近邻(ANN)搜索。虽然使用 FLAT index 类型的暴力 kNN 搜索可以提供精确结果,但它既耗时又占用资源。相比之下,使用 AUTOINDEX 或其他 index 类型的 ANN 搜索在速度和准确性之间取得平衡,提供比 kNN 显著更快、更节省资源的性能。

在 Milvus 中上述向量查询的类似等价物如下:

res = client.search(
collection_name="my_collection",
anns_field="image-vector"
data=[[-5, 9, -12]],
limit=10
)

您可以在此页面找到 Elasticsearch 示例。有关 Milvus 中 ANN 搜索的详细信息,请阅读基本 ANN 搜索

倒数排名融合

Elasticsearch 提供倒数排名融合(RRF)来将具有不同相关性指标的多个结果集合并为单个排名结果集。

以下示例演示了将传统基于术语的搜索与 k 最近邻(kNN)向量搜索相结合以提高搜索相关性:

client.search(
index="my_index",
size=10,
query={
"retriever": {
"rrf": {
"retrievers": [
{
"standard": {
"query": {
"term": {
"text": "shoes"
}
}
}
},
{
"knn": {
"field": "vector",
"query_vector": [1.25, 2, 3.5], # 示例向量;用您的实际查询向量替换
"k": 50,
"num_candidates": 100
}
}
],
"rank_window_size": 50,
"rank_constant": 20
}
}
}
)

在此示例中,RRF 合并了来自两个检索器的结果:

  • text field 中包含术语 "shoes" 的文档进行标准基于术语的搜索。

  • 使用提供的查询向量对 vector field 进行 kNN 搜索。

每个检索器贡献最多 50 个顶部匹配项,这些匹配项由 RRF 重新排名,并返回最终的前 10 个结果。

在 Milvus 中,您可以通过结合跨多个向量 field 的搜索、应用重排序策略并从合并列表中检索 top-K 结果来实现类似的混合搜索。Milvus 支持 RRF 和加权重排序器策略。有关更多详细信息,请参阅重排序

以下是上述 Elasticsearch 示例在 Milvus 中的非严格等价物。

search_params_dense = {
"data": [[1.25, 2, 3.5]],
"anns_field": "vector",
"param": {
"metric_type": "IP",
"params": {"nprobe": 10},
},
"limit": 100
}

req_dense = ANNSearchRequest(**search_params_dense)

search_params_sparse = {
"data": ["shoes"],
"anns_field": "text_sparse",
"param": {
"metric_type": "BM25",
"params": {"drop_ratio_search": 0.2}
}
}

req_sparse = ANNSearchRequest(**search_params_sparse)

res = client.hybrid_search(
collection_name="my_collection",
reqs=[req_dense, req_sparse],
reranker=RRFRanker(),
limit=10
)

此示例演示了 Milvus 中的混合搜索,它结合了:

  1. 密集向量搜索:使用内积(IP)度量,在 vector field 上设置 nprobe 为 10 进行近似最近邻(ANN)搜索。

  2. 稀疏向量搜索:使用 BM25 相似性度量,在 text_sparse field 上设置 drop_ratio_search 参数为 0.2。

来自这些搜索的结果被分别执行、合并并使用倒数排名融合(RRF)排序器重新排名。混合搜索从重新排名的列表中返回前 10 个 entity。

与 Elasticsearch 的 RRF 排名(合并来自标准基于文本的查询和 kNN 搜索的结果)不同,Milvus 结合了来自稀疏和密集向量搜索的结果,为多模态数据提供了独特的混合搜索功能优化。

总结

在本文中,我们涵盖了典型 Elasticsearch 查询转换为其 Milvus 等价物的内容,包括 term 级查询、boolean 查询、全文查询和向量查询。如果您对转换其他 Elasticsearch 查询有进一步的问题,请随时与我们联系。