Milvus에 대한 Elasticsearch 쿼리

Apache Lucene을 기반으로 구축된 Elasticsearch는 선도적인 오픈 소스 검색 엔진입니다. 그러나 높은 업데이트 비용, 낮은 실시간 성능, 비효율적인 샤드 관리, 클라우드 네이티브가 아닌 설계, 과도한 리소스 요구 등 최신 AI 애플리케이션에서 직면하고 있는 문제에 직면해 있습니다. 클라우드 네이티브 벡터 데이터베이스인 Milvus는 분리된 스토리지 및 컴퓨팅, 고차원 데이터를 위한 효율적인 인덱싱, 최신 인프라와의 원활한 통합을 통해 이러한 문제를 극복합니다. 또한 AI 워크로드를 위한 뛰어난 성능과 확장성을 제공합니다.

이 문서에서는 코드 기반을 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_sparsemessage 이라는 이름의 VarChar 필드에서 파생된 스파스 벡터 필드입니다. Milvus는 BM25 임베딩 모델을 사용하여 message 필드의 값을 스파스 벡터 임베딩으로 변환하고 message_sparse 필드에 저장합니다. 검색 요청을 받으면 Milvus는 동일한 BM25 모델을 사용하여 일반 텍스트 쿼리 페이로드를 임베딩하고 스파스 벡터 검색을 수행하여 output_fields 파라미터에 지정된 idmessage 필드를 해당 유사도 점수와 함께 반환합니다.

이 기능을 사용하려면 message 필드에서 분석기를 활성화하고 이 필드에서 message_sparse 필드를 도출하는 함수를 정의해야 합니다. 분석기를 활성화하고 Milvus에서 파생 함수를 만드는 방법에 대한 자세한 지침은 전체 텍스트 검색을 참조하세요.

용어 수준 쿼리

Elasticsearch에서 용어 수준 쿼리는 날짜 범위, IP 주소, 가격 또는 제품 ID와 같은 구조화된 데이터의 정확한 값을 기반으로 문서를 찾는 데 사용됩니다. 이 섹션에서는 Milvus에서 일부 Elasticsearch 용어 수준 쿼리의 가능한 등가물에 대해 간략하게 설명합니다. 이 섹션의 모든 예제는 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의 쿼리 및 get 요청과 필터 표현식에 대한 자세한 내용은 쿼리필터링을 참조하세요.

접두사 쿼리

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 설명서에 있는 예제에서 수정한 것입니다. 이 쿼리는 이름에 production 태그가 있는 kimchy 사용자를 반환합니다.

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 필드가 있다고 가정합니다. 이 쿼리는 이름에 production 태그가 있는 kimchy 사용자를 반환합니다.

벡터 쿼리

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-NN(k-근접 이웃) 벡터 검색을 결합하는 방법을 보여줍니다:

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와 가중치 재랭커 전략을 모두 지원합니다. 자세한 내용은 재랭크하기를 참조하세요.

다음은 위의 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. 고밀도 벡터 검색: vector 필드에서 근사 근사 이웃(ANN) 검색을 위해 nprobe 을 10으로 설정하여 내부 곱(IP) 메트릭을 사용합니다.

  2. 희소 벡터 검색: text_sparse 필드에서 BM25 유사성 메트릭을 사용합니다.

이러한 검색의 결과는 개별적으로 실행되고, 결합되며, 상호 순위 융합(RRF) 순위 매기기를 사용하여 다시 순위가 매겨집니다. 하이브리드 검색은 순위가 재조정된 목록에서 상위 10개 엔티티를 반환합니다.

표준 텍스트 기반 쿼리와 kNN 검색의 결과를 병합하는 Elasticsearch의 RRF 순위와는 달리, Milvus는 스파스 및 고밀도 벡터 검색의 결과를 결합하여 멀티모달 데이터에 최적화된 고유한 하이브리드 검색 기능을 제공합니다.

요약

이 문서에서는 용어 수준 쿼리, 부울 쿼리, 전체 텍스트 쿼리, 벡터 쿼리 등 일반적인 Elasticsearch 쿼리를 Milvus에 상응하는 쿼리로 변환하는 방법을 다루었습니다. 다른 Elasticsearch 쿼리 변환에 대해 더 궁금한 점이 있으시면 언제든지 문의해 주세요.