Consultas de Elasticsearch a Milvus

Elasticsearch, basado en Apache Lucene, es uno de los principales motores de búsqueda de código abierto. Sin embargo, se enfrenta a retos en las aplicaciones modernas de IA, como los altos costes de actualización, el bajo rendimiento en tiempo real, la gestión ineficaz de fragmentos, un diseño no nativo de la nube y una demanda excesiva de recursos. Como base de datos vectorial nativa de la nube, Milvus supera estos problemas con almacenamiento y computación desacoplados, indexación eficiente para datos de alta dimensión e integración perfecta con infraestructuras modernas. Ofrece un rendimiento y una escalabilidad superiores para cargas de trabajo de IA.

Este artículo tiene como objetivo facilitar la migración de su base de código de Elasticsearch a Milvus, proporcionando varios ejemplos de conversión de consultas en el medio.

Visión general

En Elasticsearch, las operaciones en el contexto de consulta generan puntuaciones de relevancia, mientras que las del contexto de filtro no. Del mismo modo, las búsquedas Milvus producen puntuaciones de similitud, mientras que sus consultas de tipo filtro no lo hacen. Al migrar su base de código de Elasticsearch a Milvus, el principio clave es convertir los campos utilizados en el contexto de consulta de Elasticsearch en campos vectoriales para permitir la generación de puntuaciones de similitud.

La siguiente tabla describe algunos patrones de consulta de Elasticsearch y sus correspondientes equivalentes en Milvus.

Consultas Elasticsearch

Equivalentes en Milvus

Observaciones

Consultas de texto completo

Consulta de coincidencia

Búsqueda de texto completo

Ambas ofrecen funciones similares.

Consultas a nivel de término

ID

in operador

Ambos proporcionan el mismo o similar conjunto de capacidades cuando estas consultas Elasticsearch se utilizan en el contexto de filtro.

Consulta de prefijo

like operador

Consulta de rango

Operadores de comparación como >, <, >=, y <=

Consulta de términos

Operadores de comparación como ==

Consulta de términos

in operador

Consulta con comodín

like operador

Consulta booleana

Operadores lógicos como AND

Ambos ofrecen funciones similares cuando se utilizan en el contexto de un filtro.

Consultas vectoriales

Consulta kNN

Búsqueda

Milvus proporciona capacidades de búsqueda vectorial más avanzadas.

Fusión recíproca de rangos

Búsqueda híbrida

Milvus admite múltiples estrategias de reordenación.

Consultas de texto completo

En Elasticsearch, las consultas de texto completo permiten buscar en campos de texto analizados, como el cuerpo de un correo electrónico. La cadena de consulta se procesa utilizando el mismo analizador que se aplicó al campo durante la indexación.

Consulta de coincidencia

En Elasticsearch, una consulta de coincidencia devuelve documentos que coinciden con un texto, número, fecha o valor booleano proporcionado. El texto proporcionado se analiza antes de realizar la coincidencia.

A continuación se muestra un ejemplo de solicitud de búsqueda en Elasticsearch con una consulta de coincidencia.

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

Milvus proporciona la misma capacidad a través de la función de búsqueda de texto completo. Puede convertir la consulta de Elasticsearch anterior en Milvus de la siguiente manera:

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

En el ejemplo anterior, message_sparse es un campo vectorial disperso derivado de un campo VarChar llamado message. Milvus utiliza el modelo de incrustación BM25 para convertir los valores del campo message en incrustaciones de vectores dispersos y los almacena en el campo message_sparse. Al recibir la petición de búsqueda, Milvus incrusta la carga útil de la consulta en texto plano utilizando el mismo modelo BM25 y realiza una búsqueda de vectores dispersos y devuelve los campos id y message especificados en el parámetro output_fields junto con las puntuaciones de similitud correspondientes.

Para utilizar esta funcionalidad, debe activar el analizador en el campo message y definir una función para derivar el campo message_sparse a partir de él. Para obtener instrucciones detalladas sobre cómo habilitar el analizador y crear la función derivada en Milvus, consulte Búsqueda de texto completo.

Consultas a nivel de término

En Elasticsearch, las consultas a nivel de término se utilizan para encontrar documentos basados en valores exactos en datos estructurados, como intervalos de fechas, direcciones IP, precios o ID de productos. Esta sección describe los posibles equivalentes de algunas consultas a nivel de término de Elasticsearch en Milvus. Todos los ejemplos de esta sección están adaptados para operar dentro del contexto del filtro para alinearse con las capacidades de Milvus.

IDs

En Elasticsearch, puede encontrar documentos basándose en sus IDs en el contexto de filtrado como se indica a continuación:

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

En Milvus, también puede encontrar entidades basadas en sus IDs como sigue:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre las peticiones query y get así como las expresiones de filtrado en Milvus, consulte Consulta y filtrado.

Consulta de prefijo

En Elasticsearch, puede encontrar documentos que contengan un prefijo específico en un campo proporcionado en el contexto de filtrado de la siguiente manera:

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

En Milvus, puede encontrar las entidades cuyos valores comienzan con el prefijo especificado de la siguiente manera:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre el operador like en Milvus, consulte Uso deLIKE para la concordancia de patrones.

Consulta de rango

En Elasticsearch, puede encontrar documentos que contengan términos dentro de un rango proporcionado como sigue:

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

En Milvus, puede encontrar las entidades cuyos valores en un campo específico están dentro de un rango proporcionado de la siguiente manera:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre los operadores de comparación en Milvus, consulte Operadores de comparación.

Consulta de términos

En Elasticsearch, puede encontrar documentos que contengan un término exacto en un campo proporcionado como sigue:

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

En Milvus, puede encontrar las entidades cuyos valores en el campo especificado son exactamente el término especificado como sigue:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre los operadores de comparación en Milvus, consulte Operadores de comparación.

Consulta de términos

En Elasticsearch, puede encontrar documentos que contengan uno o más términos exactos en un campo proporcionado de la siguiente manera:

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

Milvus no tiene una equivalencia completa de éste. Sin embargo, puede encontrar las entidades cuyos valores en el campo especificado sean uno de los términos especificados de la siguiente manera:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre los operadores de rango en Milvus, consulte Operadores de rango.

Consulta comodín

En Elasticsearch, puede encontrar documentos que contengan términos que coincidan con un patrón comodín de la siguiente manera:

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

Milvus no admite comodines en sus condiciones de filtrado. Sin embargo, puede utilizar el operador like para conseguir un efecto similar como se indica a continuación:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre los operadores de rango en Milvus, consulte Operadores de rango.

Consulta booleana

En Elasticsearch, una consulta booleana es una consulta que busca documentos que coincidan con combinaciones booleanas de otras consultas.

El siguiente ejemplo está adaptado de un ejemplo en la documentación de Elasticsearch en esta página. La consulta devolverá usuarios con kimchy en sus nombres con una etiqueta production.

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

En Milvus, puede hacer algo similar de la siguiente manera:

filter = 

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

El ejemplo anterior supone que tiene un campo user del tipo VarChar y un campo tags del tipo Array, en la colección de destino. La consulta devolverá los usuarios con kimchy en sus nombres con una etiqueta production.

Consultas vectoriales

En Elasticsearch, las consultas vectoriales son consultas especializadas que trabajan sobre campos vectoriales para realizar búsquedas semánticas de forma eficiente.

Consulta Knn

Elasticsearch admite tanto consultas kNN aproximadas como consultas kNN exactas de fuerza bruta. Puede encontrar los k vectores más cercanos a un vector de consulta de cualquiera de las dos formas, medidos por una métrica de similitud, como se indica a continuación:

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

Milvus, como base de datos especializada en vectores, utiliza tipos de índice para optimizar las búsquedas de vectores. Normalmente, da prioridad a la búsqueda aproximada del vecino más cercano (kNN) para datos vectoriales de alta dimensión. Aunque la búsqueda kNN de fuerza bruta con el tipo de índice FLAT ofrece resultados precisos, consume mucho tiempo y recursos. Por el contrario, la búsqueda RNA con AUTOINDEX u otros tipos de índice equilibra velocidad y precisión, ofreciendo un rendimiento significativamente más rápido y más eficiente en recursos que kNN.

Una equivalencia similar a la consulta vectorial anterior en Mlivus es la siguiente:

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

Puede encontrar el ejemplo de Elasticsearch en esta página. Para más detalles sobre las búsquedas ANN en Milvus, lea Búsqueda ANN básica.

Fusión de rango recíproco

Elasticsearch proporciona la Fusión de Rango Recíproco (RRF) para combinar múltiples conjuntos de resultados con diferentes indicadores de relevancia en un único conjunto de resultados clasificados.

El siguiente ejemplo muestra la combinación de una búsqueda tradicional basada en términos con una búsqueda vectorial k-nearest neighbors (kNN) para mejorar la relevancia de la búsqueda:

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

En este ejemplo, RRF combina los resultados de dos recuperadores:

  • Una búsqueda estándar basada en términos de documentos que contengan el término "shoes" en el campo text.

  • Una búsqueda kNN en el campo vector utilizando el vector de consulta proporcionado.

Cada recuperador aporta hasta 50 coincidencias principales, que RRF vuelve a clasificar, y devuelve los 10 resultados finales más importantes.

En Milvus, puede conseguir una búsqueda híbrida similar combinando búsquedas en múltiples campos vectoriales, aplicando una estrategia de renumeración y recuperando los resultados top-K de la lista combinada. Milvus admite las estrategias RRF y weighted reranker. Para más detalles, consulte Reranking.

Lo siguiente es una equivalencia no estricta del ejemplo anterior de Elasticsearch en 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 ejemplo demuestra una búsqueda híbrida en Milvus que combina:

  1. Búsqueda vectorial densa: Uso de la métrica del producto interior (PI) con nprobe establecido en 10 para la búsqueda aproximada del vecino más cercano (RNA) en el campo vector.

  2. Búsqueda de vectores dispersos: Utilización de la métrica de similitud BM25 en el campo text_sparse.

Los resultados de estas búsquedas se ejecutan por separado, se combinan y se vuelven a clasificar utilizando el clasificador Reciprocal Rank Fusion (RRF). La búsqueda híbrida devuelve las 10 entidades más importantes de la lista reordenada.

A diferencia del clasificador RRF de Elasticsearch, que combina resultados de consultas estándar basadas en texto y búsquedas kNN, Milvus combina resultados de búsquedas de vectores dispersos y densos, proporcionando una capacidad de búsqueda híbrida única optimizada para datos multimodales.

Recapitulación

En este artículo, hemos cubierto las conversiones de consultas típicas de Elasticsearch a sus equivalentes en Milvus, incluyendo consultas a nivel de término, consultas booleanas, consultas de texto completo y consultas vectoriales. Si tiene más preguntas sobre la conversión de otras consultas de Elasticsearch, no dude en ponerse en contacto con nosotros.