Elasticsearch 查询到 Milvus

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

本文旨在帮助您将代码库从 Elasticsearch 迁移到 Milvus,并提供中间转换查询的各种示例。

概述

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

下表列出了一些 Elasticsearch 查询模式及其在 Milvus 中的对应模式。

Elasticsearch 查询

Milvus 对应模式

备注

全文查询

匹配查询

全文搜索

两者提供类似的功能。

术语级查询

ID

in 操作符

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

前缀查询

like 操作符

范围查询

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

术语查询

比较操作符,如==

术语查询

in 操作符

通配符查询

like 操作符

布尔查询

逻辑操作符,如AND

在过滤器上下文中使用时,这两种操作符都能提供类似的功能。

向量查询

kNN 查询

搜索

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

互易等级融合

混合搜索

Milvus 支持多种 Rerankers 策略。

全文本查询

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

匹配查询

在 Elasticsearch 中,匹配查询会返回与所提供的文本、数字、日期或布尔值相匹配的文档。在匹配之前会对所提供的文本进行分析。

下面是一个使用匹配查询的 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 字段衍生而来。Milvus 使用 BM25 嵌入模型将message 字段中的值转换为稀疏向量嵌入,并将其存储在message_sparse 字段中。收到搜索请求后,Milvus 会使用相同的 BM25 模型嵌入纯文本查询有效载荷,并执行稀疏向量搜索,然后返回output_fields 参数中指定的idmessage 字段以及相应的相似性分数。

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

术语级查询

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

ID

在 Elasticsearch 中,你可以在过滤器上下文中根据 ID 查找文件,如下所示:

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

在 Milvus 中,你也可以根据 ID 查找实体,如下所示:

# Use the filter parameter
res = client.query(
    collection_name="my_collection",
    filter="id in [1, 4, 100]",
    output_fields=["id", "title"]
)

# Use the ids parameter
res = client.query(
    collection_name="my_collection",
    ids=[1, 4, 100],
    output_fields=["id", "title"]
)

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

前缀查询

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

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

在 Milvus 中,你可以按如下方式查找其值以指定前缀开头的实体:

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

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

范围查询

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

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

在 Milvus 中,你可以按如下方式查找特定字段中的值在所提供范围内的实体:

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

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

术语查询

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

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

在 Milvus 中,您可以按如下方式查找指定字段中的值正好是指定术语的实体:

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

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

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

术语查询

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

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

Milvus 没有与此完全等价的词。不过,您可以按如下方式查找指定字段中的值为指定术语之一的实体:

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

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

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

通配符查询

在 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 中范围操作符的详细信息,请参阅范围操作符

布尔查询

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

下面的示例改编自本页 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"]
)

上面的示例假定在目标 Collections 中有一个VarChar类型的user 字段和一个Array类型的tags 字段。查询将返回名称中包含kimchy 的用户,并带有production 标记。

向量查询

在 Elasticsearch 中,向量查询是对向量字段进行处理以有效执行语义搜索的专门查询。

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 使用索引类型来优化向量搜索。通常,它优先考虑对高维向量数据进行近似近邻(ANN)搜索。虽然使用 FLAT 索引类型的暴力 kNN 搜索能得到精确的结果,但它既耗时又耗资源。相比之下,使用 AUTOINDEX 或其他索引类型的 ANN 搜索能在速度和精确度之间取得平衡,其性能明显比 kNN 更快、更节省资源。

在 Mlivus 中,与上述向量查询类似的等价关系是这样的:

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

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

互惠排名融合

Elasticsearch 提供互惠排名融合 (RRF),可将具有不同相关性指标的多个结果集合并为一个排名结果集。

下面的示例演示了如何将传统的基于术语的搜索与 k-nearest neighbors (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],  # Example vector; replace with your actual query vector
                            "k": 50,
                            "num_candidates": 100
                        }
                    }
                ],
                "rank_window_size": 50,
                "rank_constant": 20
            }
        }
    }
)

在这个例子中,RRF 将两个检索器的结果结合在一起:

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

  • 使用提供的查询向量对vector 字段进行 kNN 检索。

每个检索器最多可贡献 50 个最匹配结果,RRF 会对这些结果进行重新排序,并返回最终的前 10 个结果。

在 Milvus 中,您可以通过组合多个向量字段的搜索、应用重新排序策略并从组合列表中检索前 K 结果来实现类似的混合搜索。Milvus 支持 RRF 和加权重排序策略。更多详情,请参阅Rerankers

下面是上述 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",
    }
}

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)度量,将nprobe 设置为 10,在vector 字段上进行近似近邻(ANN)搜索。

  2. 稀疏向量搜索:在text_sparse 字段上使用 BM25 相似度指标。

这些搜索的结果分别执行、合并,并使用 Riprocal Rank Fusion (RRF) 排序器重新排序。混合搜索会从重新排序的列表中返回前 10 个实体。

与 Elasticsearch 的 RRF 排序器(它将标准文本查询和 kNN 搜索的结果合并在一起)不同,Milvus 将稀疏向量搜索和密集向量搜索的结果合并在一起,提供了一种针对多模态数据优化的独特混合搜索能力。

回顾

在本文中,我们介绍了将典型 Elasticsearch 查询转换为 Milvus 对应查询的方法,包括术语级查询、布尔查询、全文查询和向量查询。如果您对其他 Elasticsearch 查询的转换有进一步的问题,请随时联系我们。

想要更快、更简单、更好用的 Milvus SaaS服务 ?

Zilliz Cloud是基于Milvus的全托管向量数据库,拥有更高性能,更易扩展,以及卓越性价比

免费试用 Zilliz Cloud
反馈

此页对您是否有帮助?