انتقل إلى المحتوى الرئيسي

OpenSearch وOpenSearch Dashboards: قارِن، اختَر، هاجِر

يُعيد Karim قراءة شروط استعمال Elastic ويسأل Inès في اجتماع المنتج: «هل يمكننا التّحوّل إلى OpenSearch لتفادي مفاجآت الرّخصة حين يمرّ Veille إلى SaaS؟». يأخذ الفريق نصف يوم لإعادة تنفيذ استعلامات الدّورة على fork من AWS، ويقارن المحرّكَين بأمانة، ويقرّر. ترسم هذه الوحدة الحدود بين ما هو متطابق، وما يتباعد، وما يهمّ فعلًا لمنتج يبيع البحث.

من أين جاء الـfork

نقطة التّحوّل هي يناير 2021. حتّى ذلك الوقت، كان Elasticsearch وKibana يُنشران تحت رخصة Apache 2.0، وهي رخصة متساهلة تُتيح لأيّ أحد، بما في ذلك مضيف سحابيّ، إعادة بيع البرمجيّة. تُعلن Elastic الانتقال إلى SSPL / ELv2 ثنائيًّا (Server Side Public License وElastic License 2.0) ابتداءً من النّسخة 7.11. الرّسالة صريحة: لم تعد AWS قادرة على تقديم خدمتها المُدارة باسم «Elasticsearch» دون التّفاوض على اتّفاق تجاريّ. SSPL، المشتقّة من AGPL، تشترط مشاركة الشّيفرة كاملةً بالرّخصة نفسها المستعملة لتقديم الخدمة كـSaaS؛ وELv2 تمنع التّقديم المُدار كخدمة.

فبراير 2021، تردّ AWS بـfork. نقطة الانطلاق هي آخر نسخة Apache 2.0: Elasticsearch 7.10.2 وKibana 7.10.2. يُعاد تسمية الـfork إلى OpenSearch وOpenSearch Dashboards، ويُطَوَّر علنًا، محكومًا في البداية من AWS. النّسخة 1.0 تصدر في صيف 2021.

منذ ذلك الحين، تطوّران بارزان. في 2024، تُضيف Elastic AGPLv3 خيارًا ثالثًا لـElasticsearch: يمكن للمستخدمين اختيار SSPL أو ELv2 أو AGPLv3. عودة جزئيّة إلى المنظومة مفتوحة المصدر الكلاسيكيّة — لكن مسألة SaaS تبقى. في السّنة نفسها، يخرج OpenSearch من احتضان AWS الحصريّ وينضمّ إلى Linux Foundation ضمن مؤسّسة جديدة، OpenSearch Software Foundation، تحضرها أيضًا Uber وSAP وAiven وBytedance وآخرون. تصبح الحوكمة بحقّ متعدّدة الأطراف.

محرّكان، قاعدة مشتركة

كلّ مفردات الدّورة (فهرس، shard، mapping، text مقابل keyword، التّجميعات، Query DSL) تبقى صحيحة في الجهتَين. الفوارق تعلو ذلك: الإدارة والأمن والإضافات التّجاريّة ولغات الاستعلام الحديثة.

جدول مقارنة

يتّبع الجدول أدناه النّسخة 9.5.3 من Elasticsearch الّتي تُسلَّم في الحقيبة والنّسخة 3.8.0 من OpenSearch، وقت الكتابة.

المعيارElasticsearch 9.5OpenSearch 3.8
الرّخصةSSPL أو ELv2 أو AGPLv3 (خيار)Apache 2.0
الحوكمةElastic N.V.OpenSearch Software Foundation (Linux Foundation)
الأمن (auth وRBAC وTLS)مُضمَّن في basic المجّانيّةإضافة security مُضمَّنة، مجّانيّة
Console ويبKibanaOpenSearch Dashboards
SQL / PPLSQL basic؛ ES|QL منذ 8.11إضافة sql: SQL وPPL، مجّانيّتان
البحث الشّعاعيّdense_vector و kNN أصليّ وELSER وsemantic_textإضافة k-NN، Neural Search
AlertingBasic ومستويات مدفوعةإضافة Alerting مُضمَّنة، مجّانيّة
دورة حياة الفهارسILMISM (Index State Management)، إضافة
العملاء الرّسميّونelasticsearch v8 / v9opensearch-py، وforks لـJS وJava وGo
توافق العملاء بين المحرّكَينعميل v8+ غير متوافق مع OpenSearchعميل OpenSearch لا يُوصى به لـElastic
المُضيفون المُدارونElastic Cloud وBonsai وAivenAWS OpenSearch Service وAiven وBonsai

سطران يستحقّان التّعمّق. الأمن المُضمَّن: في Elasticsearch، TLS والمستخدمون والأدوار في رخصة basic المجّانيّة منذ 2020، وهو ما يجهله الكثيرون بعد. تستعمله حقيبة veille-es. من جهة OpenSearch، إضافة security مُدمَجة أصليًّا (لكنّها مُعطَّلة في الملفّ المقارن للحقيبة تبسيطًا لقراءة URL). لغات الأنبوب: ES|QL في جهة Elastic، وPPL في جهة OpenSearch، جوابان متمايزان لحاجة واحدة — استبدال أنابيب JSON الطّويلة في Query DSL ببنية خطّيّة قابلة للقراءة.

Elasticsearch (ES|QL)
FROM news | WHERE category == "POLITICS" | STATS c = COUNT() BY category | SORT c DESC

OpenSearch (PPL)
source=news | where category="POLITICS" | stats count() by category | sort -count()

تشغيل OpenSearch في الحقيبة

تُسلِّم الحقيبة ملفًّا مخصَّصًا يتعايش مع Elasticsearch بتحويل المنافذ (9201 و5602). الأمن مُعطَّل طوعًا في هذا الملفّ لتبقى وحدة المقارنة قابلة للقراءة؛ في الإنتاج، نُفعِّل إضافة security وTLS.

./lab.sh opensearch-up

المتوقَّع في النّهاية:

[OK] OpenSearch prêt sur http://localhost:9201 — Dashboards sur http://localhost:5602

فحص سريع بلا مصادقة:

GET _cluster/health

الاستجابة المتوقَّعة:

{
"cluster_name": "veille-os",
"status": "green",
"number_of_nodes": 1,
"active_primary_shards": "(votre chiffre peut différer)"
}

إعادة تنفيذ ثلاثة استعلامات من الدّورة

تعيش مدوَّنة News في Elasticsearch، لا في OpenSearch — وهذه بالضّبط النّقطة. لمقارنة Query DSL دون إعادة استيراد 200 853 وثيقة، أنشئ فهرسًا صغيرًا بثلاث مقالات في OpenSearch Dashboards → Dev Tools (http://localhost:5602/app/dev_tools#/console).

PUT news
{
"settings": { "number_of_shards": 1, "number_of_replicas": 0 },
"mappings": {
"properties": {
"headline": { "type": "text" },
"category": { "type": "keyword" },
"date": { "type": "date" }
}
}
}
POST news/_bulk
{ "index": {} }
{ "headline": "Change Is Here. Climate Change.", "category": "POLITICS", "date": "2017-06-02" }
{ "index": {} }
{ "headline": "How To Cook A Perfect Steak At Home", "category": "TASTE", "date": "2015-11-14" }
{ "index": {} }
{ "headline": "Reuters: Markets Watch Fed Signals", "category": "BUSINESS", "date": "2018-01-09" }

الاستعلام 1 — بحث نصّيّ:

GET news/_search
{
"query": { "match": { "headline": "climate change" } }
}

النّتيجة المتوقَّعة: hit واحد بـ_score غير صفريّ على مقال POLITICS. على المدوَّنة الحقيقيّة في Elasticsearch (الوحدة 5)، يُعيد الاستعلام نفسه 2 834 نتيجة.

الاستعلام 2 — تجميع terms على category:

GET news/_search
{
"size": 0,
"aggs": {
"par_categorie": { "terms": { "field": "category", "size": 5 } }
}
}

المتوقَّع هنا: 3 buckets بمقال واحد لكلّ منها. على المدوَّنة الحقيقيّة، تُعيد الكتلة نفسها POLITICS 32 739 وWELLNESS 17 827 وENTERTAINMENT 16 058 وTRAVEL 9 887 وSTYLE & BEAUTY 9 649.

الاستعلام 3 — الملاءمة مع bool:

GET news/_search
{
"query": {
"bool": {
"must": [{ "match": { "headline": "steak" } }],
"filter": [{ "term": { "category": "TASTE" } }]
}
}
}

انسخ هذه الاستعلامات الثّلاثة كما هي في Kibana Dev Tools (http://localhost:5601) على فهرس news الخاصّ بالدّورة: البنية النّحويّة متطابقة، وتختلف الأرقام فقط. هذا هو أوضح برهان: Query DSL معيار فعليّ مشترك.

ما يختلف عند القراءة

_xpack يختفي في جهة OpenSearch، ويُستبدل بـ_plugins/_security و_plugins/_sql و_plugins/_knn و_plugins/_ism. تُحفظ نقاط النّهاية القياسيّة _cat/* بلا تغيير.

OpenSearch Dashboards مقابل Kibana

الأرغونوميا قريبة لا متطابقة. نجد فيها Discover وVisualize وDashboards وDev Tools وStack Management. تصويرات Lens الّتي في Kibana ليست موجودة بعد؛ يقترح OpenSearch محرّر Visualize القديم إضافةً إلى VisBuilder. ملفّات الكائنات المحفوظة (ndjson) المُصدَّرة من Kibana غير مضمونة التّوافق مع OpenSearch Dashboards والعكس. في الواقع، نُعيد بناء لوحات المعلومات في الأداة المستهدفة.

إضافات الطّرف الأوّل في OpenSearch

كلّها تحت Apache 2.0، وكلّها مُضمَّنة في الصّورة:

  • security: مستخدمون وأدوار وABAC وTLS ومراجعة
  • sql: SQL وPPL على الفهارس
  • k-NN: بحث شعاعيّ مضبوط ومقارَب
  • neural-search: تكامل مع embeddings
  • alerting: مراقبون ووجهات (Slack، بريد، webhook)
  • anomaly-detection: كشف بلا إشراف
  • index-management (ISM): سياسات دورة الحياة
  • notifications وml-commons وobservability وflow-framework

معايير القرار لـVeille

خمسة أسئلة عمليّة يحسمها الفريق.

  1. هل الرّخصة تحجب استعمالًا مُخطَّطًا له؟ يستغلّ Veille سحابيًّا داخليًّا، ولا يُعيد توزيع المحرّك، ولا يبيع خدمة مُدارة «OpenSearch as a Service». basic المجّانيّة لـElastic تُغطّي الحاجة: SSPL لا تعوق شيئًا.
  2. هل ميزانيّة رخصة تجاريّة ممكنة؟ إن أراد Veille ELSER أو مصادقة OIDC لزبائنه أو تعلّم آلة مُدارًا، فسيلزم اشتراك Elastic Cloud أو Platinum. يُسلِّم OpenSearch المكافئ المجّانيّ في عدّة محاور.
  3. أيّ مُضيف؟ Elastic Cloud من جهة، AWS OpenSearch Service من جهة أخرى؛ والاثنان موجودان أيضًا عند Aiven وBonsai.
  4. أيّ منظومة ذكاء اصطناعيّ للبحث؟ ELSER وsemantic_text ميزة صافية لـElastic في 2026؛ k-NN الأصليّ وNeural Search في جهة OpenSearch يبقيان صلبَين لكنّهما يتطلّبان مزيدًا من التّركيب.
  5. أيّ عملاء؟ إن كتب Karim واجهته البرمجيّة في Python مقابل elasticsearch v9، فالهجرة تعني الانتقال إلى opensearch-py (استيرادات، بعض الخيارات المُعاد تسميتها، بعض الاستجابات المختلفة في البيانات الوصفيّة).
الحكم الدّاخليّ لـVeille

البقاء على Elasticsearch 9 اليوم. مراقبة OpenSearch كلّ ستّة أشهر: إن تجاوز فارق كلفة السّحابة عتبةً، أو إن اشترط زبون رخصة Apache 2.0 صارمة، فالباب يبقى مفتوحًا.

هجرة فهرس

طريقتان، الأولى هي الصّائبة تقريبًا دائمًا.

الطّريقة 1 — إعادة الاستيراد من المصدر

هذه هي الطّريقة النّظيفة. يمتلك Veille أصلًا News_Category_Dataset_v2.json في data/؛ ومُستورِد الحقيبة سكربت Python من 200 سطر. توجيهه إلى http://localhost:9201 بدل http://localhost:9200 ، وإزالة المصادقة (أو استبدالها بمصادقة إضافة security) ، وإعادة التّشغيل. تُعاد كتابة الـmapping بالمثل في OpenSearch: لا شيء خاصّ بـElastic في مخطّطنا. لا خطر انحراف، اختبارات قابلة للتّكرار، والرّجوع تافه.

الطّريقة 2 — _reindex بـsource.remote

مفيدة حين يكون المصدر بعيدًا أو غير متاح. مدعومة رسميًّا بين Elasticsearch 7.10.2 وOpenSearch 1.x؛ فوق ذلك، كلّ تركيبة نسختَين يجب التّحقّق منها. يجب أوّلًا التّرخيص للمُضيف المصدر في opensearch.yml:

reindex.remote.whitelist: "elasticsearch:9200"

ثمّ، في OpenSearch Dev Tools:

POST _reindex
{
"source": {
"remote": {
"host": "http://elasticsearch:9200",
"username": "elastic",
"password": "veille2026"
},
"index": "news"
},
"dest": { "index": "news" }
}

يُطلق هذا _reindex عن بعد يستعلم الواجهة البرمجيّة لـElasticsearch ويدفع الوثائق بـ_bulk محلّيًّا. لمدوَّنة من 200 853 وثيقة، احسب دقائق عدّة.

انتبه إلى الـmapping

_reindex لا يُهاجر الـmapping تلقائيًّا. أنشئ الفهرس المستهدف بالـmappings الصّحيح قبل الاستدعاء، وإلّا يُخمِّن OpenSearch mapping ديناميكيًّا قد يختلف عن الأصليّ (مثلًا date مُخمَّن كـtext إن كان أوّل تاريخ يُقرأ ملتبسًا).

الإيقاف السّليم

./lab.sh opensearch-down

يُوقف هذا الأمر حاوِيَتَي veille-opensearch وveille-os-dashboards دون حذف الحجم os-data. ./lab.sh opensearch-up التّالي يستأنف الحالة. ./lab.sh reset يحذف كلّ شيء، بما في ذلك بيانات OpenSearch.

جرّب 1 — فحص صحّة الكتلة

نفِّذ GET _cluster/health على المحرّكَين، ودوِّن ثلاثة فوارق في استجابة JSON.

الحلّ
  • cluster_name: veille في جهة Elastic، وveille-os في جهة OpenSearch.
  • الحقلان active_shards_percent_as_number وunassigned_primary_shards مُنسَّقان بشكل مختلف حسب النّسخة.
  • يعرض OpenSearch discovered_master (توافق)، ويعرض Elasticsearch discovered_cluster_manager وdiscovered_master مرادفًا حتّى النّسخة 8، ثمّ يُعيد التّسمية كاملًا.

جرّب 2 — الاستعلام terms على category

اكتب الاستعلام نفسه terms على category (أفضل 5) الذي كان سيُعطي POLITICS 32 739 وWELLNESS 17 827 وENTERTAINMENT 16 058 وTRAVEL 9 887 وSTYLE & BEAUTY 9 649 على مدوَّنة Elasticsearch. تذكير: size: 0 للحصول على buckets فقط.

الحلّ
GET news/_search
{
"size": 0,
"aggs": {
"categories": {
"terms": { "field": "category", "size": 5 }
}
}
}

الاستعلام نفسه مكتوبًا في Kibana Dev Tools يُعيد بالضّبط الـbuckets الخمسة أعلاه؛ في OpenSearch Dashboards على وثائق العرض الثّلاث، يُعيد 3 buckets بمقال واحد.

جرّب 3 — مذكّرة داخليّة لـInès

اكتب مذكّرة داخليّة من خمسة أسطر: «هل نبقى على Elasticsearch؟». حاجج على الرّخصة والأمن والتّكلفة والمنظومة.

الحلّ

مذكّرة ممكنة: «نبقى على Elasticsearch حاليًّا. تُغطّي basic المجّانيّة حاجتنا الأمنيّة، ويُسرِّع ELSER وsemantic_text البحث الدّلاليّ للمنتج، وتبقى الهجرة إلى OpenSearch قابلة للعكس عبر إعادة استيراد من News_Category_Dataset_v2.json. نُعيد التّقييم خلال ستّة أشهر وفق (1) كلفة Elastic Cloud، (2) متطلّبات رخصة زبائننا الكبار، (3) حالة PPL وإضافات ML في جهة OpenSearch.»

النقاط الأساسيّة

  • الـfork يعود إلى يناير 2021: تُغيّر Elastic الرّخصة انطلاقًا من 7.11، وتفعل AWS fork من Elasticsearch 7.10.2 تحت Apache 2.0.
  • 2024 يُدخل AGPLv3 في جهة Elastic (خيار) وLinux Foundation وصيّةً على OpenSearch.
  • Query DSL والتّجميعات و_cat/*: شبه متطابقة. _xpack يصبح _plugins/_*.
  • PPL في جهة OpenSearch، وES|QL في جهة Elastic: لغتا أنبوب متوازيتان لحاجة واحدة.
  • تُنجَز هجرة فهرس دائمًا تقريبًا بإعادة استيراد من المصدر؛ ويبقى _reindex عن بعد خطّة بديلة.
  • لـVeille في 2026، Elasticsearch يبقى الاختيار الافتراضيّ؛ ويدخل OpenSearch حين تنقلب الرّخصة أو كلفة السّحابة أو متطلّب تعاقديّ.
  • لا تخلط بين العملاء: elasticsearch v9 لم يُصنع للتّحدّث مع OpenSearch، والعكس صحيح لـopensearch-py.

استكشاف الأخطاء

  • opensearch-up يفشل بسبب max_map_count أو OOM → قيد النّواة مطابق لـElasticsearch، الذّاكرة يجب أن ترتفع → ./lab.sh doctor يُعطي أمر sysctl والقيمة المستهدفة.
  • المنفذ 9201 مأخوذ → حاوية OpenSearch سابقة من ورشة قديمة → ./lab.sh opensearch-down ثمّ أعِد التّشغيل.
  • Dashboards يعرض «OpenSearch cluster is not ready» → اترك دقيقة إلى دقيقتَين لأوّل تشغيل، أو نفِّذ ./lab.sh logs opensearch لقراءة رسالة الخطأ الحقيقيّة.
  • _reindex عن بعد يُرفض (400 reindex.remote.whitelist) → المُضيف المصدر ليس مُدرَجًا في opensearch.yml → أضِف reindex.remote.whitelist: "elasticsearch:9200" وأعِد تشغيل OpenSearch.

للاستزادة

الوحدة التّالية: قواعد البيانات الرّسوميّة وNeo4j وأولى الخطوات في Cypher — تضع رسم فريق Veille المصغَّر قبل تحميل رسم News.