البحث الدلالي بالمتجهات وموضوعات أخرى لكسب الأصدقاء والمحبين
مشهد البحث الكامل: البحث المطابق، والتقريبي، والدلالي، والهجين — ومتى تجمع بينها كلها.
في هذه الصفحة
- مشهد البحث المتجهي: مقارنة 16 خيارًا
- المصطلحات المستخدمة في هذا الدليل
- كيف تعثر التضمينات على المحتوى المرتبط
- متى يتفوق pgvector
الأقسام الفرعية
- اجمع الكلمات المفتاحية والمتجهات للاستعلامات المختلطة
- طابق كل واجهة بحث مع أنواع الاستعلامات الخاصة بها
الأقسام الفرعية
- متى تتجاوز pgvector
- لا تضمّن المعرّفات وتتوقع مطابقات تامة
- ابنِ البحث حول شكل الاستعلام
البحث ليس شيئًا واحدًا، والبحث الدلالي ليس بديلًا عن بقية أنواعه.
مشهد البحث المتجهي: مقارنة 16 خيارًا
قارن بين أساليب النشر، والتراخيص، وقدرات البحث، ومدى ملاءمة كل خيار لأحمال العمل. ترد شروحات الأعمدة وأمثلة SQL أدناه.
| قاعدة البيانات | النشر | الترخيص | البحث الهجين | المتجهات المتناثرة | واجهة الاستعلام | التضمين متعدد الوسائط المدمج | فهرس على القرص | حدود أبعاد المتجه | أفضل ملاءمة |
|---|---|---|---|---|---|---|---|---|---|
| pgvector | استضافة ذاتية / مُدار (Supabase، Neon، RDS) | مفتوح المصدر (PostgreSQL) | يدوي (RRF عبر SQL) | ❌ | ✅ SQL كامل | ❌ | ✅ HNSW على القرص | 16,000 للتخزين؛ 2,000 للفهرسة vector | استخدام PostgreSQL مسبقًا؛ أعداد متجهات متوسطة |
| Qdrant | استضافة ذاتية / سحابي | Apache 2.0 | ✅ BM25 أصلي | ✅ دعم ناضج | ❌ (REST/gRPC) | ❌ | ✅ | 65,535 | استعلامات مفلترة على نطاق واسع؛ بيانات وصفية معقدة |
| Weaviate | استضافة ذاتية / سحابي | BSD 3 | ✅ BM25 أصلي + RRF | ✅ | ❌ (GraphQL / gRPC) | ✅ عبر الوحدات | ✅ | 65,535 | أنماط وصول GraphQL؛ تحويل متجهي مدمج |
| Pinecone | سحابي فقط | مملوك | ✅ (أُضيف في 2024) | ✅ | ❌ | ❌ | ✅ (بلا خوادم) | 20,000 | بساطة الخدمة المُدارة؛ من دون فريق تشغيل |
| Milvus / Zilliz | استضافة ذاتية / سحابي (Zilliz) | Apache 2.0 | ✅ أصلي | ✅ | ✅ شبيه بـ SQL (لغة استعلام Milvus) | ✅ | ✅ DiskANN | 32,768 | نطاق المليارات؛ نشر مؤسسي داخل مقر المؤسسة |
| Chroma | مضمّن / استضافة ذاتية | Apache 2.0 | ❌ | ❌ | ❌ | ❌ | ❌ | 65,535 | التطوير المحلي والنمذجة الأولية فقط |
| LanceDB | مضمّن / سحابي | Apache 2.0 | ✅ | ❌ | ✅ SQL عبر DataFusion | ✅ أصلي | ✅ (تنسيق Lance) | غير محدود | الحافة / بلا خوادم؛ بحيرة بيانات متعددة الوسائط |
| Orama | مضمّن / سحابي | Apache 2.0 | ✅ نص كامل + متجهات | ❌ | ❌ | ❌ | ❌ | يختلف | تطبيقات JS/الحافة؛ بحث خفيف للمواقع والتطبيقات |
| Turbopuffer | سحابي فقط (بلا خوادم) | مملوك | ✅ BM25 + متجهات | ❌ | ❌ | ❌ | ✅ (تخزين الكائنات) | 16,000 | برمجيات SaaS متعددة المستأجرين؛ ملايين مساحات الأسماء |
| Elasticsearch | استضافة ذاتية / Elastic Cloud | SSPL / AGPLv3 | ✅ RRF + ELSER المتناثر | ✅ (ELSER) | ✅ Query DSL | ❌ | ✅ DiskBBQ | 4,096 | استخدام حزمة Elastic مسبقًا؛ بحث مؤسسي هجين |
| OpenSearch | استضافة ذاتية / مُدار عبر AWS | Apache 2.0 | ✅ RRF + البحث العصبي | ✅ | ✅ Query DSL | ❌ | ✅ FAISS + HNSW | 16,000 | أصلي لـ AWS؛ بديل مفتوح المصدر لـ Elastic |
| Vespa | استضافة ذاتية / سحابي | Apache 2.0 | ✅ أصلي | ✅ موترات / ترتيب معجمي | ✅ YQL | ✅ موترات | ✅ | غير محدود عمليًا | أنظمة البحث + الترتيب + التوصية |
| ClickHouse | استضافة ذاتية / سحابي | Apache 2.0 | يدوي | ❌ | ✅ SQL كامل | ❌ | ✅ عمودي + HNSW | يختلف | التحليلات والسجلات مع البحث المتجهي إلى جانب OLAP |
| MongoDB Atlas | سحابي / استضافة ذاتية | SSPL | ✅ مدمج | ❌ | ✅ MQL + التجميع | ❌ | ✅ HNSW | 8,192 | استخدام MongoDB مسبقًا؛ المستندات والمتجهات في مكان واحد |
| Redis (VSS) | استضافة ذاتية / Redis Cloud | RSALv2 / SSPL | ✅ (RediSearch) | ✅ | ❌ | ❌ | ❌ في الذاكرة فقط | 32,768 | زمن استجابة بالغ الانخفاض؛ بحث متجهي في طبقة التخزين المؤقت |
| Marqo | سحابي / استضافة ذاتية | Apache 2.0 | ✅ | ❌ | ❌ | ✅ تركيز أصلي | ✅ | يختلف | متعدد الوسائط من البداية إلى النهاية: صورة + نص + فيديو |
«العثور على مستخدم بعنوان البريد الإلكتروني dan@example.com» و«العثور لي على مقالات عن تصحيح الأخطاء بصفتي مهندسًا جديدًا» يوصفان كلاهما بأنهما بحث، لكن لا يكاد يجمعهما شيء من ناحية المشكلة الهندسية. للأول إجابة صحيحة وفحص فهرس بتعقيد O(log n). أما الثاني فلا إجابة صحيحة له — بل صلة فقط — ويتطلب فهم اللغة والنية والمعنى.
المهندسون الأكثر إقناعًا في قرارات البحث — أولئك الذين يكسبون النقاشات ويشحنون النظام الصحيح — يفهمون المشهد بأكمله. يعرفون الأداة التي ينبغي اللجوء إليها وسبب ذلك، ويستطيعون شرح الأمر بوضوح.
يغطي هذا المقال الطبقة الدلالية: ما الذي يفعله البحث المتجهي فعلًا، ومتى يتفوق، وأين ينبغي أن يبتعد عن الطريق. النسخة المفيدة ليست «حوّل كل شيء إلى تضمينات». بل معرفة متى تنتمي المتجهات إلى جانب البحث المعجمي، والضبابي، والبحث بالمطابقة التامة ضمن بنية هجينة.
النصف المعجمي والضبابي من الصورة — tsvector وpg_trgm وpg_search — موضح في دليل البحث النصي في Postgres لعام 2026.
المصطلحات المستخدمة في هذا الدليل
التضمين — قائمة كثيفة من أعداد الفاصلة العائمة تنتجها نماذج، وتمثل قطعة من النص (أو صورة أو صوت وغير ذلك) كنقطة في فضاء عالي الأبعاد. تصل المحتويات ذات الصلة دلاليًا إلى نقاط متقاربة؛ بينما تتباعد المحتويات غير المرتبطة.
البحث المعجمي — بحث يستند إلى المطابقة التامة للكلمات والرموز. سريع وحتمي وصحيح للمصطلحات المعروفة. لكنه لا يفهم المرادفات أو إعادة الصياغة أو المكافئات عبر اللغات.
البحث الدلالي — بحث يستند إلى المعنى بدلًا من الرموز. يمكن لاستعلام عن «كيف أتعامل مع انتهاء المهلة» أن يطابق مستندًا بعنوان «تهيئة سياسات إعادة المحاولة» من دون كلمات مشتركة، لأن التضمينين متقاربان هندسيًا.
المتجه — قائمة من الأعداد. في سياق البحث، هو ناتج نموذج التضمين. يعثر «البحث المتجهي» على المتجهات الأقرب إلى متجه الاستعلام وفق المسافة الهندسية.
FTS (البحث في النص الكامل) — البحث المعجمي المدمج في Postgres، والمدعوم بـ tsvector / tsquery. يقسم النص إلى رموز، ويستخلص جذورها، ويفهرسه لاستعلامات الكلمات المفتاحية. قوي للنثر والبحث عن المصطلحات التامة؛ لكنه لا يرى المعنى.
BM25 — خوارزمية لترتيب نتائج البحث المعجمي (تستخدمها Elasticsearch وQdrant وغيرهما). تسجل النتائج وفق تكرار المصطلح، مع ترجيحه بحسب مدى ندرته في كامل مجموعة البيانات. أفضل من مطابقة الكلمات المفتاحية الخام؛ لكنها تظل معجمية.
HNSW (العالم الصغير الهرمي القابل للملاحة) — الفهرس القياسي التقريبي لأقرب الجيران في البحث المتجهي. ينشئ رسمًا بيانيًا طبقيًا للتقارب من أجل استعلامات تشابه سريعة وعالية الاستدعاء. تستخدمه pgvector وQdrant وWeaviate ومعظم الأدوات الأخرى.
RRF (دمج الرتب التبادلية) — خوارزمية لدمج قوائم النتائج المرتبة القادمة من أنظمة استرجاع متعددة. تعتمد على موضع النتيجة في الترتيب فقط، ولا تحتاج إلى تطبيع الدرجات. تحصل النتيجة التي تحتل ترتيبًا مرتفعًا في قائمتي FTS والمتجهات على درجة مجمعة أقوى من نتيجة تتفوق في قائمة واحدة فقط.
كيف تعثر التضمينات على المحتوى المرتبط
تحوّل التضمينات المتجهية النص (أو الصور أو الصوت وغير ذلك) إلى قائمة من الأرقام — أي نقطة في فضاء عالي الأبعاد. ويُدرَّب نموذج التضمين بحيث تصل النصوص المتقاربة دلاليًا إلى نقاط متقاربة في ذلك الفضاء. ينتهي الأمر بكلمتي “Dog” و”canine” متقاربتين. أما عبارتا “Running a marathon” و”running a Python script” فتبتعدان عن بعضهما، رغم اشتراكهما في كلمة واحدة.
يبحث البحث عن التشابه في ذلك الفضاء عن المستندات التي يقترب معناها أكثر من معنى الاستعلام، بغض النظر عن التطابق الحرفي للكلمات.
وهذا يعني أن:
- يمكن لعبارة “How do I configure request timeouts?” أن تطابق مقالًا بعنوان “Setting connection limits and retry policies” — لا توجد كلمات مفتاحية مشتركة، لكن الصلة المفاهيمية قوية
- يمكن لعبارة “Something light for a summer evening” أن تطابق توصية بنبيذ، حتى من دون ظهور أي من كلماتها المفتاحية في وصف المنتج
- يمكن لاستعلام باللغة الإنجليزية أن يطابق مستندات ذات صلة بالفرنسية أو الإسبانية أو اليابانية، إذا دُرِّب نموذج التضمين على عدة لغات
لا يستطيع البحث المعجمي (tsvector، pg_trgm) فعل أي من ذلك. فهو يعمل على الكلمات والمحارف، لا على المعنى. الأداتان ليستا بديلين متكافئين — إذ تحل كل منهما نوعًا مختلفًا من المشكلات.
متى يتفوق pgvector
عند بناء RAG. يسترجع التوليد المعزَّز بالاسترجاع (Retrieval-Augmented Generation) مقاطع المستندات الأقرب من حيث المعنى إلى سؤال المستخدم، ثم يمررها إلى نموذج لغوي بوصفها سياقًا. خطوة الاسترجاع هذه عملية متجهية. سيفوّت FTS إعادة الصياغة والمرادفات والتطابقات المفاهيمية التي قد يعبّر بها مقطع ذو صلة بطريقة مختلفة. وتتمثل أفضلية pgvector على مخزن متجهات مستقل في أنه يعمل داخل مثيل Postgres الموجود لديك — فلا توجد خدمة منفصلة لنشرها أو تشغيلها أو مزامنة البيانات معها.
عندما يصف المستخدمون ما يريدونه، لا ما ينبغي البحث عنه. لا تحتوي عبارة “Articles about building confidence as a new manager” على كلمات مفتاحية يُرجَّح ظهورها بشكل موثوق في المنشورات ذات الصلة. وقد لا تستخدم عبارة “A lightweight framework for handling side effects” الكلمات نفسها حرفيًا في الوثائق. يطابق البحث المتجهي القصد، لا التهجئة.
العثور على العناصر المتشابهة. منتجات ذات صلة، أو تذاكر دعم متشابهة، أو تقارير أخطاء مكررة، أو مقالات قد تهمك أيضًا. إن عبارة “Find issues similar to this one” هي بحث عن أقرب الجيران — تضمّن العنصر، ثم اعثر على جيرانه الهندسيين. لكن هناك تحذير مهم: يعيد البحث المتجهي نتائج دائمًا، حتى عندما لا يكون أي منها مشابهًا فعلًا. في حالات إزالة التكرار والتوصيات، صفِّ النتائج باستخدام حد أدنى للتشابه (مثلًا، تشابه جيب التمام ≥ 0.80) لتجنب عرض مطابقات منخفضة الثقة كما لو كانت ذات معنى.
إزالة التكرار الدلالي. قبل فهرسة المحتوى لأغراض RAG أو البحث، تحتاج غالبًا إلى تحديد النسخ شبه المكررة داخل مجموعة البيانات — مثل المقالات التي نُقحت عدة مرات، أو تذاكر الدعم التي أُرسلت مرتين، أو إدخالات قاعدة المعرفة المتداخلة بدرجة كبيرة. ضمّن المستندات، ثم صفِّها وفق عتبة تشابه جيب التمام لتمييز النسخ شبه المكررة أو دمجها قبل أن تلوّث الفهرس. يمنع ذلك الاسترجاع من إعادة عدة مقاطع متطابقة تقريبًا وتخفيف كثافة المعلومات في نافذة السياق.
البحث متعدد اللغات. تربط نماذج التضمين متعددة اللغات المحتوى المتكافئ دلاليًا عبر اللغات بمتجهات متقاربة. ويمكن لاستعلام بالإسبانية عن “perder peso” أن يطابق مقالًا إنجليزيًا عن “sustainable weight loss habits” — لا توجد رموز مشتركة، لكن المعنى الأساسي واحد. يتطلب FTS إعداد قاموس خاص بكل لغة، ويتعامل بصورة سيئة مع الاستعلامات العابرة للغات. أما pg_trgm فهو مستقل عن اللغة، لكنه إملائي لا دلالي.
إعداد pgvector
من تثبيت الامتداد إلى تنفيذ استعلام التشابه، لا يتطلب الإعداد سوى عدد قليل من عبارات SQL:
CREATE EXTENSION IF NOT EXISTS vector;
ALTER TABLE documents ADD COLUMN embedding vector(1536);
-- HNSW is usually the first index to try for moderate-size datasetsCREATE INDEX documents_embedding_idx ON documents USING hnsw (embedding vector_cosine_ops);
-- Semantic search querySELECT id, title, 1 - (embedding <=> $1::vector) AS similarityFROM documentsORDER BY embedding <=> $1::vectorLIMIT 10;<=> هي مسافة جيب التمام. ويعطي 1 - cosine_distance تشابه جيب التمام (1.0 = متطابق، و0.0 = متعامد). وبالنسبة إلى ivfflat (البديل الأقدم والأسرع في البناء)، استخدم lists = sqrt(row_count) كنقطة بداية.
أين يعيد البحث المتجهي الإجابة الخاطئة
- مطابقة الرموز المميزة حرفيًا — مثل رموز المنتجات، ورموز الأخطاء، وأسماء الدوال.
ORD-12345ليس مشابهًا دلاليًا لأي شيء. وقد يعيد البحث المعتمد على التضمينات ORD-12344أو لا يعيد شيئًا ذا صلة. استخدم FTS أو فهرس B-tree. - الأسماء وأسماء الأعلام. ينظّم فضاء التضمينات العناصر حسب المعنى، لا حسب التهجئة. وسجل المستخدم
"Micheal Jordan"لا يقع بالضرورة قرب"Michael Jordan"في فضاء المتجهات. - السلاسل القصيرة التي تكون فيها مشابهة الأحرف أهم من المعنى. يتولى
pg_trgmهذه الحالة. - الاستعلامات التي يجب أن يظهر فيها المصطلح حرفيًا. يكون BM25 وFTS أكثر موثوقية في مطابقة المصطلحات المعروفة.
اجمع الكلمات المفتاحية والمتجهات للاستعلامات المختلطة
تُعد الوثائق التقنية أوضح مثال على حالة لا تكفي فيها أي من الأداتين بمفردها.
فالمستخدمون الذين يبحثون عن "how to configure timeouts" يحتاجون إلى مطابقة مفاهيمية: إذ لا يحتوي مقال بعنوان "Setting retry policies and connection limits" على كلمات مفتاحية مشتركة، لكنه بالضبط ما يحتاجون إليه.
لكن المستخدمين أنفسهم يبحثون أيضًا عن withRetry() وECONNRESET وERR_SOCKET_TIMEOUT. يجب أن تظهر هذه السلاسل حرفيًا — وقد لا يعثر عليها التطابق الدلالي بشكل موثوق، كما أن النتيجة الإيجابية الكاذبة (مشابهة مفاهيميًا، لكنها ليست واجهة البرمجة الصحيحة) مضللة فعليًا.
يتولى البحث المتجهي الاستعلامات المفاهيمية. ويتولى FTS المصطلحات الحرفية. ولا يتعامل أي منهما مع الحالتين جيدًا بمفرده.
الحل هو البحث الهجين: شغّل النظامين معًا وادمج النتائج.
ادمج النتائج المرتبة باستخدام RRF
دمج الرتب التبادلي (Reciprocal Rank Fusion، أو RRF) هو الخوارزمية القياسية لدمج القوائم المرتبة القادمة من أنظمة استرجاع مختلفة. ولا يحتاج إلى توحيد النتائج الرقمية بين الأنظمة — فهو يستخدم مواضع الترتيب فقط. وتحصل النتيجة التي تظهر في مرتبة عالية في كلتا القائمتين على درجة مجمعة أقوى من نتيجة تهيمن على قائمة واحدة فقط.
WITH fts_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY ts_rank(search_vector, query) DESC) AS rank FROM documents, to_tsquery('english', $1) query WHERE search_vector @@ query LIMIT 50),vector_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY embedding <=> $2::vector) AS rank FROM documents ORDER BY embedding <=> $2::vector LIMIT 50),rrf AS ( SELECT COALESCE(f.id, v.id) AS id, COALESCE(1.0 / (60 + f.rank), 0) + COALESCE(1.0 / (60 + v.rank), 0) AS rrf_score FROM fts_results f FULL OUTER JOIN vector_results v ON f.id = v.id)SELECT d.id, d.title, rrf.rrf_scoreFROM rrfJOIN documents d ON d.id = rrf.idORDER BY rrf_score DESCLIMIT 10;العدد 60 في المقام هو ثابت RRF. تؤدي القيم الأعلى إلى تخفيف الفروق بين مواضع الترتيب، بينما تضخمها القيم الأقل. وتعمل القيمة الافتراضية 60 جيدًا مع معظم أنواع المحتوى.
يتجنب RRF المشكلة الأصعب المتمثلة في توحيد ts_rank (وهي درجة تعتمد على التكرار اللوغاريتمي) مع مسافة جيب التمام (وهي مقياس هندسي). فهما غير قابلين للمقارنة. ولا يسأل RRF إلا: «ما مدى ارتفاع ترتيب هذه النتيجة في كل قائمة؟»
أضف الترايغرامات للتعامل مع الأخطاء الإملائية والأسماء
في البحث الموجه للمستخدمين على محتوى مختلط — حيث قد يبحث المستخدم في الجلسة نفسها عن اسم شخص، أو مفهوم، أو مصطلح حرفي — يتولى الدمج ثلاثي الاتجاهات الحالات كلها:
WITH trgm_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY similarity(title, $1) DESC) AS rank FROM documents WHERE title % $1 LIMIT 50),fts_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY ts_rank(search_vector, to_tsquery('english', $1)) DESC) AS rank FROM documents WHERE search_vector @@ to_tsquery('english', $1) LIMIT 50),vector_results AS ( SELECT id, ROW_NUMBER() OVER (ORDER BY embedding <=> $2::vector) AS rank FROM documents ORDER BY embedding <=> $2::vector LIMIT 50),rrf AS ( SELECT COALESCE(t.id, f.id, v.id) AS id, COALESCE(1.0 / (60 + t.rank), 0) + COALESCE(1.0 / (60 + f.rank), 0) + COALESCE(1.0 / (60 + v.rank), 0) AS rrf_score FROM trgm_results t FULL OUTER JOIN fts_results f ON t.id = f.id FULL OUTER JOIN vector_results v ON COALESCE(t.id, f.id) = v.id)SELECT d.id, d.title, rrf.rrf_scoreFROM rrfJOIN documents d ON d.id = rrf.idORDER BY rrf_score DESCLIMIT 10;يتعامل هذا مع: مطابقة الأسماء بشكل تقريبي (الترايغرامات)، ومطابقة الكلمات المفتاحية حرفيًا (FTS)، والاستعلامات المفاهيمية (المتجهات). ويمكن لمربع بحث واحد خدمة أنواع نوايا المستخدم الثلاثة.
طابق كل واجهة بحث مع أنواع الاستعلامات الخاصة بها
نادرًا ما تحتوي التطبيقات الفعلية على واجهة بحث واحدة. فهي تحتوي على واجهات متعددة، لكل منها احتياج مختلف:
| الواجهة | ما الذي يستعلم عنه المستخدمون | الطبقات الموصى بها |
|---|---|---|
| البحث في المدونة / الوثائق | الكلمات المفتاحية + المفاهيم | FTS + pgvector (RRF) |
| البحث عن اسم مستخدم / عميل | الأسماء التي تحتوي على أخطاء إملائية | pg_trgm |
| البحث عن المنتجات | الأسماء والأوصاف وعبارة «مشابه لـ» | pg_trgm + FTS + pgvector |
| إزالة التكرار في تذاكر الدعم | «مشكلات مشابهة لهذه» | pgvector فقط |
| البحث الداخلي عن SKU / الطلبات | المعرّفات الدقيقة | فهرس B-tree |
| RAG فوق قاعدة معرفية كبيرة | الأسئلة باللغة الطبيعية | pgvector (مستندات مجزأة) |
| «قد يعجبك أيضًا» في التجارة الإلكترونية | التشابه السلوكي + الدلالي | pgvector |
| الإكمال التلقائي | البادئة، مع تحمّل الأخطاء الإملائية | pg_trgm |
هذه ليست حالات افتراضية. تحتاج معظم التطبيقات الغنية بالمحتوى إلى واجهتي بحث مختلفتين على الأقل، لكل منهما أشكال استعلام مختلفة. الإغراء هنا هو اختيار نهج واحد واستخدامه في كل مكان — وغالبًا ما يكون البحث المتجهي الآن، لأنه الخيار الرائج. وهذا يؤدي إلى إنشاء تضمينات مكلفة لمشكلات كان فهرس الترايغرَام سيعالجها بسرعة أكبر، وبتكلفة أقل، وبدقة أعلى.
أضف طبقة بحث عندما يفشل نوع من الاستعلامات
أضف طبقة عندما يظهر نمط فشل لا تستطيع الطبقة الحالية إصلاحه:
- يشكو المستخدمون من أن الأخطاء الإملائية لا تؤدي إلى مطابقات → أضف
pg_trgm - يبحث المستخدمون بالمفهوم ويفوّتون النتائج ذات الصلة → أضف pgvector
- يبحث المستخدمون عن رموز أو أكواد دقيقة، لكنهم يحصلون بدلًا من ذلك على نتائج مفاهيمية → أضف FTS أو تحقّق مما إذا كنت تعتمد أكثر من اللازم على البحث المتجهي
- تصبح زمن الاستجابة مشكلة → قيّم التصفية المسبقة، أو الفهارس التقريبية، أو مخزنًا مخصصًا
متى تتجاوز pgvector
تتعامل pgvector مع قدر كبير من احتياجات البحث في التطبيقات قبل أن تحتاج إلى قاعدة بيانات أخرى. يعتمد الحد التقريبي على عدد المتجهات، وإعدادات الفهرس، ومعدل الكتابة، والمرشحات، والعتاد، والتزامن؛ لذلك تعامل مع أي قاعدة من نوع «أقل من 10 ملايين متجه» بوصفها افتراضًا أوليًا يحتاج إلى قياس معياري، لا حدًا للمنتج. وعندما تتجاوز قدراتها فعلًا — بسبب التزامن المرتفع جدًا، أو متطلبات p99 منخفضة جدًا لزمن الاستجابة، أو مليارات المتجهات، أو الحاجة الجادة إلى عزل المستأجرين — فإن منظومة قواعد البيانات المتجهية المخصصة واسعة وتستحق الفهم.
كيف تقرأ المقارنة
البحث الهجين يعني أن بحث الكلمات المفتاحية باستخدام BM25 وتشابه المتجهات يعملان ضمن استعلام واحد، ثم تُدمج النتائج عبر RRF. ومن دونه، إما أن تختار نمط بحث واحدًا، أو تدمج الاستعلامين بنفسك.
المتجهات المتناثرة تتجاوز BM25. يحتوي المتجه المتناثر SPLADE على نحو 30,000 بُعد (بُعد واحد لكل مصطلح في المفردات)، ويكون نحو 98% منها أصفارًا. تخبرك المواضع غير الصفرية بالمصطلحات المهمة ودرجة أهميتها. فالاستعلام عن «dogs» يضع وزنًا أيضًا على «canine» و«pet» — دقة على مستوى BM25، مع توسيع للمصطلحات داخل فهرس متجهي. إذا كان هذا العمود يساوي false، فستحتاج إلى طبقة FTS منفصلة للاستعلامات التي تتطلب مطابقة المصطلحات بدقة.
# SPLADE: ~30,000 dims, ~60 non-zero — only relevant vocabulary positions firedef encode_splade(text: str) -> dict: tokens = tokenizer(text, return_tensors="pt", truncation=True, max_length=512) with torch.no_grad(): output = model(**tokens) vec = torch.log1p(torch.relu(output.logits)).max(dim=1).values.squeeze() return {"indices": vec.nonzero().squeeze().tolist(), "values": vec[vec != 0].tolist()}SQL / ما يشبه SQL يتعلق في الواقع بالتصفية. البحث المتجهي من دون تصفية مجرد عرض تجريبي. ستظل بحاجة إلى تحديد نطاق المستأجر، ونطاقات زمنية، وصلاحيات، ومرشحات للفئات. تتيح SQL الكاملة (في pgvector وLanceDB) التعبير عن ذلك إلى جانب عمليات الربط الموجودة لديك. أما قواعد البيانات المصممة لهذا الغرض فتستخدم كائنات مرشحات JSON (في Qdrant وPinecone)، أو لغة DSL للاستعلام (في Elasticsearch وMilvus)، أو GraphQL (في Weaviate). كل هذه الخيارات تعمل؛ لكن SQL تصبح أكثر جاذبية كلما ازداد تعقيد منطق التصفية.
-- pgvector: vector similarity is just another expressionSELECT id, title, 1 - (embedding <=> $1) AS scoreFROM documentsWHERE tenant_id = $2 AND category = ANY($3::text[]) AND created_at > NOW() - INTERVAL '90 days'ORDER BY embedding <=> $1LIMIT 10;# Qdrant: equivalent filter as a Python object — same result, more ceremonyresults = client.query_points( collection_name="documents", query=query_embedding, query_filter=models.Filter(must=[ models.FieldCondition(key="tenant_id", match=models.MatchValue(value=tenant_id)), models.FieldCondition(key="category", match=models.MatchAny(any=categories)), models.FieldCondition(key="created_at", range=models.DatetimeRange(gte=cutoff)), ]), limit=10,)الدعم الأصلي للوسائط المتعددة يعني أن قاعدة البيانات توفر نماذج تضمين للمحتوى غير النصي. تعطيها عنوان URL لصورة خام، وهي تتولى تحويلها إلى متجه. معظم قواعد البيانات غير مرتبطة بنموذج تضمين بعينه — وأنت المسؤول عن خط أنابيب التضمين. وتغلق Marqo وWeaviate (عبر وحدات CLIP/ImageBind) هذه الحلقة.
# Marqo: POST raw images, query with text — no external embedding stepmq.index("products").add_documents( [{"id": "shoe-001", "image": "https://cdn.example.com/shoes/001.jpg"}], tensor_fields=["image"])results = mq.index("products").search(q="lightweight shoes for summer")# Returns shoe-001 despite zero keyword overlap — CLIP handles the cross-modal matchالفهرس القائم على القرص أداة للتحكم في التكلفة. يمكن لفهارس HNSW المقيمة في الذاكرة أن تتطلب عدة غيغابايتات من الذاكرة لكل مليون متجه ذي 1536 بُعدًا، بعد احتساب المتجهات الخام، والحمل الإضافي للرسم البياني، والبيانات الوصفية. غالبًا ما توازن البدائل الأصلية للقرص — مثل Milvus DiskANN وElasticsearch DiskBBQ وتنسيق Lance في LanceDB وطبقة التخزين الكائني في Turbopuffer — بين قدر من زمن الاستعلام وتكلفة بنية تحتية أقل. وفي أحمال RAG التي يهيمن فيها زمن النموذج أصلًا، يستحق هذا التبادل القياس المعياري في كثير من الأحيان.
الحد الأقصى للأبعاد عملية ترحيل كامنة في معماريتك. يستخدم text-embedding-3-large عدد 3072 بُعدًا، ويمكن لـ Jina v3 إنتاج تضمينات أكبر، وتواصل النماذج البحثية دفع الأحجام إلى أعلى. تنشر بعض الخدمات المُدارة حدودًا قصوى صارمة للأبعاد؛ بينما توثق خدمات أخرى حدودًا مرتفعة أو لا تضع حدًا عمليًا لنماذج التضمين المعتادة. راجع الوثائق الحالية قبل الالتزام. اختر خيارًا يترك هامشًا للنمو؛ فترحيل فهرس متجهي لأنك اصطدمت بسقف الأبعاد عملية مؤلمة.
مفاضلات تشغيلية لا يستطيع الجدول إظهارها
تعدد المستأجرين في Turbopuffer مصمم للتعامل مع أعداد كبيرة جدًا من مساحات الأسماء. يركز طرحها العلني وقصص عملائها على أحمال مثل قاعدة Notion الكبيرة والغنية بمساحات الأسماء. إذا كان كل مستخدم أو مؤسسة يحتاج إلى بحث متجهي معزول، فقد تغير هذه المعمارية اقتصاديات الحل، لكن عليك مع ذلك قياس شكل المستأجرين لديك.
وضع LanceDB المضمّن هو أقرب ما يكون إلى «SQLite للبحث المتجهي». يعمل داخل العملية، ولا يتطلب خادمًا، ويعمل في Lambda وCloudflare Workers وبيئات الحافة. ويجعل تنسيق Lance العمودي التشغيل المضمّن عمليًا على نطاق حقيقي.
تتفوّق Chroma في التطوير/الاختبار ونشر التطبيقات الصغيرة. إذا كنت تستهدف مجموعات بيانات ضخمة جدًا، أو التوافر العالي، أو التشغيل المعتمد بكثافة على الأقراص، أو البحث الهجين المتكامل، فقيّم مخزنًا موجّهًا للإنتاج قبل أن تترقى بالنموذج الأولي إلى بنية تحتية.
Vespa هي ما تلجأ إليه عندما لا يكون الاسترجاع سوى نصف المنتج. فهي تجمع بين الاسترجاع المعجمي، والبحث بأقرب الجيران، والموترات، وتعبيرات الترتيب، والتجميع، والتقديم عبر الإنترنت. هذه القوة حقيقية، وكذلك التعقيد التشغيلي وتعقيد النمذجة. وهي تلائم فرق البحث/التوصيات أكثر من حالة «أضف البحث الدلالي إلى تطبيق CRUD لديّ».
ينبغي أن تكون ClickHouse ضمن الخيارات المطروحة عندما يكون البحث مرتبطًا بالتحليلات. إذا كانت قاعدة الحقيقة لديك هي الأحداث أو السجلات أو آثار التتبع أو المقاييس، فإن ClickHouse يجمع مسافة المتجه، والتصفية، والتجميع، والفهرسة الجادة للنص الكامل في محرك SQL واحد. إنها ليست قاعدة بيانات متجهية متخصصة، لكنها غالبًا الإجابة الصحيحة المملة للاسترجاع التحليلي.
المتجهات المتناثرة هي الطريقة التي تحصل بها على مطابقة كلمات مفتاحية بجودة BM25 داخل فهرس متجهي — من دون تشغيل محرك نص كامل منفصل. لدى Qdrant وElasticsearch تطبيقات ناضجة خصوصًا في هذا المجال. إذا كان البحث الهجين حاسمًا وكانت بنية النظامين غير مقبولة، فدعم المتجهات المتناثرة هو ما ينبغي أن تبحث عنه.
اختر المخزن وفقًا لحِمل العمل
- منتج SaaS مع عزل لكل مستأجر → Turbopuffer
- تصفية معقدة للبيانات الوصفية على نطاق واسع → Qdrant
- تستخدم بالفعل حزمة Elastic/ELK → Elasticsearch مع DiskBBQ
- فريق يستخدم AWS ويريد حلولًا مفتوحة المصدر → OpenSearch
- منصة بحث/توصيات ذات احتياجات جادة للترتيب → Vespa
- التحليلات، وقابلية الرصد، والبحث في السجلات/الأحداث → ClickHouse
- على نطاق المليارات داخل مقر العمل / مستضاف ذاتيًا → Milvus
- الحافة / عديم الخوادم / متعدد الوسائط → LanceDB
- تطبيق JavaScript صغير، أو موقع توثيق، أو تجربة بحث أصلية للحافة → Orama
- صفر عمليات، والتكلفة أولوية ثانوية → Pinecone
- متعدد الوسائط أولًا (الصور، والفيديو، والصوت) → Marqo
- تستخدم MongoDB بالفعل → Atlas Vector Search
- تستخدم Postgres بالفعل وتحتاج إلى هامش نمو أكبر → Supabase Vector أو Neon (كلاهما pgvector مُدار، مع أدوات أفضل)
لا تضمّن المعرّفات وتتوقع مطابقات تامة
لا تستخدم البحث المتجهي كبحث نصي تقريبي للأشياء التي لها إجابات صحيحة.
«اعثر لي على المستخدم الذي بريده الإلكتروني هو dan@example.com» ليست مسألة بحث متجهي. و«اعثر على الطلب ذي المعرّف ORD-12345» ليست كذلك. سيؤدي تضمين ORD-12345 والبحث باستخدام تشابه جيب التمام إلى إرجاع شيء ما — لكنه قد يكون خاطئًا. للمعرّف إجابة صحيحة. والمطابقة التقريبية للمعرّف خطأ.
يعيد البحث المتجهي العنصر الأكثر تشابهًا في مجموعة بياناتك، حتى عندما لا يكون أي شيء ذا صلة فعلية. فهو لا يعرف متى لا توجد إجابة جيدة. وهذا مقبول بالنسبة إلى المستندات ذات الصلة. لكنه مشكلة خطيرة عند البحث الدقيق عن سجل، حيث تكون الإجابة الخاطئة الواثقة أسوأ من نتيجة فارغة.
وينطبق الأمر نفسه في الاتجاه الآخر: لا تستخدم FTS للاستعلامات التي يصف فيها المستخدم مفهومًا. فعبارة «مقالات عن اتخاذ قرارات صعبة في ظل عدم اليقين» لا تحتوي على كلمات مفتاحية موثوقة. سيعيد FTS إما ضجيجًا أو لا شيء. استخدم الأداة المناسبة لشكل الاستعلام.
ابنِ البحث حول شكل الاستعلام
تحتاج معظم أنظمة البحث الإنتاجية إلى أكثر من طبقة واحدة:
pg_trgmللأسماء، والأخطاء المطبعية، والإكمال التلقائي- FTS /
pg_searchللبحث في النثر القائم على الكلمات المفتاحية - pgvector للاستعلامات الدلالية والمفاهيمية
- دمج RRF للواجهات التي يخلط فيها المستخدمون بين أنواع الاستعلامات
- الفهارس العادية للمعرّفات الدقيقة، والمرشحات، والقوائم المرتبة
هذه الأدوات ليست متنافسة؛ بل متكاملة. يختار نظام البحث المبني جيدًا الطبقة المناسبة لكل شكل من أشكال الاستعلام — وعندما تتداخل أشكال الاستعلام، يشغّل طبقات متعددة ويدمج النتائج.
تفهم الفرق التي تطلق ميزات بحث جيدة المكدس بأكمله. أما الفرق التي لا تفعل ذلك، فتتجه إلى قاعدة بيانات متجهية، وتضمّن كل شيء، ثم تتساءل لماذا تعيد عمليات البحث الدقيقة أحيانًا السجل الخطأ.
