Запросы Elasticsearch к Milvus

Elasticsearch, построенный на базе Apache Lucene, является ведущей поисковой системой с открытым исходным кодом. Однако в современных приложениях искусственного интеллекта он сталкивается с такими проблемами, как высокая стоимость обновления, низкая производительность в реальном времени, неэффективное управление шардами, не облачный нативный дизайн и чрезмерные требования к ресурсам. Milvus, являясь облачной векторной базой данных, решает эти проблемы за счет разделения хранения и вычислений, эффективного индексирования для высокоразмерных данных и бесшовной интеграции с современными инфраструктурами. Она обеспечивает превосходную производительность и масштабируемость для рабочих нагрузок ИИ.

Цель этой статьи - облегчить миграцию вашей кодовой базы с Elasticsearch на Milvus, предоставив различные примеры преобразования запросов между ними.

Обзор

В Elasticsearch операции в контексте запроса генерируют оценки релевантности, а операции в контексте фильтра - нет. Аналогично, поиск в Milvus выдает оценки сходства, а его фильтроподобные запросы - нет. При переносе кодовой базы с Elasticsearch на Milvus ключевым принципом является преобразование полей, используемых в контексте запроса Elasticsearch, в векторные поля, чтобы обеспечить генерацию оценок сходства.

В таблице ниже приведены некоторые шаблоны запросов Elasticsearch и их эквиваленты в Milvus.

Запросы Elasticsearch

Эквиваленты в Milvus

Примечания

Полнотекстовые запросы

Запрос на соответствие

Полнотекстовый поиск

Оба предоставляют схожие возможности.

Запросы на уровне терминов

Идентификаторы

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, выполняет поиск по разреженному вектору и возвращает поля id и message, указанные в параметре output_fields, вместе с соответствующими оценками сходства.

Чтобы использовать эту функциональность, необходимо включить анализатор для поля message и определить функцию для получения из него поля message_sparse. Подробные инструкции по включению анализатора и созданию производной функции в Milvus см. в разделе Полнотекстовый поиск.

Запросы на уровне терминов

В Elasticsearch запросы на уровне терминов используются для поиска документов на основе точных значений в структурированных данных, таких как диапазоны дат, IP-адреса, цены или идентификаторы продуктов. В этом разделе описаны возможные эквиваленты некоторых запросов уровня терминов Elasticsearch в Milvus. Все примеры в этом разделе адаптированы для работы в контексте фильтра, чтобы соответствовать возможностям Milvus.

Идентификаторы

В Elasticsearch вы можете найти документы по их идентификаторам в контексте фильтра следующим образом:

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

В Milvus вы также можете находить сущности по их идентификаторам следующим образом:

# 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 можно найти на этой странице. Подробнее о запросах query и get, а также о выражениях фильтрации в 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 можно найти на этой странице. Подробнее об операторе like в Milvus читайте в разделе Использование 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"]
)

В приведенном выше примере предполагается, что в целевой коллекции есть поле user типа VarChar и поле tags типа Array. Запрос вернет пользователей с 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). Хотя грубый kNN-поиск с типом индекса FLAT дает точные результаты, он требует много времени и ресурсов. В отличие от этого, поиск ANN с использованием AUTOINDEX или других типов индексов обеспечивает баланс между скоростью и точностью, предлагая значительно более быструю и ресурсоэффективную производительность, чем kNN.

Аналогичный векторный запрос в Mlivus выглядит следующим образом:

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

Пример Elasticsearch можно найти на этой странице. Подробнее о поиске с помощью ANN в Milvus читайте в статье Базовый поиск с помощью ANN.

Слияние реципрокных рангов

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 объединяет результаты двух ретриверов:

  • Стандартный поиск документов, содержащих термин "shoes" в поле text.

  • kNN-поиск по полю vector с использованием предоставленного вектора запроса.

Каждый ретривер вносит до 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. Плотный векторный поиск: Использование метрики внутреннего произведения (IP) с nprobe, установленным на 10, для приблизительного поиска ближайших соседей (ANN) на поле vector.

  2. Поиск по разреженному вектору: Использование метрики сходства BM25 на поле text_sparse.

Результаты этих поисков выполняются отдельно, объединяются и ранжируются с помощью ранжировщика Reciprocal Rank Fusion (RRF). Гибридный поиск возвращает 10 лучших сущностей из ранжированного списка.

В отличие от ранжирования RRF в Elasticsearch, которое объединяет результаты стандартных текстовых запросов и kNN-поиска, Milvus объединяет результаты поиска по разреженным и плотным векторам, предоставляя уникальную возможность гибридного поиска, оптимизированного для мультимодальных данных.

Обзор

В этой статье мы рассмотрели преобразование типичных запросов Elasticsearch в их эквиваленты в Milvus, включая запросы на уровне терминов, булевы запросы, полнотекстовые запросы и векторные запросы. Если у вас возникнут дополнительные вопросы по преобразованию других запросов Elasticsearch, обращайтесь к нам.