Pencarian Hibrida dengan Milvus
Dalam tutorial ini, kami akan mendemonstrasikan cara melakukan pencarian hybrid dengan Milvus dan model BGE-M3. Model BGE-M3 dapat mengubah teks menjadi vektor padat dan jarang. Milvus mendukung penyimpanan kedua jenis vektor tersebut dalam satu koleksi, sehingga memungkinkan pencarian hibrida yang meningkatkan relevansi hasil.
Milvus mendukung metode pencarian Dense, Sparse, dan Hybrid:
- Pengambilan Padat: Memanfaatkan konteks semantik untuk memahami makna di balik kueri.
- Pencarian Jarang (Sparse Retrieval): Menekankan pencocokan teks untuk menemukan hasil berdasarkan istilah tertentu, setara dengan pencarian teks lengkap.
- Temu Kembali Hibrida: Menggabungkan pendekatan Dense dan Sparse, menangkap konteks lengkap dan kata kunci spesifik untuk hasil pencarian yang komprehensif.
Dengan mengintegrasikan metode-metode ini, Pencarian Hibrida Milvus menyeimbangkan kemiripan semantik dan leksikal, sehingga meningkatkan relevansi hasil pencarian secara keseluruhan. Buku catatan ini akan memandu Anda melalui proses pengaturan dan penggunaan strategi pencarian ini, menyoroti keefektifannya dalam berbagai skenario pencarian.
Ketergantungan dan Lingkungan
$ pip install --upgrade pymilvus "pymilvus[model]"
Unduh Dataset
Untuk mendemonstrasikan pencarian, kita memerlukan korpus dokumen. Mari kita gunakan dataset Pertanyaan Duplikat Quora dan letakkan di direktori lokal.
Sumber dataset: Rilis Dataset Quora Pertama: Pasangan Pertanyaan
# Run this cell to download the dataset
$ wget http://qim.fs.quoracdn.net/quora_duplicate_questions.tsv
Memuat dan Menyiapkan Data
Kami akan memuat set data dan menyiapkan korpus kecil untuk pencarian.
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?
Gunakan Model BGE-M3 untuk Penyematan
Model BGE-M3 dapat menyematkan teks sebagai vektor padat dan jarang.
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]
Menyiapkan Koleksi dan Indeks Milvus
Kita akan menyiapkan koleksi Milvus dan membuat indeks untuk bidang vektor.
- Menetapkan uri sebagai file lokal, misalnya "./milvus.db", adalah metode yang paling mudah, karena secara otomatis menggunakan Milvus Lite untuk menyimpan semua data dalam file ini.
- Jika Anda memiliki data berskala besar, misalnya lebih dari satu juta vektor, Anda dapat menyiapkan server Milvus yang lebih berkinerja tinggi di Docker atau Kubernetes. Dalam pengaturan ini, gunakan uri server, misalnya http://localhost:19530, sebagai uri Anda.
- Jika Anda ingin menggunakan Zilliz Cloud, layanan cloud yang dikelola sepenuhnya untuk Milvus, sesuaikan uri dan token, yang sesuai dengan Public Endpoint dan API key di 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()
Memasukkan Data ke dalam Koleksi Milvus
Masukkan dokumen dan penyematannya ke dalam koleksi.
# 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
Masukkan Kueri Pencarian Anda
# 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?
Jalankan Pencarian
Pertama-tama kita akan menyiapkan beberapa fungsi yang berguna untuk menjalankan pencarian:
dense_search
: hanya mencari di bidang vektor yang padatsparse_search
: hanya mencari di bidang vektor yang jaranghybrid_search
: mencari di seluruh bidang vektor padat dan vektor dengan perangkingan tertimbang
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]
Mari kita jalankan tiga pencarian yang berbeda dengan fungsi yang ditentukan:
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,
)
Menampilkan Hasil Pencarian
Untuk menampilkan hasil pencarian Padat, Jarang, dan Hibrida, kita memerlukan beberapa utilitas untuk memformat hasilnya.
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
Kemudian kita dapat menampilkan hasil pencarian dalam bentuk teks dengan sorotan:
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))
Hasil Pencarian Padat:
Apa cara terbaik untuk mulai belajar robotika?
Bagaimana cara mempelajari bahasa komputer seperti java?
Bagaimana saya bisa mulai belajar keamanan informasi?
Apa itu pemrograman Java? Bagaimana Cara Belajar Bahasa Pemrograman Java?
Bagaimana saya bisa belajar keamanan komputer?
Apa cara terbaik untuk memulai robotika? Apa papan pengembangan terbaik yang bisa saya gunakan untuk mulai mengerjakannya?
Bagaimana saya bisa belajar berbicara bahasa Inggris dengan lancar?
Apa cara terbaik untuk belajar bahasa Prancis?
Bagaimana cara membuat fisika menjadi mudah dipelajari?
Bagaimana cara kita mempersiapkan diri untuk UPSC?
Hasil Pencarian Jarang:
Apa itu pemrograman Java? Bagaimana Cara Belajar Bahasa Pemrograman Java?
Apa cara terbaik untuk mulai belajar robotika?
Apa alternatif lain dari pembelajaran mesin?
Bagaimana cara membuat Terminal baru dan shell baru di Linux menggunakan pemrograman C?
Bagaimana cara membuat shell baru di terminal baru menggunakan pemrograman C (terminal Linux)?
Bisnis mana yang lebih baik untuk dimulai di Hyderabad?
Bisnis mana yang bagus untuk memulai di Hyderabad?
Apa cara terbaik untuk memulai robotika? Apa papan pengembangan terbaik yang bisa saya gunakan untuk mulai mengerjakannya?
Matematika apa yang dibutuhkan oleh seorang pemula untuk memahami algoritma pemrograman komputer? Buku algoritma apa yang cocok untuk pemula yang lengkap?
Bagaimana Anda membuat hidup sesuai dengan Anda dan menghentikan hidup menyiksa Anda secara mental dan emosional?
Hasil Pencarian Hibrida:
Apa cara terbaik untuk memulai robotika? Apa papan pengembangan terbaik yang bisa saya gunakan untuk mulai mengerjakannya?
Apa itu pemrograman Java? Bagaimana Cara Belajar Bahasa Pemrograman Java?
Apa cara terbaik untuk mulai belajar robotika?
Bagaimana cara kita mempersiapkan diri untuk UPSC?
Bagaimana cara membuat fisika menjadi mudah dipelajari?
Apa cara terbaik untuk belajar bahasa Prancis?
Bagaimana saya bisa belajar berbicara bahasa Inggris dengan lancar?
Bagaimana saya bisa belajar keamanan komputer?
Bagaimana saya bisa mulai belajar keamanan informasi?
Bagaimana cara belajar bahasa komputer seperti java?
Apa alternatif lain untuk pembelajaran mesin?
Bagaimana cara membuat Terminal dan shell baru di Linux menggunakan pemrograman C?
Bagaimana cara membuat shell baru di terminal baru menggunakan pemrograman C (terminal Linux)?
Bisnis mana yang lebih baik untuk dimulai di Hyderabad?
Bisnis mana yang bagus untuk memulai di Hyderabad?
Matematika apa yang dibutuhkan seorang pemula untuk memahami algoritma pemrograman komputer? Buku algoritma apa yang cocok untuk pemula yang lengkap?
Bagaimana Anda membuat hidup sesuai dengan Anda dan menghentikan hidup menyiksa Anda secara mental dan emosional?
Penerapan Cepat
Untuk mempelajari tentang cara memulai demo online dengan tutorial ini, silakan lihat contoh aplikasi.