فتح الاسترجاع الحقيقي على مستوى الكيان: مجموعة جديدة من الهياكل وقدرات MAX_SIM في ميلفوس
إذا كنت قد أنشأت تطبيقات ذكاء اصطناعي فوق قواعد البيانات المتجهة، فمن المحتمل أنك واجهت نفس المشكلة: تسترجع قاعدة البيانات تضمينات الأجزاء الفردية، لكن تطبيقك يهتم بالكيانات. عدم التطابق يجعل سير عمل الاسترجاع بأكمله معقدًا.
من المحتمل أنك رأيت هذا الأمر مرارًا وتكرارًا:
قواعد المعرفة RAG: يتم تجزئة المقالات إلى أجزاء مضمنة في فقرات، لذلك يقوم محرك البحث بإرجاع أجزاء متناثرة بدلاً من المستند الكامل.
توصيات التجارة الإلكترونية: يحتوي المنتج على تضمينات صور متعددة، ويعيد نظامك خمس زوايا لنفس العنصر بدلاً من خمسة منتجات فريدة.
منصات الفيديو: يتم تقسيم مقاطع الفيديو إلى تضمينات مقاطع فيديو، ولكن نتائج البحث تُظهر شرائح من نفس الفيديو بدلاً من إدخال واحد مدمج.
استرجاع على غرار ColBERT / ColPali: تتوسع المستندات إلى مئات من التضمينات على مستوى الرمز أو مستوى التصحيح، وتعود نتائجك كقطع صغيرة لا تزال تتطلب الدمج.
تنبع جميع هذه المشكلات من نفس الفجوة المعمارية: معظم قواعد البيانات المتجهة تتعامل مع كل تضمين كصف منفصل، بينما تعمل التطبيقات الحقيقية على كيانات ذات مستوى أعلى - المستندات والمنتجات ومقاطع الفيديو والعناصر والمشاهد. ونتيجةً لذلك، تضطر الفرق الهندسية إلى إعادة بناء الكيانات يدويًا باستخدام منطق إلغاء التكرار، والتجميع، والتجميع، والتجميع في مجموعات، وإعادة ترتيبها. إنها تعمل، لكنها هشة وبطيئة وتضخم طبقة التطبيق الخاصة بك بمنطق لا ينبغي أن يكون هناك في المقام الأول.
يغلقميلفوس 2.6.4 هذه الفجوة بميزة جديدة: صفيف الهياكل مع نوع القياس MAX_SIM. تسمح هذه الميزات معًا بتخزين جميع التضمينات لكيان واحد في سجل واحد وتمكين Milvus من تسجيل الكيان وإرجاعه بشكل كلي. لا مزيد من مجموعات النتائج المكررة المملوءة. لا مزيد من المعالجة اللاحقة المعقدة مثل إعادة الترتيب والدمج
سنستعرض في هذه المقالة كيفية عمل مصفوفة الهياكل و MAX_SIM - وسنوضحها من خلال مثالين حقيقيين: استرجاع مستندات ويكيبيديا والبحث عن المستندات المستندة إلى صور ColPali.
ما هي مصفوفة الهياكل؟
في ميلفوس، يسمح حقل مصفوفة الهياكل باحتواء سجل واحد على قائمة مرتبة من عناصر الهيكل، كل منها يتبع نفس المخطط المحدد مسبقًا. يمكن أن تحتوي البنية على متجهات متعددة بالإضافة إلى حقول قياسية أو سلاسل أو أي أنواع أخرى مدعومة. بعبارة أخرى، يتيح لك تجميع جميع الأجزاء التي تنتمي إلى كيان واحد - تضمين الفقرات، وطرق عرض الصور، وناقلات الرموز، والبيانات الوصفية - مباشرةً داخل صف واحد.
فيما يلي مثال لكيان من مجموعة تحتوي على حقل صفيف من الهياكل.
{
'id': 0,
'title': 'Walden',
'title_vector': [0.1, 0.2, 0.3, 0.4, 0.5],
'author': 'Henry David Thoreau',
'year_of_publication': 1845,
// highlight-start
'chunks': [
{
'text': 'When I wrote the following pages, or rather the bulk of them...',
'text_vector': [0.3, 0.2, 0.3, 0.2, 0.5],
'chapter': 'Economy',
},
{
'text': 'I would fain say something, not so much concerning the Chinese and...',
'text_vector': [0.7, 0.4, 0.2, 0.7, 0.8],
'chapter': 'Economy'
}
]
// hightlight-end
}
في المثال أعلاه، الحقل chunks هو حقل صفيف من حقول الهياكل، ويحتوي كل عنصر من عناصر الهياكل على الحقول الخاصة به، وهي text و text_vector و chapter.
يحل هذا النهج مشكلة نمذجة طويلة الأمد في قواعد البيانات المتجهة. تقليديًا، يجب أن يصبح كل تضمين أو سمة صفًا خاصًا به، مما يفرض تقسيم الكيانات متعددة المتجهات (المستندات والمنتجات ومقاطع الفيديو) إلى عشرات أو مئات أو حتى آلاف السجلات. باستخدام Array of Structs، يتيح لك Milvus تخزين الكيان متعدد المتجهات بالكامل في حقل واحد، مما يجعله مناسبًا بشكل طبيعي لقوائم الفقرات أو تضمينات الرموز أو تسلسلات المقاطع أو الصور متعددة المشاهد أو أي سيناريو يتكون فيه عنصر منطقي واحد من العديد من المتجهات.
كيف تعمل مصفوفة الهياكل مع MAX_SIM؟
يوجد فوق بنية مصفوفة الهياكل الجديدة هذه MAX_SIM، وهي استراتيجية تسجيل جديدة تجعل استرجاع الدلالات مدركًا للكيانات. عندما يأتي استعلام، يقارنه Milvus مع كل متجه داخل كل مصفوفة من الهياكل ويأخذ الحد الأقصى للتشابه كدرجة نهائية للكيان. ثم يتم ترتيب الكيان وإرجاعه بناءً على تلك الدرجة الواحدة. هذا يتجنب مشكلة قاعدة البيانات المتجهة التقليدية المتمثلة في استرداد الأجزاء المبعثرة ودفع عبء التجميع وإلغاء التصنيف وإعادة الترتيب إلى طبقة التطبيق. باستخدام MAX_SIM، يصبح الاسترجاع على مستوى الكيان مدمجًا ومتسقًا وفعالًا.
لفهم كيفية عمل MAX_SIM عمليًا، دعونا نستعرض مثالًا ملموسًا.
ملاحظة: يتم إنشاء جميع المتجهات في هذا المثال بواسطة نموذج التضمين نفسه، ويتم قياس التشابه باستخدام تشابه جيب التمام في النطاق [0،1].
لنفترض أن مستخدمًا يبحث عن "دورة تعلم الآلة للمبتدئين".
تم ترميز الاستعلام إلى ثلاثة رموز:
تعلّم الآلة
مبتدئ
دورة تدريبية
يتم بعد ذلك تحويل كل رمز من هذه الرموز إلى متجه تضمين بواسطة نفس نموذج التضمين المستخدم للمستندات.
والآن، تخيل أن قاعدة البيانات المتجهة تحتوي على مستندين:
doc_1: دليل تمهيدي للشبكات العصبية العميقة باستخدام بايثون
المستند_2: دليل متقدم لقراءة أوراق LLM
تم تضمين كلا المستندين في متجهات وتم تخزينهما داخل مصفوفة من الهياكل.
الخطوة 1: حساب MAX_SIM لـ doc_1
بالنسبة لكل متجه استعلام، يحسب ميلفوس تشابه جيب التمام مقابل كل متجه في doc_1:
| مقدمة | دليل | الشبكات العصبية العميقة | بيثون | |
|---|---|---|---|---|
| التعلم الآلي | 0.0 | 0.0 | 0.9 | 0.3 |
| مبتدئ | 0.8 | 0.1 | 0.0 | 0.3 |
| الدورة | 0.3 | 0.7 | 0.1 | 0.1 |
لكل متجه استعلام، يختار MAX_SIM أعلى تشابه من صفه:
التعلم الآلي → الشبكات العصبية العميقة (0.9)
مبتدئ → مقدمة (0.8)
الدورة التدريبية → دليل (0.7)
جمع أفضل التطابقات يعطي doc_1 درجة MAX_SIM 2.4.
الخطوة 2: حساب MAX_SIM للمستند_2
الآن نكرر العملية للمستند_2:
| متقدم | الدليل | LLM | الورقي | القراءة | |
|---|---|---|---|---|---|
| التعلم الآلي | 0.1 | 0.2 | 0.9 | 0.3 | 0.1 |
| مبتدئ | 0.4 | 0.6 | 0.0 | 0.2 | 0.5 |
| الدورة | 0.5 | 0.8 | 0.1 | 0.4 | 0.7 |
أفضل التطابقات لـ doc_2 هي
"التعلم الآلي" → "LLM" (0.9)
"مبتدئ" → "دليل" (0.6)
"دورة" → "مرشد" (0.8)
جمعها يعطي doc_2 درجة MAX_SIM 2.3.
الخطوة 3: مقارنة الدرجات
نظرًا لأن 2.4 > 2.3، فإن المستند_1 يحتل مرتبة أعلى من المستند2، وهو أمر منطقي بديهي لأن المستند_1 أقرب إلى دليل تعلم آلي تمهيدي.
من هذا المثال يمكننا تسليط الضوء على ثلاث خصائص أساسية لـ MAX_SIM
الدلالي أولاً، وليس على أساس الكلمات الرئيسية: يقارن MAX_SIM التضمينات، وليس النصوص الحرفية. على الرغم من أن "التعلّم الآلي" و "الشبكات العصبية العميقة" لا يشتركان في أي كلمات متداخلة، إلا أن التشابه الدلالي بينهما يبلغ 0.9. وهذا ما يجعل MAX_SIM قويًا تجاه المرادفات وإعادة الصياغة والتداخل المفاهيمي وأعباء العمل الحديثة الغنية بالتضمينات.
غير حساس للطول والترتيب: لا يتطلب MAX_SIM أن يحتوي المستند والاستعلام على نفس عدد المتجهات (على سبيل المثال، يحتوي المستند_1 على 4 متجهات بينما يحتوي المستند 2 على 5 متجهات، وكلاهما يعمل بشكل جيد). كما أنه يتجاهل أيضًا ترتيب المتجهات - ظهور "مبتدئ" في الاستعلام سابقًا وظهور "مقدمة" لاحقًا في المستند ليس له أي تأثير على النتيجة.
كل متجه استعلام مهم: يأخذ MAX_SIM أفضل تطابق لكل متجه استعلام ويجمع أفضل الدرجات. هذا يمنع المتجهات غير المتطابقة من تحريف النتيجة ويضمن أن كل رمز استعلام مهم يساهم في النتيجة النهائية. على سبيل المثال، يقلل التطابق الأقل جودة لرمز "مبتدئ" في doc_2 من نتيجته الإجمالية مباشرةً.
سبب أهمية MAX_SIM + صفيف الهياكل في قاعدة بيانات المتجهات
Milvus هي قاعدة بيانات متجهات مفتوحة المصدر وعالية الأداء وتدعم الآن بشكل كامل MAX_SIM مع مصفوفة الهياكل، مما يتيح استرجاع متعدد المتجهات على مستوى الكيانات:
تخزين الكيانات متعددة المتجهات محليًا: تسمح لك Array of Structs بتخزين مجموعات من المتجهات ذات الصلة في حقل واحد دون تقسيمها إلى صفوف منفصلة أو جداول مساعدة.
حساب أفضل تطابق فعال: بالاقتران مع فهارس المتجهات مثل IVF و HNSW، يمكن ل MAX_SIM حساب أفضل التطابقات دون مسح كل متجه، مما يحافظ على الأداء العالي حتى مع المستندات الكبيرة.
مصمم خصيصًا لأعباء العمل ذات الدلالات الثقيلة: تتفوق هذه الطريقة في استرجاع النصوص الطويلة، والمطابقة الدلالية متعددة الأوجه، والمحاذاة الدلالية متعددة الأوجه، ومحاذاة ملخص المستندات، والاستعلامات متعددة الكلمات الرئيسية، وسيناريوهات الذكاء الاصطناعي الأخرى التي تتطلب استدلالاً دلاليًا مرنًا ودقيقًا.
متى تستخدم مصفوفة الهياكل
تصبح قيمة مصفوفة الهياكل واضحة عندما تنظر إلى ما تتيحه. توفر هذه الميزة في جوهرها ثلاث قدرات أساسية:
إنها تجمع البيانات غير المتجانسة - المتجهاتوالمقاييس والسلاسل والبيانات الوصفية - في كائن واحد منظم.
تقوم بمحاذاة التخزين مع كيانات العالم الحقيقي، بحيث يتم ربط كل صف من قاعدة البيانات بشكل نظيف بعنصر فعلي مثل مقالة أو منتج أو فيديو.
عند دمجها مع الدوال المجمعة مثل MAX_SIM، فإنها تتيح استرجاعًا حقيقيًا متعدد المتجهات على مستوى الكيان مباشرةً من قاعدة البيانات، مما يلغي التكرار أو التجميع أو إعادة الترتيب في طبقة التطبيق.
وبسبب هذه الخصائص، فإن مصفوفة الهياكل مناسبة بشكل طبيعي عندما يتم تمثيل كيان منطقي واحد بواسطة ناقلات متعددة. تشمل الأمثلة الشائعة المقالات المقسمة إلى فقرات، أو المستندات المتحللة إلى تضمينات رمزية، أو المنتجات الممثلة بصور متعددة. إذا كانت نتائج البحث الخاصة بك تعاني من تكرار النتائج، أو أجزاء مبعثرة، أو ظهور نفس الكيان عدة مرات في أعلى النتائج، فإن مصفوفة الهياكل تحل هذه المشكلات في طبقة التخزين والاسترجاع - وليس من خلال التصحيح اللاحق في التعليمات البرمجية للتطبيق.
يعد هذا النمط قويًا بشكل خاص لأنظمة الذكاء الاصطناعي الحديثة التي تعتمد على الاسترجاع متعدد النواقل. على سبيل المثال:
يمثّلColBERT مستندًا واحدًا على شكل 100-500 رمز مضمن لمطابقة دلالية دقيقة عبر مجالات مثل النصوص القانونية والأبحاث الأكاديمية.
يقومColPali بتحويل كل صفحة من صفحات PDF إلى 256-1024 رقعة صورة لاسترجاع متعدد الوسائط عبر البيانات المالية والعقود والفواتير وغيرها من المستندات الممسوحة ضوئيًا.
تسمح مصفوفة من الهياكل لـ Milvus بتخزين جميع هذه المتجهات تحت كيان واحد وحساب التشابه الكلي (على سبيل المثال، MAX_SIM) بكفاءة وبشكل أصلي. لتوضيح ذلك، إليك مثالين ملموسين.
مثال 1: البحث عن منتجات التجارة الإلكترونية
في السابق، كان يتم تخزين المنتجات ذات الصور المتعددة في مخطط مسطح - صورة واحدة لكل صف. كان المنتج الذي يحتوي على لقطات أمامية وجانبية وزاوية ينتج عنه ثلاثة صفوف. غالبًا ما كانت نتائج البحث تُرجع صورًا متعددة لنفس المنتج، مما كان يتطلب إلغاء التكرار وإعادة الترتيب يدويًا.
مع مصفوفة الهياكل، يصبح كل منتج صفًا واحدًا. تعيش جميع عمليات تضمين الصور والبيانات الوصفية (الزاوية، is_primary، وما إلى ذلك) داخل حقل images كمصفوفة من الهياكل. يفهم ميلفوس أنها تنتمي إلى نفس المنتج ويعيد المنتج ككل - وليس صوره الفردية.
مثال 2: قاعدة المعرفة أو البحث في ويكيبيديا
في السابق، كانت مقالة واحدة في ويكيبيديا مقسمة إلى عدد N من الفقرات. كانت نتائج البحث تُرجع فقرات مبعثرة، مما كان يجبر النظام على تجميعها وتخمين المقالة التي تنتمي إليها.
مع صفيف الهياكل، تصبح المقالة بأكملها صفًا واحدًا. يتم تجميع جميع الفقرات وتضميناتها تحت حقل الفقرات، وتُرجع قاعدة البيانات المقالة كاملة، وليس أجزاءً مجزأة.
دروس عملية: استرجاع على مستوى المستند باستخدام صفيف الهياكل
1. استرجاع مستند ويكيبيديا
سنستعرض في هذا البرنامج التعليمي كيفية استخدام مصفوفة الهياكل لتحويل البيانات على مستوى الفقرة إلى سجلات مستند كاملة - مما يسمح لملفوس بإجراء استرجاع حقيقي على مستوى المستند بدلاً من إرجاع أجزاء معزولة.
تخزن العديد من خطوط أنابيب القاعدة المعرفية مقالات ويكيبيديا على شكل فقرات. يعمل هذا بشكل جيد للتضمين والفهرسة، لكنه يعطل الاسترجاع: عادةً ما يُرجع استعلام المستخدم فقرات مبعثرة، مما يجبرك على تجميع المقالة يدويًا وإعادة بنائها. باستخدام مصفوفة من الهياكل و MAX_SIM، يمكننا إعادة تصميم مخطط التخزين بحيث تصبح كل مقالة صفًا واحدًا، ويمكن لـ Milvus ترتيب المستند بأكمله وإرجاعه أصلاً.
سنوضح في الخطوات التالية كيفية:
التحميل والمعالجة المسبقة لبيانات فقرات ويكيبيديا
تجميع كل الفقرات التي تنتمي إلى نفس المقالة في مصفوفة من الهياكل
إدراج هذه المستندات المهيكلة في ميلفوس
قم بتشغيل استعلامات MAX_SIM لاسترداد المقالات الكاملة - بشكل نظيف، دون حذف أو إعادة ترتيب
بحلول نهاية هذا البرنامج التعليمي، سيكون لديك خط أنابيب يعمل حيث يتعامل ميلفوس مع الاسترجاع على مستوى الكيان مباشرة، بالطريقة التي يتوقعها المستخدمون بالضبط.
نموذج البيانات:
{
"wiki_id": int, # WIKI ID(primary key)
"paragraphs": ARRAY<STRUCT< # Array of paragraph structs
text:VARCHAR # Paragraph text
emb: FLOAT_VECTOR(768) # Embedding for each paragraph
>>
}
الخطوة 1: تجميع البيانات وتحويلها
في هذا العرض التوضيحي، نستخدم مجموعة بيانات تضمينات ويكيبيديا البسيطة.
import pandas as pd
import pyarrow as pa
# Load the dataset and group by wiki_id
df = pd.read_parquet(“train-*.parquet”)
grouped = df.groupby(‘wiki_id’)
# Build the paragraph array for each article
wiki_data = []
for wiki_id, group in grouped:
wiki_data.append({
‘wiki_id’: wiki_id,
‘paragraphs’: [{‘text’: row[‘text’], ‘emb’: row[‘emb’]}
for _, row in group.iterrows()]
})
الخطوة 2: إنشاء مجموعة ميلفوس
from pymilvus import MilvusClient, DataType
client = MilvusClient(uri=“http://localhost:19530”)
schema = client.create_schema()
schema.add_field(“wiki_id”, DataType.INT64, is_primary=True)
# Define the Struct schema
struct_schema = client.create_struct_field_schema()
struct_schema.add_field(“text”, DataType.VARCHAR, max_length=65535)
struct_schema.add_field(“emb”, DataType.FLOAT_VECTOR, dim=768)
schema.add_field(“paragraphs”, DataType.ARRAY,
element_type=DataType.STRUCT,
struct_schema=struct_schema, max_capacity=200)
client.create_collection(“wiki_docs”, schema=schema)
الخطوة 3: إدراج البيانات وبناء الفهرس
# Batch insert documents
client.insert("wiki_docs", wiki_data)
# Create an HNSW index
index_params = client.prepare_index_params()
index_params.add_index(
field_name="paragraphs[emb]",
index_type=“HNSW”,
metric_type=“MAX_SIM_COSINE”,
params={“M”: 16, “efConstruction”: 200}
)
client.create_index(“wiki_docs”, index_params)
client.load_collection(“wiki_docs”)
الخطوة 4: البحث في المستندات
# Search query
import cohere
from pymilvus.client.embedding_list import EmbeddingList
# The dataset uses Cohere’s multilingual-22-12 embedding model, so we must embed the query using the same model.
co = cohere.Client(f"<>" )
query = ‘Who founded Youtube’
response = co.embed(texts=[query], model=‘multilingual-22-12’)
query_embedding = response.embeddings
query_emb_list = EmbeddingList()
for vec in query_embedding[0]:
query_emb_list.add(vec)
results = client.search(
collection_name=“wiki_docs”,
data=[query_emb_list],
anns_field="paragraphs[emb]",
search_params={
“metric_type”: “MAX_SIM_COSINE”,
“params”: {“ef”: 200, “retrieval_ann_ratio”: 3}
},
limit=10,
output_fields=[“wiki_id”]
)
# Results: directly return 10 full articles!
for hit in results[0]:
print(f"Article {hit[‘entity’][‘wiki_id’]}: Score {hit[‘distance’]:.4f}")
مقارنة المخرجات: الاسترجاع التقليدي مقابل صفيف الهياكل
يصبح تأثير مصفوفة الهياكل واضحًا عندما ننظر إلى ما ترجعه قاعدة البيانات بالفعل:
| البُعد | النهج التقليدي | صفيف الهياكل |
|---|---|---|
| مخرجات قاعدة البيانات | إرجاع أفضل 100 فقرة (تكرار كبير) | إرجاع أفضل 10 مستندات كاملة - نظيفة ودقيقة |
| منطق التطبيق | يتطلب التجميع وإلغاء التكرار وإعادة الترتيب (معقد) | لا حاجة إلى معالجة لاحقة - تأتي النتائج على مستوى الكيان مباشرةً من ميلفوس |
في مثال ويكيبيديا، عرضنا أبسط حالة فقط: دمج متجهات الفقرات في تمثيل موحد للمستند. لكن القوة الحقيقية لـ Array of Structs هي أنه يعمم على أي نموذج بيانات متعدد المتجهات - سواءً كانت خطوط أنابيب الاسترجاع الكلاسيكية أو بنى الذكاء الاصطناعي الحديثة.
سيناريوهات الاسترجاع التقليدية متعددة النواقل
تعمل العديد من أنظمة البحث والتوصيات الراسخة بشكل طبيعي على الكيانات ذات المتجهات المتعددة المرتبطة بها. تتوافق مصفوفة الهياكل مع حالات الاستخدام هذه بشكل نظيف:
| السيناريو | نموذج البيانات | المتجهات لكل كيان |
|---|---|---|
| 🛍️ منتجات التجارة الإلكترونية | منتج واحد ← صور متعددة | 5-20 |
| 🎬 البحث عن الفيديو | فيديو واحد ← مقاطع متعددة | 20-100 |
| 📖 استرجاع الورق | ورقة واحدة ← مقاطع متعددة | 5-15 |
أعباء عمل نموذج الذكاء الاصطناعي (حالات الاستخدام الرئيسية متعددة النواقل)
تصبح مصفوفة الهياكل أكثر أهمية في نماذج الذكاء الاصطناعي الحديثة التي تنتج عن قصد مجموعات كبيرة من المتجهات لكل كيان من أجل التفكير الدلالي الدقيق.
| النموذج | نموذج البيانات | المتجهات لكل كيان | التطبيق |
|---|---|---|---|
| كولبيرت | مستند واحد → العديد من التضمينات الرمزية | 100-500 | النصوص القانونية، والأبحاث الأكاديمية، واسترجاع المستندات الدقيقة |
| كولبالي | صفحة PDF واحدة → العديد من التضمينات الرمزية | 256-1024 | تقارير مالية، وعقود، وفواتير، وبحث عن مستندات متعددة الوسائط |
تتطلب هذه النماذج نمط تخزين متعدد النواقل. قبل مصفوفة الهياكل، كان على المطورين تقسيم المتجهات عبر الصفوف وإعادة تجميع النتائج يدويًا. مع Milvus، يمكن الآن تخزين هذه الكيانات واسترجاعها محليًا، مع تعامل MAX_SIM مع التسجيل على مستوى المستند تلقائيًا.
2. بحث المستندات القائم على الصور ColPali
ColPali هو نموذج قوي لاسترجاع ملفات PDF متعددة الوسائط. فبدلاً من الاعتماد على النص، يعالج كل صفحة PDF كصورة ويقسمها إلى ما يصل إلى 1024 رقعة مرئية، مما يؤدي إلى إنشاء تضمين واحد لكل رقعة. في ظل مخطط قاعدة البيانات التقليدية، سيتطلب ذلك تخزين صفحة واحدة كمئات أو آلاف الصفوف المنفصلة، مما يجعل من المستحيل على قاعدة البيانات فهم أن هذه الصفوف تنتمي إلى نفس الصفحة. ونتيجة لذلك، يصبح البحث على مستوى الكيان مجزأ وغير عملي.
يحل Array of Structs هذا الأمر بشكل نظيف من خلال تخزين جميع تضمينات التصحيح داخل حقل واحد، مما يسمح لـ Milvus بمعالجة الصفحة ككيان واحد متماسك متعدد المتجهات.
يعتمد البحث التقليدي لملفات PDF التقليدية غالبًا على التعرف الضوئي على الحروف OCR، والذي يحول صور الصفحة إلى نص. يعمل هذا مع النص العادي ولكنه يفقد المخططات والجداول والتخطيط والإشارات البصرية الأخرى. يتجنب ColPali هذا القيد من خلال العمل مباشرةً على صور الصفحات، مع الحفاظ على جميع المعلومات المرئية والنصية. المفاضلة هي الحجم: تحتوي كل صفحة الآن على مئات المتجهات، وهو ما يتطلب قاعدة بيانات يمكنها تجميع العديد من التضمينات في كيان واحد - وهو بالضبط ما توفره Array of Structs + MAX_SIM.
حالة الاستخدام الأكثر شيوعًا هي Vision RAG، حيث تصبح كل صفحة PDF كيانًا متعدد المتجهات. تتضمن السيناريوهات النموذجية ما يلي:
التقارير المالية: البحث في آلاف ملفات PDF عن الصفحات التي تحتوي على مخططات أو جداول محددة.
العقود: استرداد البنود من المستندات القانونية الممسوحة ضوئيًا أو المصورة.
الفواتير: البحث عن الفواتير حسب البائع أو المبلغ أو التخطيط.
العروض التقديمية: تحديد موقع الشرائح التي تحتوي على شكل أو مخطط معين.
نموذج البيانات:
{
"page_id": int, # Page ID (primary key)
"page_number": int, # Page number within the document
"doc_name": VARCHAR, # Document name
"patches": ARRAY<STRUCT< # Array of patch objects
patch_embedding: FLOAT_VECTOR(128) # Embedding for each patch
>>
}
الخطوة 1: إعداد البياناتيمكنك الرجوع إلى المستند للحصول على تفاصيل حول كيفية تحويل ColPali للصور أو النصوص إلى تمثيلات متعددة المتجهات.
import torch
from PIL import Image
from colpali_engine.models import ColPali, ColPaliProcessor
model_name = “vidore/colpali-v1.3”
model = ColPali.from_pretrained(
model_name,
torch_dtype=torch.bfloat16,
device_map=“cuda:0”, # or “mps” if on Apple Silicon
).eval()
processor = ColPaliProcessor.from_pretrained(model_name)
# Example: 2 documents, 5 pages each, total 10 images
images = [
Image.open(“path/to/your/image1.png”),
Image.open(“path/to/your/image2.png”),
…
Image.open(“path/to/your/image10.png”)
]
# Convert each image into multiple patch embeddings
batch_images = processor.process_images(images).to(model.device)
with torch.no_grad():
image_embeddings = model(**batch_images)
الخطوة 2: إنشاء مجموعة ميلفوس
from pymilvus import MilvusClient, DataType
client = MilvusClient(uri=“http://localhost:19530”)
schema = client.create_schema()
schema.add_field(“page_id”, DataType.INT64, is_primary=True)
schema.add_field(“page_number”, DataType.INT64)
schema.add_field(“doc_name”, DataType.VARCHAR, max_length=500)
# Struct Array for patches
struct_schema = client.create_struct_field_schema()
struct_schema.add_field(“patch_embedding”, DataType.FLOAT_VECTOR, dim=128)
schema.add_field(“patches”, DataType.ARRAY,
element_type=DataType.STRUCT,
struct_schema=struct_schema, max_capacity=2048)
client.create_collection(“doc_pages”, schema=schema)
الخطوة 3: إدراج البيانات وإنشاء الفهرس
# Prepare data for insertion
page_data=[
{
"page_id": 0,
"page_number": 0,
"doc_name": "Q1_Financial_Report.pdf",
"patches": [
{"patch_embedding": emb} for emb in image_embeddings[0]
],
},
...,
{
"page_id": 9,
"page_number": 4,
"doc_name": "Product_Manual.pdf",
"patches": [
{"patch_embedding": emb} for emb in image_embeddings[9]
],
},
]
client.insert(“doc_pages”, page_data)
# Create index
index_params = client.prepare_index_params()
index_params.add_index(
field_name="patches[patch_embedding]",
index_type=“HNSW”,
metric_type=“MAX_SIM_IP”,
params={“M”: 32, “efConstruction”: 200}
)
client.create_index(“doc_pages”, index_params)
client.load_collection(“doc_pages”)
الخطوة 4: البحث متعدد الوسائط: استعلام نصي ← نتائج الصور
# Run the search
from pymilvus.client.embedding_list import EmbeddingList
queries = [
“quarterly revenue growth chart”
]
# Convert the text query into a multi-vector representation
batch_queries = processor.process_queries(queries).to(model.device)
with torch.no_grad():
query_embeddings = model(**batch_queries)
query_emb_list = EmbeddingList()
for vec in query_embeddings[0]:
query_emb_list.add(vec)
results = client.search(
collection_name=“doc_pages”,
data=[query_emb_list],
anns_field="patches[patch_embedding]",
search_params={
“metric_type”: “MAX_SIM_IP”,
“params”: {“ef”: 100, “retrieval_ann_ratio”: 3}
},
limit=3,
output_fields=[“page_id”, “doc_name”, “page_number”]
)
print(f"Query: '{queries[0]}'")
for i, hit in enumerate(results, 1):
entity = hit[‘entity’]
print(f"{i}. {entity[‘doc_name’]} - Page {entity[‘page_number’]}")
print(f" Score: {hit[‘distance’]:.4f}\n")
عينة من المخرجات:
Query: 'quarterly revenue growth chart'
1. Q1_Financial_Report.pdf - Page 2
Score: 0.9123
2. Q1_Financial_Report.pdf - Page 1
Score: 0.7654
3. Product_Manual.pdf - Page 1
Score: 0.5231
هنا، تعرض النتائج مباشرةً صفحات PDF كاملة. لا داعي للقلق بشأن تضمين 1024 رقعة أساسية - يعالج ميلفوس كل التجميع تلقائيًا.
الخلاصة
تخزن معظم قواعد البيانات المتجهة كل جزء كسجل مستقل، مما يعني أن التطبيقات يجب أن تعيد تجميع تلك الأجزاء عندما تحتاج إلى مستند أو منتج أو صفحة كاملة. مصفوفة من الهياكل تغير ذلك. من خلال الجمع بين الكميات القياسية والمتجهات والنصوص والحقول الأخرى في كائن منظم واحد، فهي تسمح لصف واحد في قاعدة البيانات بتمثيل كيان واحد كامل من البداية إلى النهاية.
والنتيجة بسيطة ولكنها قوية: العمل الذي كان يتطلب تجميعًا معقدًا وإلغاءً وإعادة ترتيب في طبقة التطبيق يصبح قدرة قاعدة بيانات أصلية. وهذا هو بالضبط ما يتجه إليه مستقبل قواعد البيانات المتجهة - هياكل أكثر ثراءً واسترجاعًا أكثر ذكاءً وخطوط أنابيب أبسط.
لمزيد من المعلومات حول صفيف الهياكل و MAX_SIM، راجع الوثائق أدناه:
هل لديك أسئلة أو تريد التعمق في أي ميزة في أحدث إصدار من Milvus؟ انضم إلى قناة Discord الخاصة بنا أو قم بتسجيل المشكلات على GitHub. يمكنك أيضًا حجز جلسة فردية مدتها 20 دقيقة للحصول على رؤى وإرشادات وإجابات لأسئلتك من خلال ساعات عمل Milvus المكتبية.
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word



