Consultas Elasticsearch para Milvus

O Elasticsearch, criado com base no Apache Lucene, é um dos principais motores de pesquisa de código aberto. No entanto, enfrenta desafios nas aplicações modernas de IA, incluindo elevados custos de atualização, fraco desempenho em tempo real, gestão ineficiente de fragmentos, um design não nativo da nuvem e exigências excessivas de recursos. Como uma base de dados vetorial nativa da nuvem, o Milvus supera estes problemas com armazenamento e computação dissociados, indexação eficiente para dados de elevada dimensão e integração perfeita com infra-estruturas modernas. Oferece desempenho e escalabilidade superiores para cargas de trabalho de IA.

Este artigo tem como objetivo facilitar a migração da sua base de código do Elasticsearch para o Milvus, fornecendo vários exemplos de conversão de consultas no meio.

Visão geral

No Elasticsearch, as operações no contexto da consulta geram pontuações de relevância, enquanto as do contexto do filtro não. Da mesma forma, as pesquisas do Milvus produzem pontuações de semelhança, enquanto as consultas do tipo filtro não o fazem. Ao migrar a sua base de código do Elasticsearch para o Milvus, o princípio fundamental é converter os campos utilizados no contexto de consulta do Elasticsearch em campos vectoriais para permitir a geração de pontuações de similaridade.

A tabela abaixo descreve alguns padrões de consulta do Elasticsearch e os seus equivalentes correspondentes no Milvus.

Consultas Elasticsearch

Equivalentes em Milvus

Observações

Consultas de texto completo

Consulta de correspondência

Pesquisa de texto integral

Ambos fornecem conjuntos de capacidades semelhantes.

Consultas ao nível do termo

IDs

in operador

Ambas fornecem o mesmo conjunto de recursos ou um conjunto semelhante quando essas consultas do Elasticsearch são usadas no contexto do filtro.

Consulta de prefixo

like operador

Consulta de intervalo

Operadores de comparação como >, <, >=, e <=

Consulta de termo

Operadores de comparação como ==

Consulta de termos

in operador

Operador de consulta curinga

like operador

Consulta booleana

Operadores lógicos como AND

Ambos fornecem conjuntos semelhantes de capacidades quando utilizados no contexto do filtro.

Consultas vectoriais

Consulta kNN

Pesquisa

O Milvus fornece capacidades de pesquisa vetorial mais avançadas.

Fusão de classificação recíproca

Pesquisa híbrida

Milvus suporta múltiplas estratégias de reranking.

Consultas de texto integral

No Elasticsearch, as consultas de texto completo permitem-lhe pesquisar campos de texto analisados, como o corpo de um e-mail. A cadeia de consulta é processada utilizando o mesmo analisador que foi aplicado ao campo durante a indexação.

Consulta de correspondência

No Elasticsearch, uma consulta de correspondência retorna documentos que correspondem a um texto, número, data ou valor booleano fornecido. O texto fornecido é analisado antes da correspondência.

O seguinte é um exemplo de pedido de pesquisa do Elasticsearch com uma consulta de correspondência.

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

O Milvus fornece a mesma capacidade através da funcionalidade de pesquisa de texto integral. Pode converter a consulta Elasticsearch acima em Milvus da seguinte forma:

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

No exemplo acima, message_sparse é um campo vetorial esparso derivado de um campo VarChar denominado message. O Milvus usa o modelo de incorporação BM25 para converter os valores no campo message em incorporação de vetor esparso e os armazena no campo message_sparse. Ao receber o pedido de pesquisa, o Milvus incorpora a carga útil da consulta de texto simples utilizando o mesmo modelo BM25 e efectua uma pesquisa de vetor esparso e devolve os campos id e message especificados no parâmetro output_fields juntamente com as pontuações de semelhança correspondentes.

Para usar essa funcionalidade, você deve habilitar o analisador no campo message e definir uma função para derivar o campo message_sparse a partir dele. Para obter instruções detalhadas sobre como ativar o analisador e criar a função derivada no Milvus, consulte Pesquisa de texto integral.

Consultas no nível do termo

No Elasticsearch, as consultas de nível de termo são utilizadas para encontrar documentos com base em valores exactos em dados estruturados, tais como intervalos de datas, endereços IP, preços ou IDs de produtos. Esta secção descreve os possíveis equivalentes de algumas consultas de nível de termo do Elasticsearch no Milvus. Todos os exemplos nesta secção são adaptados para funcionarem no contexto do filtro para se alinharem com as capacidades do Milvus.

IDs

No Elasticsearch, pode encontrar documentos com base nos respectivos IDs no contexto de filtro da seguinte forma:

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

No Milvus, também pode encontrar entidades com base nos seus IDs da seguinte forma:

# 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"]
)

Pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre os pedidos de query e get, bem como sobre as expressões de filtro no Milvus, consulte Query and Filtering(Consulta e filtragem).

Consulta de prefixo

No Elasticsearch, pode encontrar documentos que contenham um prefixo específico num campo fornecido no contexto do filtro da seguinte forma:

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

No Milvus, pode encontrar as entidades cujos valores começam com o prefixo especificado da seguinte forma:

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

Pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre o operador like no Milvus, consulte Usando LIKE para correspondência de padrões.

Consulta de intervalo

No Elasticsearch, é possível encontrar documentos que contenham termos dentro de um intervalo fornecido da seguinte forma:

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

No Milvus, pode encontrar as entidades cujos valores num campo específico estão dentro de um intervalo fornecido da seguinte forma:

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

Pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre os operadores de comparação no Milvus, consulte Operadores de comparação.

Consulta de termo

No Elasticsearch, pode encontrar documentos que contenham um termo exato num campo fornecido da seguinte forma:

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

No Milvus, pode encontrar as entidades cujos valores no campo especificado são exatamente o termo especificado da seguinte forma:

# 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"]
)

Pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre os operadores de comparação no Milvus, consulte Operadores de comparação.

Consulta de termos

No Elasticsearch, é possível encontrar documentos que contenham um ou mais termos exactos num campo fornecido da seguinte forma:

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

O Milvus não tem uma equivalência completa desta. No entanto, pode encontrar as entidades cujos valores no campo especificado são um dos termos especificados da seguinte forma:

# 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"]
)

Pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre os operadores de intervalo no Milvus, consulte Operadores de intervalo.

Consulta curinga

No Elasticsearch, é possível encontrar documentos que contenham termos que correspondam a um padrão curinga da seguinte forma:

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

O Milvus não oferece suporte a curingas em suas condições de filtragem. No entanto, pode utilizar o operador like para obter um efeito semelhante da seguinte forma:

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

Você pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre os operadores de intervalo no Milvus, consulte Operadores de intervalo.

Consulta booleana

No Elasticsearch, uma consulta booleana é uma consulta que corresponde a documentos que correspondem a combinações booleanas de outras consultas.

O exemplo a seguir é adaptado de um exemplo na documentação do Elasticsearch nesta página. A consulta devolverá os utilizadores com kimchy nos seus nomes com uma etiqueta production.

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

No Milvus, pode fazer algo semelhante da seguinte forma:

filter = 

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

O exemplo acima pressupõe que tem um campo user do tipo VarChar e um campo tags do tipo Array, na coleção de destino. A consulta devolverá os utilizadores com kimchy nos seus nomes com uma etiqueta production.

Consultas vetoriais

No Elasticsearch, as consultas de vetor são consultas especializadas que funcionam em campos de vetor para executar com eficiência a pesquisa semântica.

Consulta Knn

O Elasticsearch oferece suporte a consultas kNN aproximadas e a consultas kNN exatas e de força bruta. É possível encontrar os k vetores mais próximos de um vetor de consulta de qualquer maneira, conforme medido por uma métrica de similaridade, da seguinte forma:

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

O Milvus, como uma base de dados especializada em vectores, utiliza tipos de índices para otimizar as pesquisas de vectores. Normalmente, dá prioridade à pesquisa do vizinho mais próximo aproximado (ANN) para dados vectoriais de elevada dimensão. Embora a pesquisa kNN de força bruta com o tipo de índice FLAT forneça resultados precisos, é demorada e consome muitos recursos. Em contrapartida, a pesquisa ANN utilizando AUTOINDEX ou outros tipos de índice equilibra velocidade e precisão, oferecendo um desempenho significativamente mais rápido e eficiente em termos de recursos do que o kNN.

Uma equivalência semelhante à consulta de vetor acima no Mlivus é a seguinte:

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

Pode encontrar o exemplo do Elasticsearch nesta página. Para obter detalhes sobre pesquisas ANN no Milvus, leia Pesquisa ANN básica.

Fusão de classificação recíproca

O Elasticsearch fornece o Reciprocal Rank Fusion (RRF) para combinar vários conjuntos de resultados com diferentes indicadores de relevância em um único conjunto de resultados classificados.

O exemplo a seguir demonstra a combinação de uma busca tradicional baseada em termos com uma busca vetorial de k vizinhos mais próximos (kNN) para melhorar a relevância da busca:

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
            }
        }
    }
)

Neste exemplo, a RRF combina resultados de dois recuperadores:

  • Uma pesquisa padrão baseada em termos para documentos que contêm o termo "shoes" no campo text.

  • Uma pesquisa kNN no campo vector usando o vetor de consulta fornecido.

Cada recuperador contribui com até 50 correspondências de topo, que são reavaliadas pela RRF, e os 10 resultados finais de topo são devolvidos.

No Milvus, é possível obter uma pesquisa híbrida semelhante combinando pesquisas em vários campos vetoriais, aplicando uma estratégia de classificação e recuperando os resultados top-K da lista combinada. O Milvus suporta as estratégias RRF e reranker ponderado. Para mais detalhes, consulte Reranking.

O seguinte é uma equivalência não estrita do exemplo Elasticsearch acima em 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
)

Este exemplo demonstra uma pesquisa híbrida no Milvus que combina:

  1. Pesquisa de vetor denso: Usando a métrica de produto interno (IP) com nprobe definido como 10 para busca aproximada do vizinho mais próximo (ANN) no campo vector.

  2. Pesquisa de vectores esparsos: Usando a métrica de similaridade BM25 no campo text_sparse.

Os resultados destas pesquisas são executados separadamente, combinados e reavaliados utilizando o classificador Reciprocal Rank Fusion (RRF). A busca híbrida retorna as 10 principais entidades da lista ranqueada.

Ao contrário da classificação RRF do Elasticsearch, que mescla resultados de consultas baseadas em texto padrão e buscas kNN, o Milvus combina resultados de buscas vetoriais esparsas e densas, fornecendo um recurso exclusivo de busca híbrida otimizado para dados multimodais.

Recapitulação

Neste artigo, abordamos as conversões de consultas típicas do Elasticsearch para seus equivalentes no Milvus, incluindo consultas no nível do termo, consultas booleanas, consultas de texto completo e consultas de vetor. Se tiver mais perguntas sobre a conversão de outras consultas do Elasticsearch, não hesite em contactar-nos.