مرحبًا أيها الأصدقاء! هناك أشخاص بمستويات مختلفة من الخبرة يساهمون في منتدياتنا - وهذا أمر رائع! لكن في الوقت الحالي، أبحث عن جبابرة روبي الحقيقيين!
Elasticsearch هو محرك بحث يعتمد على مكتبة موثوقة وناضجة - Apache Lucene. نشاط ضخم في git المشروع المستودع والتطبيق في مشاريع مثل GitHub و SoundCloud و Stack Overflow و LinkedIn يشهد على شعبيته الكبيرة. يقول الجزء "المرن" كل شيء عن طبيعة النظام، الذي يتمتع بقدرات هائلة: من البحث البسيط عن الملفات على نطاق صغير، مروراً باكتشاف المعرفة، وصولاً إلى تحليل البيانات الضخمة في الوقت الحقيقي، وما يجعل Elastic أقوى من المنافسين هو مجموعة التكوينات والسلوكيات الافتراضية، التي تسمح بإنشاء مجموعة والبدء في إضافة المستندات إلى الفهرس في بضع دقائق. سيقوم Elastic بتهيئة مجموعة عنقودية لك، وسيحدد فهرسًا ويحدد أنواع الحقول لأول مستند تم الحصول عليه، وعندما تضيف خادمًا آخر، سيتعامل تلقائيًا مع تقسيم بيانات الفهرس بين الخوادم، ولسوء الحظ، فإن الأتمتة المذكورة أعلاه تجعل من غير الواضح لنا ما الذي تنطوي عليه الإعدادات الافتراضية، وغالبًا ما يتبين أنها مضللة. تبدأ هذه المقالة سلسلة من المقالات التي سأتعامل فيها مع أكثر المشاكل شيوعًا، والتي قد تواجهك أثناء عملية إنشاء التطبيق القائم على المرونة.
لا يمكن تغيير عدد القطع
لنقم بفهرسة المستند الأول باستخدام فهرس واجهة برمجة التطبيقات:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"الاسم_الأول" : "جين",
"الاسم_الأخير" : "سميث",
"steet_number": 12
}'
في هذه اللحظة، يقوم Elastic بإنشاء فهرس لنا، بعنوان myindex. ما لا يظهر هنا هو عدد الأجزاء المخصصة للفهرس. يمكن فهم الأجزاء على أنها عمليات فردية مسؤولة عن فهرسة وتخزين والبحث في جزء من المستندات في فهرس كامل. أثناء عملية فهرسة المستند، تقرر المرونة أي جزء يجب أن يوجد فيه المستند. يعتمد ذلك على الصيغة التالية:
شارد = تجزئة(document_id) % عدد_الأجزاء_الأساسية
من الواضح الآن أنه لا يمكن تغيير عدد الأجزاء الأساسية لفهرس يحتوي على مستندات. لذا، قبل فهرسة المستند الأول، قم دائمًا بإنشاء فهرس يدويًا، مع إعطاء عدد الأجزاء التي تعتقد أنها كافية لحجم البيانات المفهرسة:
< $ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"الإعدادات" : {
"Number_of_shards" : 10
}
}'
القيمة الافتراضية ل عدد_الأجزاء_من_الأجزاء
هو 5. هذا يعني أنه يمكن توسيع نطاق الفهرس إلى 5 خوادم، والتي تجمع البيانات أثناء الفهرسة. بالنسبة لبيئة الإنتاج، يجب تعيين قيمة الأجزاء بناءً على التكرار المتوقع للفهرسة وحجم المستندات. بالنسبة لبيئات التطوير والاختبار، أوصي بتعيين القيمة إلى 1 - لماذا؟ سيتم شرح ذلك في الفقرة التالية من هذه المقالة.
فرز نتائج البحث النصي مع عدد قليل نسبياً من المستندات
عندما نبحث عن مستند بعبارة ما:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"استعلام": {
"تطابق": {
"العنوان": "الثعلب البني السريع"
}
}
}'
يعالج Elastic البحث عن النص المرن في خطوات قليلة، ببساطة:
- يتم تحويل العبارة من الطلب إلى نفس الشكل المطابق الذي تمت فهرسة المستند به، وفي حالتنا هذه ستكون مجموعة من المصطلحات:
["سريع"، "بني"، "ثعلب"]
("ال" محذوفة لأنها غير مهمة),
- يتم تصفح الفهرس للبحث في المستندات التي تحتوي على كلمة واحدة على الأقل من الكلمات التي تم البحث عنها,
- يتم تقييم كل مستند مطابق من حيث صلته بعبارة البحث,
- يتم فرز النتائج حسب الصلة المحسوبة ويتم إرجاع الصفحة الأولى من النتائج إلى المستخدم.
في الخطوة الثالثة، يتم أخذ القيم التالية (من بين قيم أخرى) في الاعتبار:
- عدد الكلمات من عبارة البحث الموجودة في المستند
- عدد مرات ورود كلمة معينة في مستند ما (TF - تكرار المصطلح)
- ما إذا كانت الكلمات المطابقة تتكرر في مستندات أخرى (IDF - تكرار المستند العكسي) - كلما كانت الكلمة أكثر شيوعًا في المستندات الأخرى، كلما كانت الكلمة أقل أهمية
- كم يبلغ طول المستند
عمل IDF مهم بالنسبة لنا. لا يقوم Elastic لأسباب تتعلق بالأداء بحساب هذه القيمة فيما يتعلق بكل مستند في الفهرس - بدلاً من ذلك، يقوم كل جزء (عامل الفهرس) بحساب IDF المحلي الخاص به ويستخدمه للفرز. لذلك، أثناء البحث في الفهرس مع عدد قليل من المستندات، قد نحصل على نتائج مختلفة إلى حد كبير اعتمادًا على عدد الأجزاء في الفهرس وتوزيع المستندات.
لنتخيل أن لدينا جزأين في الفهرس؛ في الجزء الأول يوجد 8 مستندات مفهرسة بكلمة "ثعلب"، وفي الجزء الثاني مستندان فقط بنفس الكلمة. نتيجة لذلك، ستختلف كلمة "ثعلب" اختلافًا كبيرًا في كلا الجزأين، وقد يؤدي ذلك إلى نتائج غير صحيحة. لذلك، يجب إنشاء فهرس يتكون من جزء أساسي واحد فقط لأغراض التطوير:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"الإعدادات" : { "Number_of_shards" : 1 } }'
يؤدي عرض نتائج صفحات البحث "البعيدة" إلى قتل مجموعتك
كما كتبتُ من قبل في الفقرات السابقة، تتم مشاركة المستندات في الفهرس بين عمليات فهرس فردية تمامًا - أجزاء. كل عملية مستقلة تمامًا وتتعامل فقط مع المستندات التي تم تعيينها لها.
عندما نبحث في فهرس يحتوي على ملايين المستندات وننتظر الحصول على أفضل 10 نتائج، يجب على كل جزء أن يُرجع أفضل 10 نتائج مطابقة له إلى مجموعة العقدةالتي بدأت البحث. ثم يتم ضم الردود من كل جزء معًا واختيار أفضل 10 نتائج بحث (ضمن الفهرس بأكمله). يسمح هذا النهج بتوزيع عملية البحث بكفاءة بين العديد من الخوادم.
دعنا نتخيل أن تطبيقنا يسمح بعرض 50 نتيجة لكل صفحة، دون قيود تتعلق بعدد الصفحات التي يمكن للمستخدم عرضها. تذكر أن فهرسنا يتكون من 10 أجزاء أساسية (1 لكل خادم).
لنرى كيف سيبدو الحصول على نتائج البحث للصفحة الأولى والصفحة المائة:
الصفحة رقم 1 من نتائج البحث:
- تقوم العقدة التي تستقبل الاستعلام (وحدة التحكم) بتمريره إلى 10 أجزاء.
- تعرض كل جزء أفضل 50 مستنداً مطابقاً مرتبة حسب الصلة.
- بعد استلام الردود من كل جزء، تقوم وحدة التحكم بدمج النتائج (500 مستند).
- نتائجنا هي أفضل 50 مستنداً من الخطوة السابقة.
الصفحة رقم 100 من نتائج البحث:
- تقوم العقدة التي تستقبل الاستعلام (وحدة التحكم) بتمريره إلى 10 أجزاء.
- كل جزء يعرض أفضل 5000 مستند مطابق له مرتبة حسب الصلة.
- بعد تلقي الردود من كل جزء، تقوم وحدة التحكم بدمج النتائج (50000 مستند).
- نتائجنا هي المستندات من الخطوة السابقة الموضوعة في الموضع 4901 - 5000.
إذا افترضنا أن حجم المستند الواحد يبلغ 1 كيلوبايت، فهذا يعني في الحالة الثانية أنه يجب إرسال حوالي 50 ميغابايت من البيانات ومعالجتها حول المجموعة، من أجل عرض 100 نتيجة لمستخدم واحد.
ليس من الصعب ملاحظة أن حركة مرور الشبكة وتحميل الفهرس يزداد بشكل كبير مع كل صفحة نتائج متتالية. لهذا السبب لا يُنصح بإتاحة صفحات البحث "البعيدة" للمستخدم. إذا تم تكوين فهرسنا بشكل جيد، من المفترض أن يجد المستخدم النتيجة التي يهتم بها في صفحات البحث الأولى، وسنحمي أنفسنا من التحميل غير الضروري على مجموعتنا. لإثبات هذه القاعدة، تحقق من عدد صفحات نتائج البحث التي تسمح محركات البحث الأكثر شعبية على الويب بعرضها.
المثير للاهتمام أيضًا هو ملاحظة زمن استجابة المتصفح لصفحات نتائج البحث المتتالية. على سبيل المثال، يمكنك العثور أدناه على أزمنة الاستجابة لصفحات نتائج البحث الفردية في بحث Google (كان مصطلح البحث "محرك البحث"):
| صفحة نتائج البحث (10 مستندات في كل صفحة) | وقت الاستجابة |
|——————————————–|—————|
| 1 | 250 مللي ثانية |
| 10 | 290 مللي ثانية |
| 20 | 350 مللي ثانية |
| 30 | 380 مللي ثانية |
| 38 (آخر واحدة متوفرة) |
في الجزء التالي، سأنظر عن كثب في المشاكل المتعلقة بفهرسة المستندات.