🚀 Попробуйте Zilliz Cloud, полностью управляемый Milvus, бесплатно — ощутите 10-кратное увеличение производительности! Попробовать сейчас>

milvus-logo
LFAI
Главная
  • Home
  • Docs
  • Учебники

  • Гибридный поиск с Milvus

Гибридный поиск с помощью Milvus

Open In Colab GitHub Repository

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

Milvus поддерживает плотный, разреженный и гибридный методы поиска:

  • Плотный поиск: Использует семантический контекст для понимания смысла запросов.
  • Разрозненный поиск: Упор делается на сопоставление текста для поиска результатов по определенным терминам, что эквивалентно полнотекстовому поиску.
  • Гибридный поиск: Комбинирует плотный и разреженный подходы, захватывая полный контекст и конкретные ключевые слова для получения исчерпывающих результатов поиска.

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

Зависимости и окружение

$ pip install --upgrade pymilvus "pymilvus[model]"

Загрузить набор данных

Для демонстрации поиска нам нужен корпус документов. Давайте воспользуемся набором данных Quora Duplicate Questions и поместим его в локальную директорию.

Источник набора данных: First Quora Dataset Release: Question Pairs

# Run this cell to download the dataset
$ wget http://qim.fs.quoracdn.net/quora_duplicate_questions.tsv

Загрузка и подготовка данных

Мы загрузим набор данных и подготовим небольшой корпус для поиска.

import pandas as pd

file_path = "quora_duplicate_questions.tsv"
df = pd.read_csv(file_path, sep="\t")
questions = set()
for _, row in df.iterrows():
    obj = row.to_dict()
    questions.add(obj["question1"][:512])
    questions.add(obj["question2"][:512])
    if len(questions) > 500:  # Skip this if you want to use the full dataset
        break

docs = list(questions)

# example question
print(docs[0])
What is the strongest Kevlar cord?

Использование модели BGE-M3 для вкраплений

Модель BGE-M3 может встраивать тексты в виде плотных и разреженных векторов.

from milvus_model.hybrid import BGEM3EmbeddingFunction

ef = BGEM3EmbeddingFunction(use_fp16=False, device="cpu")
dense_dim = ef.dim["dense"]

# Generate embeddings using BGE-M3 model
docs_embeddings = ef(docs)
Fetching 30 files: 100%|██████████| 30/30 [00:00<00:00, 302473.85it/s]
Inference Embeddings: 100%|██████████| 32/32 [01:59<00:00,  3.74s/it]

Настройка коллекции и индекса Milvus

Мы настроим коллекцию Milvus и создадим индексы для векторных полей.

  • Задание uri локального файла, например "./milvus.db", является наиболее удобным методом, поскольку он автоматически использует Milvus Lite для хранения всех данных в этом файле.
  • Если у вас большой объем данных, скажем, более миллиона векторов, вы можете настроить более производительный сервер Milvus на Docker или Kubernetes. В этом случае в качестве uri используйте ури сервера, например http://localhost:19530.
  • Если вы хотите использовать Zilliz Cloud, полностью управляемый облачный сервис для Milvus, настройте uri и token, которые соответствуют публичной конечной точке и ключу API в Zilliz Cloud.
from pymilvus import (
    connections,
    utility,
    FieldSchema,
    CollectionSchema,
    DataType,
    Collection,
)

# Connect to Milvus given URI
connections.connect(uri="./milvus.db")

# Specify the data schema for the new Collection
fields = [
    # Use auto generated id as primary key
    FieldSchema(
        name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=True, max_length=100
    ),
    # Store the original text to retrieve based on semantically distance
    FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=512),
    # Milvus now supports both sparse and dense vectors,
    # we can store each in a separate field to conduct hybrid search on both vectors
    FieldSchema(name="sparse_vector", dtype=DataType.SPARSE_FLOAT_VECTOR),
    FieldSchema(name="dense_vector", dtype=DataType.FLOAT_VECTOR, dim=dense_dim),
]
schema = CollectionSchema(fields)

# Create collection (drop the old one if exists)
col_name = "hybrid_demo"
if utility.has_collection(col_name):
    Collection(col_name).drop()
col = Collection(col_name, schema, consistency_level="Strong")

# To make vector search efficient, we need to create indices for the vector fields
sparse_index = {"index_type": "SPARSE_INVERTED_INDEX", "metric_type": "IP"}
col.create_index("sparse_vector", sparse_index)
dense_index = {"index_type": "AUTOINDEX", "metric_type": "IP"}
col.create_index("dense_vector", dense_index)
col.load()

Вставка данных в коллекцию Milvus

Вставьте документы и их вкрапления в коллекцию.

# For efficiency, we insert 50 records in each small batch
for i in range(0, len(docs), 50):
    batched_entities = [
        docs[i : i + 50],
        docs_embeddings["sparse"][i : i + 50],
        docs_embeddings["dense"][i : i + 50],
    ]
    col.insert(batched_entities)
print("Number of entities inserted:", col.num_entities)
Number of entities inserted: 502

Введите поисковый запрос

# Enter your search query
query = input("Enter your search query: ")
print(query)

# Generate embeddings for the query
query_embeddings = ef([query])
# print(query_embeddings)
How to start learning programming?

Сначала мы подготовим несколько полезных функций для запуска поиска:

  • dense_search: только поиск по плотному векторному полю
  • sparse_search: поиск только по разреженному векторному полю
  • hybrid_search: поиск по плотному и векторному полю с взвешенным реранкером
from pymilvus import (
    AnnSearchRequest,
    WeightedRanker,
)


def dense_search(col, query_dense_embedding, limit=10):
    search_params = {"metric_type": "IP", "params": {}}
    res = col.search(
        [query_dense_embedding],
        anns_field="dense_vector",
        limit=limit,
        output_fields=["text"],
        param=search_params,
    )[0]
    return [hit.get("text") for hit in res]


def sparse_search(col, query_sparse_embedding, limit=10):
    search_params = {
        "metric_type": "IP",
        "params": {},
    }
    res = col.search(
        [query_sparse_embedding],
        anns_field="sparse_vector",
        limit=limit,
        output_fields=["text"],
        param=search_params,
    )[0]
    return [hit.get("text") for hit in res]


def hybrid_search(
    col,
    query_dense_embedding,
    query_sparse_embedding,
    sparse_weight=1.0,
    dense_weight=1.0,
    limit=10,
):
    dense_search_params = {"metric_type": "IP", "params": {}}
    dense_req = AnnSearchRequest(
        [query_dense_embedding], "dense_vector", dense_search_params, limit=limit
    )
    sparse_search_params = {"metric_type": "IP", "params": {}}
    sparse_req = AnnSearchRequest(
        [query_sparse_embedding], "sparse_vector", sparse_search_params, limit=limit
    )
    rerank = WeightedRanker(sparse_weight, dense_weight)
    res = col.hybrid_search(
        [sparse_req, dense_req], rerank=rerank, limit=limit, output_fields=["text"]
    )[0]
    return [hit.get("text") for hit in res]

Запустим три разных поиска с заданными функциями:

dense_results = dense_search(col, query_embeddings["dense"][0])
sparse_results = sparse_search(col, query_embeddings["sparse"]._getrow(0))
hybrid_results = hybrid_search(
    col,
    query_embeddings["dense"][0],
    query_embeddings["sparse"]._getrow(0),
    sparse_weight=0.7,
    dense_weight=1.0,
)

Отображение результатов поиска

Чтобы отобразить результаты плотного, разреженного и гибридного поиска, нам понадобятся утилиты для форматирования результатов.

def doc_text_formatting(ef, query, docs):
    tokenizer = ef.model.tokenizer
    query_tokens_ids = tokenizer.encode(query, return_offsets_mapping=True)
    query_tokens = tokenizer.convert_ids_to_tokens(query_tokens_ids)
    formatted_texts = []

    for doc in docs:
        ldx = 0
        landmarks = []
        encoding = tokenizer.encode_plus(doc, return_offsets_mapping=True)
        tokens = tokenizer.convert_ids_to_tokens(encoding["input_ids"])[1:-1]
        offsets = encoding["offset_mapping"][1:-1]
        for token, (start, end) in zip(tokens, offsets):
            if token in query_tokens:
                if len(landmarks) != 0 and start == landmarks[-1]:
                    landmarks[-1] = end
                else:
                    landmarks.append(start)
                    landmarks.append(end)
        close = False
        formatted_text = ""
        for i, c in enumerate(doc):
            if ldx == len(landmarks):
                pass
            elif i == landmarks[ldx]:
                if close:
                    formatted_text += "</span>"
                else:
                    formatted_text += "<span style='color:red'>"
                close = not close
                ldx = ldx + 1
            formatted_text += c
        if close is True:
            formatted_text += "</span>"
        formatted_texts.append(formatted_text)
    return formatted_texts

Затем мы можем отобразить результаты поиска в виде текста с выделением:

from IPython.display import Markdown, display

# Dense search results
display(Markdown("**Dense Search Results:**"))
formatted_results = doc_text_formatting(ef, query, dense_results)
for result in dense_results:
    display(Markdown(result))

# Sparse search results
display(Markdown("\n**Sparse Search Results:**"))
formatted_results = doc_text_formatting(ef, query, sparse_results)
for result in formatted_results:
    display(Markdown(result))

# Hybrid search results
display(Markdown("\n**Hybrid Search Results:**"))
formatted_results = doc_text_formatting(ef, query, hybrid_results)
for result in formatted_results:
    display(Markdown(result))

Результаты плотного поиска:

Как лучше всего начать изучать робототехнику?

Как выучить такой компьютерный язык, как java?

Как начать изучать информационную безопасность?

Что такое программирование на Java? Как выучить язык программирования Java?

Как выучить компьютерную безопасность?

Как лучше всего начать заниматься робототехникой? Какая самая лучшая плата для разработки, чтобы я мог начать работать на ней?

Как научиться свободно говорить по-английски?

Каковы лучшие способы выучить французский язык?

Как сделать физику легкой для изучения?

Как подготовиться к UPSC?

Результаты разреженного поиска:

Что такое программирование на Java? Как выучить язык программирования Java?

С чего лучше всего начать изучение робототехники?

Что является альтернативой машинному обучению?

Как создать новый терминал и новую оболочку в Linux с помощью программирования на C?

Как создать новую оболочку в новом терминале с помощью программирования на C (терминал Linux)?

Какой бизнес лучше начать в Хайдарабаде?

Какой бизнес лучше начать в Хайдарабаде?

Как лучше всего начать заниматься робототехникой? Какая самая лучшая плата для разработки, чтобы я мог начать работать на ней?

Какая математика нужна новичку для понимания алгоритмов компьютерного программирования? Какие книги по алгоритмам подходят для новичков?

Как сделать так, чтобы жизнь устраивала вас и не позволяла издеваться над вами психически и эмоционально?

Результаты поиска по запросу Гибрид:

Как лучше всего начать заниматься робототехникой? Какая плата лучше для разработки, чтобы я мог начать работать на ней?

Что такое программирование на Java? Как выучить язык программирования Java?

Как лучше всего начать изучать робототехнику?

Как подготовиться к UPSC?

Как сделать физику легкой для изучения?

Каковы лучшие способы изучения французского языка?

Как научиться свободно говорить по-английски?

Как научиться компьютерной безопасности?

Как начать изучать информационную безопасность?

Как выучить такой компьютерный язык, как java?

Что является альтернативой машинному обучению?

Как создать новый терминал и новую оболочку в Linux с помощью программирования на C?

Как создать новую оболочку в новом терминале с помощью программирования на C (терминал Linux)?

Какой бизнес лучше начать в Хайдарабаде?

Какой бизнес лучше начать в Хайдарабаде?

Какая математика нужна новичку для понимания алгоритмов компьютерного программирования? Какие книги по алгоритмам подходят для начинающих?

Как сделать так, чтобы жизнь вас устраивала, и не дать жизни издеваться над вами психически и эмоционально?

Быстрое развертывание

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

Попробуйте Managed Milvus бесплатно

Zilliz Cloud работает без проблем, поддерживается Milvus и в 10 раз быстрее.

Начать
Обратная связь

Была ли эта страница полезной?