- يحسب البحث الدقيق عن المتجهات المسافة بين النقطة المعطاة وجميع النقاط في الفضاء المتجهي. وهذا يضمن أعلى دقة ممكنة، أي إن النقاط المُعادة تكون مضمونة بوصفها أقرب الجيران الفعليين. ونظرًا إلى أن الفضاء المتجهي يُفحَص بالكامل، فقد يكون البحث الدقيق عن المتجهات بطيئًا جدًا للاستخدامات العملية.
- يشير البحث التقريبي عن المتجهات إلى مجموعة من التقنيات (مثل بُنى بيانات خاصة كالرُّسوم البيانية والغابات العشوائية) التي تحسب النتائج بسرعة أكبر بكثير من البحث الدقيق عن المتجهات. وعادةً ما تكون دقة النتائج “جيدة بما يكفي” للاستخدام العملي. كما توفّر العديد من التقنيات التقريبية معلمات لضبط المفاضلة بين دقة النتائج ووقت البحث.
vectors من نوع Array، مثل Array(Float64) أو Array(Float32) أو Array(BFloat16).
يكون المتجه المرجعي مصفوفةً ثابتة، ويُعرَّف كتعبير جدول شائع.
تحسب <DistanceFunction> المسافة بين النقطة المرجعية وجميع النقاط المخزَّنة.
ويمكن استخدام أي من دوال المسافة المتاحة لهذا الغرض.
ويحدّد <N> عدد الجيران المطلوب إرجاعهم.
البحث الدقيق عن المتجهات
مثال
البحث التقريبي عن المتجهات
فهارس تشابه المتجهات
تتوفّر فهارس تشابه المتجهات في ClickHouse الإصدار 25.8 وما بعده.
إذا واجهت أي مشكلات، يُرجى فتح بلاغ في مستودع ClickHouse.
إنشاء فهرس لتشابه المتجهات
ALTER TABLE أعلاه لا تؤدي إلا إلى إنشاء الفهرس للبيانات الجديدة التي ستُدرَج في الجدول لاحقًا.
ولإنشاء الفهرس للبيانات الموجودة أيضًا، تحتاج إلى إضفاء الطابع المادي عليه:
<distance_function> إحدى القيم التالية:
L2Distance، وهي المسافة الإقليدية، وتمثل طول القطعة المستقيمة بين نقطتين في الفضاء الإقليدي،cosineDistance، وهي مسافة جيب التمام، وتمثل الزاوية بين متجهين غير صفريين، أوdotProduct، وهو الضرب النقطي (الضرب الداخلي)، ويمثل مجموع نواتج الضرب عنصرًا بعنصر لمتجهين. وهو مكافئ لـcosineDistanceفي البيانات المُطبَّعة.
L2Distance عادةً الخيار الأفضل، وإلا فيُوصى باستخدام cosineDistance للتعويض عن اختلاف المقياس.
بالنسبة إلى دالتي المسافة
L2Distance وcosineDistance، فإن القيمة الأصغر تعني تشابهًا أعلى، بينما بالنسبة إلى dotProduct، فإن القيمة الأكبر تعني تشابهًا أعلى.
ونتيجة لذلك، لا يمكن استخدام فهارس المتجهات مع L2Distance وcosineDistance إلا في استعلامات SELECT [...] ORDER BY [...] ASC (حيث إن ASC هي القيمة الافتراضية لـ ORDER BY)، بينما لا يمكن استخدام فهارس المتجهات المُنشأة لـ dotProduct إلا في استعلامات SELECT [...] ORDER BY [...] DESC.<dimensions> عدد عناصر المصفوفة في العمود الأساسي.
إذا عثر ClickHouse على مصفوفة بعدد عناصر مختلف أثناء إنشاء الفهرس، فسيتم تجاهل الفهرس وإرجاع خطأ.
تشير المعلمة الاختيارية GRANULARITY <N> إلى حجم حبيبات الفهرس (انظر هنا).
وعلى خلاف فهارس التخطي العادية، التي تستخدم قيمة افتراضية لمحببية الفهرس مقدارها 1، تستخدم فهارس تشابه المتجهات 100 مليون بوصفها محببية الفهرس الافتراضية.
تضمن هذه القيمة ألّا يُنشأ داخليًا سوى عدد قليل من الفهارس حتى مع الأجزاء الكبيرة.
نوصي بتغيير محببية الفهرس فقط للمستخدمين المتقدمين الذين يفهمون تبعات ما يفعلونه (انظر أدناه).
تُعد فهارس تشابه المتجهات عامة، بمعنى أنها يمكن أن تدعم طرق بحث تقريبي مختلفة.
ويُحدَّد النوع المستخدم فعليًا بواسطة المعلمة <type>.
حتى الآن، الطريقة الوحيدة المتاحة هي HNSW (ورقة أكاديمية)، وهي تقنية شائعة ومتقدمة للبحث المتجهي التقريبي تعتمد على رسوم بيانية هرمية للتقارب.
إذا استُخدم HNSW بوصفه النوع، فيمكن للمستخدمين اختياريًا تحديد معلمات إضافية خاصة بـ HNSW:
- يتحكم
<quantization>في تكميم المتجهات في رسم بياني القرب. القيم الممكنة هيf64وf32وf16وbf16وi8أوb1. القيمة الافتراضية هيbf16. لاحظ أن هذه المَعلمة لا تؤثر في تمثيل المتجهات في العمود الأساسي. - يتحكم
<hnsw_max_connections_per_layer>في عدد الجيران لكل عقدة في الرسم البياني، ويُعرف أيضًا باسم المَعلمة الفائقةMفي HNSW. القيمة الافتراضية هي32. وتعني القيمة0استخدام القيمة الافتراضية. - يتحكم
<hnsw_candidate_list_size_for_construction>في حجم قائمة المرشحين الديناميكية أثناء إنشاء رسم HNSW البياني، ويُعرف أيضًا باسم المَعلمة الفائقةef_constructionفي HNSW. القيمة الافتراضية هي128. وتعني القيمة0استخدام القيمة الافتراضية.
- لا يمكن إنشاء فهارس تشابه المتجهات إلا على أعمدة من النوع Array(Float32) أو Array(Float64) أو Array(BFloat16). ولا يُسمح بالمصفوفات ذات القيم العائمة القابلة لأن تكون NULL أو منخفضة الكاردينالية، مثل
Array(Nullable(Float32))وArray(LowCardinality(Float32)). - يجب إنشاء فهارس تشابه المتجهات على أعمدة مفردة.
- يمكن إنشاء فهارس تشابه المتجهات على تعبيرات محسوبة (مثل
INDEX index_name arraySort(vectors) TYPE vector_similarity([...]))، ولكن لا يمكن استخدام هذه الفهارس لاحقًا في البحث التقريبي عن الجيران. - تتطلب فهارس تشابه المتجهات أن تحتوي جميع المصفوفات في العمود الأساسي على
<dimension>عنصرًا — ويُتحقق من ذلك أثناء إنشاء الفهرس. ولاكتشاف أي انتهاك لهذا الشرط في أقرب وقت ممكن، يمكن للمستخدمين إضافة قيد على عمود المتجهات، مثلCONSTRAINT same_length CHECK length(vectors) = 256. - وبالمثل، يجب ألا تكون قيم المصفوفة في العمود الأساسي فارغة (
[]) أو ذات قيمة افتراضية (وهي أيضًا[]).
استخدام فهرس تشابه المتجهات
لاستخدام فهارس تشابه المتجهات، يجب أن تكون قيمة الإعداد compatibility هي
'' (القيمة الافتراضية)، أو '25.1' أو إصدارًا أحدث.SELECT [...] SETTINGS hnsw_candidate_list_size_for_search = <value>).
القيمة الافتراضية للإعداد وهي 256 تُحقق أداءً جيداً في غالبية حالات الاستخدام.
القيم الأعلى تعني دقةً أفضل على حساب أداء أبطأ.
إذا كان بإمكان الاستعلام استخدام فهرس تشابه المتجهات، يتحقق ClickHouse من أن قيمة LIMIT <N> المحددة في استعلامات SELECT تقع ضمن حدود معقولة.
وتحديدًا، يُعاد خطأ إذا كانت <N> أكبر من قيمة الإعداد max_limit_for_vector_search_queries التي قيمتها الافتراضية 100.
قد تؤدي قيم LIMIT الكبيرة جدًا إلى إبطاء عمليات البحث، وغالبًا ما تشير إلى خطأ في الاستخدام.
للتحقق مما إذا كان استعلام SELECT يستخدم فهرس تشابه المتجهات، يمكنك إضافة EXPLAIN indexes = 1 في بداية الاستعلام.
كمثال، الاستعلام
Skip واسم فهرس المتجه ونوعه (في المثال، idx وvector_similarity).
في هذه الحالة، تخطّى فهرس تشابه المتجهات اثنتين من أصل أربع حبيبات، أي ما يعادل 50% من البيانات.
وكلما زاد عدد الحبيبات القابلة للتخطي، كان استخدام الفهرس أكثر فاعلية.
التصفية اللاحقة والتصفية المسبقة
يمكن للمستخدمين اختياريًا تحديد جملة WHERE مع شروط تصفية إضافية لاستعلام SELECT.
سيُقيِّم ClickHouse شروط التصفية هذه باستخدام إحدى استراتيجيتَي post-filtering أو pre-filtering.
باختصار، تحدد كلتا الاستراتيجيتين الترتيبَ الذي تُقيَّم به عوامل التصفية:
- تعني التصفية اللاحقة أنه يجري أولًا تقييم فهرس تشابه المتجهات، ثم يقيّم ClickHouse عوامل التصفية الإضافية المحددة في عبارة
WHERE. - وتعني التصفية المسبقة أن ترتيب تقييم عوامل التصفية يكون بالعكس.
- تواجه التصفية اللاحقة مشكلة عامة، وهي أنها قد تُرجِع عددًا أقل من الصفوف المطلوبة في عبارة
LIMIT <N>. ويحدث ذلك عندما لا يستوفي صفّ نتيجة واحد أو أكثر، أعاده فهرس تشابه المتجهات، المرشِّحات الإضافية. - تُعدّ التصفية المسبقة عمومًا مشكلة غير محلولة. توفّر بعض قواعد بيانات المتجهات المتخصصة خوارزميات للتصفية المسبقة، لكن معظم قواعد البيانات العلائقية (بما في ذلك ClickHouse) تعود إلى البحث الدقيق عن أقرب الجيران، أي فحص brute-force من دون فهرس.
year وشُغِّل الاستعلام التالي:
- إذا كان شرط التصفية يستبعد صفًا واحدًا على الأقل داخل جزء، فسيعود ClickHouse إلى التصفية المسبقة للنطاقات “المتبقية” داخل الجزء،
- إذا كان شرط التصفية لا يستبعد أي صفوف داخل جزء، فسينفّذ ClickHouse التصفية اللاحقة لهذا الجزء.
auto التي تطبّق الاستدلالات المذكورة أعلاه) على prefilter.
ويكون ذلك مفيدًا لفرض التصفية المسبقة في الحالات التي تكون فيها شروط التصفية الإضافية شديدة الانتقائية.
على سبيل المثال، قد يستفيد الاستعلام التالي من التصفية المسبقة:
SETTINGS vector_search_filter_strategy = 'prefilter' إلى الاستعلام)، يعثر ClickHouse أولًا على جميع الكتب التي يقل سعرها عن دولارين، ثم يُجري بحثًا متجهيًا بالقوة الغاشمة على الكتب التي عُثر عليها.
وكحل بديل للمشكلة المذكورة أعلاه، يمكن ضبط vector_search_index_fetch_multiplier (القيمة الافتراضية: 1.0، والحد الأقصى: 1000.0) على قيمة > 1.0 (على سبيل المثال، 2.0).
ويُضرَب عدد أقرب الجيران التي يجري جلبها من فهرس المتجهات في قيمة هذا الإعداد، ثم يُطبَّق عامل التصفية الإضافي على تلك الصفوف لإرجاع عدد من الصفوف يساوي قيمة LIMIT.
على سبيل المثال، يمكننا تنفيذ الاستعلام مرة أخرى، ولكن بمعامل 3.0:
vector_search_index_fetch_multiplier قد يخفف من هذه المشكلة، ولكن في الحالات القصوى (عندما يكون شرط WHERE انتقائيًا جدًا)، يظل من الممكن إعادة عدد أقل من N من الصفوف المطلوبة.
إعادة التقييم
تُجري skip indexes في ClickHouse عادةً التصفية على مستوى الـ حبيبة، أي إن عملية lookup في skip index (داخليًا) تُرجع قائمة بالـ حبيبات التي يُحتمل أن تتطابق، مما يقلل حجم read data في الفحص اللاحق.
يعمل هذا جيدًا مع skip indexes عمومًا، لكن في حالة فهارس تشابه المتجهات، فإنه يسبب “عدم تطابق في granularity”.
وبمزيد من التفصيل، يحدد فهرس تشابه المتجهات أرقام الصفوف الخاصة بـ N من أكثر المتجهات تشابهًا بالنسبة إلى المتجه المرجعي معيّن، لكنه يحتاج بعد ذلك إلى إسقاط أرقام الصفوف هذه على أرقام حبيبة.
بعد ذلك، سيحمّل ClickHouse هذه الـ حبيبات من disk، ويعيد حساب المسافة لجميع المتجهات داخل هذه الـ حبيبات.
وتُسمى هذه الخطوة rescoring، ومع أنها قد تحسّن الدقة نظريًا — تذكّر أن فهرس تشابه المتجهات لا يُرجع سوى نتيجة تقريبية — فمن الواضح أنها ليست مثالية من حيث الأداء.
لذلك يوفّر ClickHouse تحسينًا يعطّل rescoring ويُرجع أكثر المتجهات تشابهًا ومسافاتها مباشرةً من index.
يكون هذا التحسين enabled افتراضيًا، راجع الإعداد vector_search_with_rescoring.
وعلى مستوى عام، تعمل هذه الآلية بأن ClickHouse يوفّر أكثر المتجهات تشابهًا ومسافاتها على هيئة عمود افتراضي _distances.
ولرؤية ذلك، شغّل query بحث متجهي باستخدام EXPLAIN header = 1:
قد يرجع الاستعلام الذي يُشغَّل دون إعادة التقييم (
vector_search_with_rescoring = 0) ومع تفعيل النسخ المتماثلة المتوازية، تلقائيًا إلى إعادة التقييم.ضبط الأداء
CODEC(NONE) لعمود المتجهات كما يلي:
system.text_log) إلى أن فهرس تشابه المتجهات قيد التحميل.
وإذا ظهرت هذه الرسائل بشكل متكرر مع استعلامات بحث متجهي مختلفة، فهذا يشير إلى أن حجم ذاكرة التخزين المؤقت منخفض جدًا.
تخزّن ذاكرة التخزين المؤقت لفهرس تشابه المتجهات حبيبات فهرس المتجهات.
إذا كان حجم حبيبات فهرس المتجهات الفردية أكبر من حجم ذاكرة التخزين المؤقت، فلن تُخزَّن مؤقتًا.
لذلك، يُرجى التأكد من حساب حجم فهرس المتجهات (استنادًا إلى الصيغة الواردة في “تقدير التخزين واستهلاك الذاكرة” أو system.data_skipping_indices) وتحديد حجم ذاكرة التخزين المؤقت بما يتناسب مع ذلك.
يقلل التكميم من دقة البحث المتجهي مقارنةً بالبحث في قيم الفاصلة العائمة الأصلية كاملة الدقة (
f32).
ومع ذلك، في معظم مجموعات البيانات، يؤدي تكميم brain float بنصف الدقة (bf16) إلى فقدان طفيف جدًا في الدقة، لذا تستخدم فهارس تشابه المتجهات أسلوب التكميم هذا افتراضيًا.
أما تكميم ربع الدقة (i8) والتكميم الثنائي (b1) فيؤديان إلى فقدان ملحوظ في دقة البحث المتجهي.
ولا نوصي باستخدام هذين النوعين من التكميم إلا إذا كان حجم فهرس تشابه المتجهات أكبر بكثير من حجم DRAM المتاح.
وفي هذه الحالة، نقترح أيضًا تمكين إعادة التقييم (vector_search_index_fetch_multiplier، vector_search_with_rescoring) لتحسين الدقة.
ولا يُنصح بالتكميم الثنائي إلا في حالتين فقط: 1) عند استخدام تضمينات مُطبَّعة (أي إن طول المتجه = 1، وعادةً ما تكون نماذج OpenAI مُطبَّعة)، و2) عند استخدام مسافة جيب التمام بوصفها دالة المسافة.
ويستخدم التكميم الثنائي داخليًا مسافة Hamming لبناء الرسم البياني للتقارب والبحث فيه.
وتستخدم خطوة إعادة التقييم المتجهات الأصلية كاملة الدقة المخزنة في الجدول لتحديد أقرب الجيران عبر مسافة جيب التمام.
ضبط نقل البيانات
يُقدَّم المتجه المرجعي في استعلام البحث المتجهي من قِبل المستخدم، ويُسترجع عادةً عبر إجراء استدعاء إلى نموذج لغوي كبير (LLM).
وقد يبدو نموذج شيفرة بايثون المعتاد الذي يُجري بحثًا متجهيًا في ClickHouse كما يلي
search_v في المقتطف أعلاه) عدد كبير جدًا من الأبعاد.
فعلى سبيل المثال، توفّر OpenAI نماذج تُنشئ متجهات تضمين تضم 1536 أو حتى 3072 بُعدًا.
في الشيفرة أعلاه، يستبدل برنامج تشغيل ClickHouse لبايثون متجه التضمين بسلسلة نصية مقروءة للبشر، ثم يرسل استعلام SELECT بالكامل كسلسلة نصية.
وبافتراض أن متجه التضمين يتكوّن من 1536 قيمة فاصلة عائمة أحادية الدقة، فإن طول السلسلة المُرسلة يصل إلى 20 كيلوبايت.
ويؤدي ذلك إلى ارتفاع استخدام CPU بسبب تقسيم النص إلى رموز، والتحليل، وإجراء آلاف التحويلات من سلسلة نصية إلى قيمة فاصلة عائمة.
كما يتطلب ذلك مساحة كبيرة في ملف سجل ClickHouse server، مما يسبب أيضًا تضخمًا في system.query_log.
لاحظ أن معظم نماذج LLM تُرجع متجه تضمين على هيئة قائمة أو مصفوفة NumPy من قيم فاصلة عائمة أصلية.
لذلك نوصي تطبيقات بايثون بربط معلمة متجه المرجع بالصيغة الثنائية باستخدام الأسلوب التالي:
system.query_log.
الإدارة والمراقبة
الاختلافات عن فهارس التخطي العادية
GRANULARITY = [N] حبيبات ([N] = 1 افتراضيًا في فهارس التخطي العادية).
على سبيل المثال، إذا كانت دقة حبيبات الفهرس الأساسي للجدول 8192 (الإعداد index_granularity = 8192) وكانت GRANULARITY = 2، فستحتوي كل كتلة مفهرسة على 16384 صفًا.
لكن بُنى البيانات والخوارزميات الخاصة ببحث أقرب الجيران التقريبي هي بطبيعتها موجّهة نحو الصفوف.
فهي تخزّن تمثيلًا مضغوطًا لمجموعة من الصفوف، كما تُرجع صفوفًا لاستعلامات البحث المتجهي.
ويؤدي ذلك إلى بعض الاختلافات غير البديهية نوعًا ما في سلوك فهارس تشابه المتجهات مقارنةً بفهارس التخطي العادية.
عندما يعرّف المستخدم فهرس تشابه متجهات على عمود، ينشئ ClickHouse داخليًا “فهرسًا فرعيًا” لتشابه المتجهات لكل كتلة فهرس.
ويكون الفهرس الفرعي “محليًا” بمعنى أنه لا يعرف إلا صفوف كتلة الفهرس التي ينتمي إليها.
في المثال السابق، وبافتراض أن العمود يحتوي على 65536 صفًا، نحصل على أربع كتل فهرس (تمتد عبر ثماني حبيبات) وفهرس تشابه متجهات فرعي لكل كتلة فهرس.
ويستطيع الفهرس الفرعي نظريًا أن يُرجع مباشرةً الصفوف التي تحتوي على أقرب N نقاط ضمن كتلة الفهرس الخاصة به.
ومع ذلك، نظرًا لأن ClickHouse يحمّل البيانات من القرص إلى الذاكرة على مستوى الحبيبات، فإن الفهارس الفرعية تُسقط الصفوف المطابقة إلى مستوى الحبيبات.
وهذا يختلف عن فهارس التخطي العادية التي تتخطى البيانات على مستوى كتل الفهرس.
تحدّد المعلمة GRANULARITY عدد فهارس تشابه المتجهات الفرعية التي يتم إنشاؤها.
فكلما كانت قيم GRANULARITY أكبر، قلّ عدد فهارس تشابه المتجهات الفرعية ولكن ازداد حجمها، إلى أن نصل إلى حالة لا يكون فيها للعمود (أو لجزء بيانات العمود) سوى فهرس فرعي واحد فقط.
في هذه الحالة، تكون لدى الفهرس الفرعي رؤية “شاملة” لجميع صفوف العمود، ويمكنه أن يُرجع مباشرةً جميع حبيبات العمود (الجزء) التي تحتوي على صفوف ذات صلة (ويكون عدد هذه الحبيبات بحد أقصى LIMIT [N]).
وفي خطوة ثانية، سيحمّل ClickHouse هذه الحبيبات ويحدّد أفضل الصفوف فعليًا من خلال إجراء حساب مسافة brute-force على جميع صفوف تلك الحبيبات.
أما عند استخدام قيمة صغيرة لـ GRANULARITY، فإن كل فهرس فرعي يُرجع ما يصل إلى LIMIT N حبيبات.
ونتيجةً لذلك، يلزم تحميل عدد أكبر من الحبيبات وتصفيتها لاحقًا.
لاحظ أن دقة البحث متساوية في كلتا الحالتين، والاختلاف الوحيد هو في أداء المعالجة.
ويُوصى عمومًا باستخدام قيمة GRANULARITY كبيرة لفهارس تشابه المتجهات، واللجوء إلى قيم GRANULARITY أصغر فقط عند ظهور مشكلات مثل الاستهلاك المفرط للذاكرة من قِبل بُنى تشابه المتجهات.
إذا لم يتم تحديد GRANULARITY لفهارس تشابه المتجهات، فإن القيمة الافتراضية هي 100 مليون.
مثال
Query
Response
البت المُكمَّم (QBit)
Array(BFloat16) بدلًا من Array(Float32)، فسينخفض حجم البيانات إلى النصف، ومن المتوقع أن تنخفض أزمنة تنفيذ الاستعلامات بنسبة مماثلة.
وتُعرف هذه الطريقة باسم التكميم. وعلى الرغم من أنها تُسرّع العمليات الحسابية، فقد تقلل من دقة النتائج رغم إجراء فحص شامل لجميع المتجهات.
في التكميم التقليدي، نفقد الدقة أثناء البحث وعند تخزين البيانات أيضًا. ففي المثال أعلاه، سنخزّن BFloat16 بدلًا من Float32، ما يعني أنه لن يعود بالإمكان إجراء بحث أكثر دقة لاحقًا، حتى لو أردنا ذلك. وأحد البدائل هو تخزين نسختين من البيانات: نسخة مكمّمة ونسخة كاملة الدقة. ورغم أن هذا الأسلوب ينجح، فإنه يتطلب تخزينًا زائدًا. تخيّل سيناريو تكون فيه Float64 هي البيانات الأصلية ونريد تشغيل عمليات بحث بدقات مختلفة (16-بت، أو 32-بت، أو 64-بت كاملة). عندها سنحتاج إلى تخزين ثلاث نسخ منفصلة من البيانات.
يوفّر ClickHouse نوع البيانات Quantized Bit (QBit) لمعالجة هذه القيود من خلال:
- تخزين البيانات الأصلية كاملة الدقة.
- إتاحة تحديد دقة التكميم وقت الاستعلام.
QBit، استخدم البنية التالية:
element_type– نوع كل عنصر في المتجه. والأنواع المدعومة هيBFloat16وFloat32وFloat64dimension– عدد العناصر في كل متجه
إنشاء جدول QBit وإدراج البيانات فيه
البحث المتجهي باستخدام QBit
QBit هنا.
بحث بالدقة الكاملة (64 بت):
اعتبارات الأداء
QBit من تقليل عمليات الإدخال/الإخراج، إذ يلزم قراءة كمية أقل من البيانات من التخزين عند استخدام دقة أقل. بالإضافة إلى ذلك، عندما يحتوي QBit على بيانات Float32، وإذا كانت معلَمة precision تساوي 16 أو أقل، فستكون هناك فوائد إضافية ناتجة عن تقليل العمليات الحسابية. وتتحكم معلَمة precision مباشرةً في المفاضلة بين الدقة والسرعة:
- دقة أعلى (أقرب إلى عرض البيانات الأصلي): نتائج أكثر دقة، واستعلامات أبطأ
- دقة أقل: استعلامات أسرع مع نتائج تقريبية، وانخفاض في استخدام الذاكرة