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 支援多種重排策略。

全文本查詢

在 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 是一個由 VarChar 欄位衍生出來的稀疏向量欄位,其名稱為message 。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"]
)

上述範例假設您在目標集合中有一個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 搜尋的詳細資訊,請閱讀Basic ANN Search

互惠排名融合

Elasticsearch 提供 Reciprocal Rank Fusion (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 中,您可以透過結合跨多個向量欄位的搜尋、套用重新排序策略,並從結合清單中擷取 Top-K 結果,來達到類似混合搜尋的目的。Milvus 支援 RRF 和加權 reranker 策略。如需詳細資訊,請參閱Reranking

以下是上述 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. 密集向量搜尋:使用nprobe 設定為 10 的內積 (IP) 公制,在vector 欄位上進行近似最近鄰 (ANN) 搜尋。

  2. 稀疏向量搜尋:在text_sparse 欄位上使用 BM25 相似度指標。

這些搜尋的結果會分別執行、合併,並使用 Reciprocal Rank Fusion (RRF) 排序器重新排序。混合搜尋會返回重新排序清單中的前 10 個實體。

不同於 Elasticsearch 的 RRF 排序會合併標準文字式查詢和 kNN 搜尋的結果,Milvus 會合併稀疏和密集向量搜尋的結果,提供獨特的混合搜尋功能,針對多模式資料進行最佳化。

重溫

在這篇文章中,我們涵蓋了典型 Elasticsearch 查詢與 Milvus 等效查詢的轉換,包括術語級查詢、布林查詢、全文查詢和向量查詢。如果您對於轉換其他 Elasticsearch 查詢有進一步的問題,請隨時聯絡我們。