🚀 جرب Zilliz Cloud، الـ Milvus المدارة بالكامل، مجاناً — تجربة أداء أسرع بـ 10 أضعاف! جرب الآن>>

milvus-logo
LFAI
  • Home
  • Blog
  • الشروع في استخدام البحث الدلالي الهجين/البحث عن النص الكامل مع ميلفوس 2.5

الشروع في استخدام البحث الدلالي الهجين/البحث عن النص الكامل مع ميلفوس 2.5

  • Engineering
December 17, 2024
Stefan Webb

في هذه المقالة، سنوضح لك كيفية بدء تشغيل ميزة البحث عن النص الكامل الجديدة بسرعة ودمجها مع البحث الدلالي التقليدي القائم على تضمينات المتجهات.

المتطلبات

أولاً، تأكد من تثبيت ميلفوس 2.5:

pip install -U pymilvus[model]

وأن يكون لديك مثيل قيد التشغيل من Milvus Standalone (على جهازك المحلي على سبيل المثال) باستخدام تعليمات التثبيت في مستندات Milvus.

بناء مخطط البيانات ومؤشرات البحث

نقوم باستيراد الفئات والوظائف المطلوبة:

from pymilvus import MilvusClient, DataType, Function, FunctionType, model

لعلك لاحظت إدخالين جديدين لـ Milvus 2.5، Function و FunctionType ، والتي سنقوم بشرحها بعد قليل.

بعد ذلك نفتح قاعدة البيانات باستخدام Milvus Standalone، أي محليًا، وننشئ مخطط البيانات. يتألف المخطط من مفتاح أساسي عدد صحيح، وسلسلة نصية، ومتجه كثيف بأبعاد 384، ومتجه متناثر (بأبعاد غير محدودة). لاحظ أن ميلفوس لايت لا يدعم حاليًا البحث في النص الكامل، فقط ميلفوس ستاندالون وميلفوس الموزع.

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema()

schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)
schema.add_field(field_name="dense", datatype=DataType.FLOAT_VECTOR, dim=768),
schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR)
{'auto_id': False, 'description': '', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 1000, 'enable_analyzer': True}}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>}], 'enable_dynamic_field': False}

ربما لاحظت المعلمة enable_analyzer=True. هذا يخبر ميلفوس 2.5 بتمكين المحلل المعجمي على هذا الحقل وبناء قائمة من الرموز وترددات الرموز الرمزية، وهي مطلوبة للبحث في النص الكامل. سيحتوي الحقل sparse على تمثيل متجه للوثائق كحقيبة من الكلمات الناتجة عن التحليل text.

ولكن كيف نربط بين الحقلين text و sparse ، ونخبر ميلفوس كيف ينبغي حساب sparse من text ؟ هذا هو المكان الذي نحتاج فيه إلى استدعاء الكائن Function وإضافته إلى المخطط:

bm25_function = Function(
    name="text_bm25_emb", # Function name
    input_field_names=["text"], # Name of the VARCHAR field containing raw text data
    output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings
    function_type=FunctionType.BM25,
)

schema.add_function(bm25_function)
{'auto_id': False, 'description': '', 'fields': [{'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'is_primary': True, 'auto_id': True}, {'name': 'text', 'description': '', 'type': <DataType.VARCHAR: 21>, 'params': {'max_length': 1000, 'enable_analyzer': True}}, {'name': 'dense', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 768}}, {'name': 'sparse', 'description': '', 'type': <DataType.SPARSE_FLOAT_VECTOR: 104>, 'is_function_output': True}], 'enable_dynamic_field': False, 'functions': [{'name': 'text_bm25_emb', 'description': '', 'type': <FunctionType.BM25: 1>, 'input_field_names': ['text'], 'output_field_names': ['sparse'], 'params': {}}]}

إن تجريد كائن Function أكثر عمومية من تجريد كائن من تطبيق البحث عن النص الكامل. في المستقبل، يمكن استخدامه في حالات أخرى حيث يجب أن يكون أحد الحقول دالة لحقل آخر. في حالتنا، نحدد أن sparse هو دالة لـ text عبر الدالة FunctionType.BM25. BM25 يشير إلى مقياس شائع في استرجاع المعلومات يستخدم لحساب تشابه الاستعلام مع مستند (بالنسبة إلى مجموعة من المستندات).

نحن نستخدم نموذج التضمين الافتراضي في ميلفوس، وهو نموذج إعادة الصياغة-ألبرت-صغير-ف2:

embedding_fn = model.DefaultEmbeddingFunction()

الخطوة التالية هي إضافة مؤشرات البحث الخاصة بنا. لدينا واحد للمتجه الكثيف وآخر منفصل للمتجه المتناثر. نوع الفهرس هو SPARSE_INVERTED_INDEX مع BM25 نظرًا لأن البحث عن النص الكامل يتطلب طريقة بحث مختلفة عن تلك الخاصة بالمتجهات الكثيفة القياسية.

index_params = client.prepare_index_params()

index_params.add_index(
    field_name="dense",
    index_type="AUTOINDEX", 
    metric_type="COSINE"
)

index_params.add_index(
    field_name="sparse",
    index_type="SPARSE_INVERTED_INDEX", 
    metric_type="BM25"
)

أخيرًا، ننشئ مجموعتنا:

client.drop_collection('demo')
client.list_collections()
[]
client.create_collection(
    collection_name='demo', 
    schema=schema, 
    index_params=index_params
)

client.list_collections()
['demo']

وبذلك، أصبح لدينا قاعدة بيانات فارغة تم إعدادها لقبول المستندات النصية وإجراء عمليات بحث دلالية وبحث عن النص الكامل!

لا يختلف إدراج البيانات عن الإصدارات السابقة من ميلفوس:

docs = [
    'information retrieval is a field of study.',
    'information retrieval focuses on finding relevant information in large datasets.',
    'data mining and information retrieval overlap in research.'
]

embeddings = embedding_fn(docs)

client.insert('demo', [
    {'text': doc, 'dense': vec} for doc, vec in zip(docs, embeddings)
])
{'insert_count': 3, 'ids': [454387371651630485, 454387371651630486, 454387371651630487], 'cost': 0}

لنقم أولاً بتوضيح البحث عن النص الكامل قبل أن ننتقل إلى البحث المختلط:

search_params = {
    'params': {'drop_ratio_search': 0.2},
}

results = client.search(
    collection_name='demo', 
    data=['whats the focus of information retrieval?'],
    output_fields=['text'],
    anns_field='sparse',
    limit=3,
    search_params=search_params
)

تشير معلمة البحث drop_ratio_search إلى نسبة المستندات ذات الدرجات المنخفضة التي سيتم إسقاطها أثناء خوارزمية البحث.

دعونا نعرض النتائج:

for hit in results[0]:
    print(hit)
{'id': 454387371651630485, 'distance': 1.3352930545806885, 'entity': {'text': 'information retrieval is a field of study.'}}
{'id': 454387371651630486, 'distance': 0.29726022481918335, 'entity': {'text': 'information retrieval focuses on finding relevant information in large datasets.'}}
{'id': 454387371651630487, 'distance': 0.2715056240558624, 'entity': {'text': 'data mining and information retrieval overlap in research.'}}

دعونا الآن نجمع بين ما تعلمناه لإجراء بحث هجين يجمع بين البحث الدلالي المنفصل والبحث بالنص الكامل مع أداة إعادة البحث:

from pymilvus import AnnSearchRequest, RRFRanker
query = 'whats the focus of information retrieval?'
query_dense_vector = embedding_fn([query])

search_param_1 = {
    "data": query_dense_vector,
    "anns_field": "dense",
    "param": {
        "metric_type": "COSINE",
    },
    "limit": 3
}
request_1 = AnnSearchRequest(**search_param_1)

search_param_2 = {
    "data": [query],
    "anns_field": "sparse",
    "param": {
        "metric_type": "BM25",
        "params": {"drop_ratio_build": 0.0}
    },
    "limit": 3
}
request_2 = AnnSearchRequest(**search_param_2)

reqs = [request_1, request_2]
ranker = RRFRanker()

res = client.hybrid_search(
    collection_name="demo",
    output_fields=['text'],
    reqs=reqs,
    ranker=ranker,
    limit=3
)
for hit in res[0]:
    print(hit)
{'id': 454387371651630485, 'distance': 0.032786883413791656, 'entity': {'text': 'information retrieval is a field of study.'}}
{'id': 454387371651630486, 'distance': 0.032258063554763794, 'entity': {'text': 'information retrieval focuses on finding relevant information in large datasets.'}}
{'id': 454387371651630487, 'distance': 0.0317460335791111, 'entity': {'text': 'data mining and information retrieval overlap in research.'}}

كما لاحظتم، هذا لا يختلف عن البحث المختلط مع حقلين دلاليين منفصلين (متاح منذ الإصدار 2.4 من ملفوس 2.4). تتطابق النتائج مع البحث بالنص الكامل في هذا المثال البسيط، ولكن بالنسبة لقواعد البيانات الأكبر وعمليات البحث الخاصة بالكلمات المفتاحية عادةً ما يكون البحث الهجين أعلى في الاستدعاء.

الملخص

أنت الآن مجهز بكل المعرفة اللازمة لإجراء بحث النص الكامل والبحث المختلط الدلالي/النص الكامل مع ميلفوس 2.5. راجع المقالات التالية لمزيد من المناقشة حول كيفية عمل البحث بالنص الكامل وسبب تكامله مع البحث الدلالي:

Like the article? Spread the word

استمر في القراءة