كيف تقرأ هذه الصفحة. ثماني خطوات ، استعلام واحد في كلّ مرّة. لكلّ خطوة : الاستعلام الذي تكتبه ، الاستجابة الدقيقة للمختبر ، وما يجب النظر إليه فيها. اكتب كلّ استعلام بنفسك (بلا نسخ ولصق) : بكتابة
PUTوGETو_docتدخل الكلمات في ذهنك. فقرات « لفهم أعمق » اختياريّة ؛ افتحها إذا تركتك خطوة في شكّ. إذا لم يكن المختبر مُشغَّلًا ، ارجع إلى التطبيق الموجّه : قسم بإيجاز يعطي الأوامر ، بما فيها الحزمة (https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr).
جعلك التطبيق الموجّه تُحمّل 504 دورة و609 رأي و12000 سطر سجلّ دفعة واحدة ، بنصّ برمجيّ. رأيت الأرقام ، لكنّك لم تكتب شيئًا بنفسك بعد. هنا ، تبدأ من الصفر : فهرس فارغ تُنشئه ، بطاقة أولى تضعها فيه ، تُعيد قراءتها ، تُكمّلها ، ثم ثانية ، بحث ، حذف. في النهاية ، تعرف ما هو الفهرس والمستند لأنّك صنعت واحدًا ، لا لأنّهم قالوا لك ذلك.
الفهرس هو خزانة. المستند هو بطاقة مرتَّبة في الخزانة : نصّ JSON صغير بحقول. لكلّ بطاقة رقم ، _id الخاصّ بها ، يسمح باستعادتها مباشرة دون البحث. لا حاجة لتعريف الأعمدة مسبقًا : البطاقة الأولى المُرتَّبة تُنشئ الربط (mapping، مخطّط الخزانة) بمفردها.
| Elasticsearch | قاعدة SQL كلاسيكيّة | في هذا التطبيق |
|---|---|---|
| فهرس | جدول | pratique-mini |
| مستند | صفّ | {"titre": "Mon premier document"} |
| حقل | عمود | titre, auteur, note |
_id | مفتاح أساسيّ | 1, 2 |
| ربط (mapping) | مخطّط الجدول (CREATE TABLE …) | يُنشَأ تلقائيًّا في الخطوة 3 |
_source | الصفّ كما كتبته | ما يُعيده لك GET _doc/1 |
افتح http://localhost:5601، القائمة ☰ → Management → Dev Tools. اللوحة اليسرى تستقبل الاستعلامات ، اليمنى تعرض الاستجابة. تُرسل بـ Ctrl + Enter (Cmd + Enter على macOS) أو الزرّ ▶ إلى يمين السطر.
كلّ استعلام له الصيغة نفسها : فعل ، مسار ، وأحيانًا متن JSON تحته.
| الفعل | ما يفعله | معادل SQL |
|---|---|---|
GET | القراءة ، بدون تغيير شيء | SELECT |
PUT | الإنشاء ، أو الاستبدال الكامل | CREATE TABLE, INSERT (أو استبدال الصفّ) |
POST | التصرّف : تحديث ، بحث بمتن | UPDATE |
DELETE | الحذف | DROP TABLE, DELETE |
المسار يقول على ماذا نتصرّف : pratique-mini (الخزانة) ، pratique-mini/_doc/1 (البطاقة رقم 1 من الخزانة) ، pratique-mini/_search (البحث في الخزانة). الكلمات التي تبدأ بـ _ هي أوامر خاصّة بـ Elasticsearch ، ليست أسماء تخصّك.
PUT pratique-miniما يطلبه الاستعلام : أنشئ فهرسًا اسمه pratique-mini. لا شيء آخر : لا أعمدة ، لا محتوى.
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "pratique-mini"
}انظر إلى : "acknowledged": true، « تمّ الأمر » ، والاسم في الصدى. الشارة في أعلى يمين الاستجابة تقول 200 - OK.
pratique- في البداية؟ كلّ الفهارس التي تُنشئها في هذه الدورة تحمل هذه البادئة. بهذه الطريقة GET _cat/indices/pratique-*?v يسرد كلّ ما هو لك ولا شيء آخر ، ويبقى cours و avis و acces بلا لمس./. Pratique-Mini سيُرفَض.400 مع resource_already_exists_exception : الخزانة موجودة بالفعل. ليس عطلًا ، إنّها استجابة.GET _cat/indices/pratique-mini?vما يطلبه الاستعلام : سطر ملخّص عن هذا الفهرس ، مع سطر العنوان (?v، verbose).
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
yellow open pratique-mini YHjAfGXBTwSZcl7CLcc2jw 1 1 0 0 227b 227b 227bانظر إلى : docs.count 0، الخزانة فارغة. و health yellow مع rep 1 : خطّط Elasticsearch نسخة احتياطيّة (réplica) لفهرسك على آلة ثانية ، ولا يمتلك المختبر إلّا آلة واحدة. لا يمكن وضع النسخة في أيّ مكان ، من هنا الأصفر. الفهارس الثلاثة للحزمة خضراء لأنّ ربطها يضبط number_of_replicas: 0. فعِل الشيء نفسه ، باستعلام واحد :
PUT pratique-mini/_settings
{
"index": { "number_of_replicas": 0 }
}{
"acknowledged": true
}أعد كتابة GET _cat/indices/pratique-mini?v :
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size dataset.size
green open pratique-mini YHjAfGXBTwSZcl7CLcc2jw 1 0 0 0 227b 227b 227bانظر إلى : green، rep 0. سيكون uuid لديك مختلفًا : إنّه المعرّف الداخليّ للفهرس ، يُسحَب عشوائيًّا عند الإنشاء.
GET _cluster/health كان يقول "status": "yellow" لكلّ المجموعة : لون المجموعة هو أسوأ لون بين فهارسها. هذا هو شرح عطل « yellow » في كتالوج الدرس 04.GET pratique-mini (بدون _cat) يُعيد بطاقة الفهرس الكاملة : "mappings": { } (فارغة ، لا بطاقة مُرتَّبة) و "settings" مع number_of_replicas.PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}ما يطلبه الاستعلام : في الخزانة pratique-mini، رتّب بطاقة (_doc) رقم 1 تحتوي على حقل titre.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}انظر إلى : "result": "created" و "_version": 1 : أوّل إصدار من البطاقة 1. معادل SQL : INSERT INTO pratique_mini (id, titre) VALUES (1, 'Mon premier document')، إلّا أنّه لم يكن هناك حاجة لأيّ CREATE TABLE.
GET pratique-mini/_mapping : الحقل titre مُعرَّف الآن من نوع text (للبحث عن كلمات فيه) مع حقل فرعيّ titre.keyword (للترتيب أو الترشيح على القيمة الدقيقة). استنتج Elasticsearch ذلك من القيمة "Mon premier document"، سلسلة حروف.1 في _doc/1، أنت من اخترته. تفعل مستندات الحزمة الشيء نفسه (C0001، A00001…). إذا كتبت POST pratique-mini/_doc بدون رقم ، سيخترع Elasticsearch _id من عشرين حرفًا ؛ عمليّ للسجلّات ، مزعج لبطاقة تريد إيجادها يدويًّا._shards, _seq_no, _primary_term هي محاسبة داخليّة (على كم قطعة تمّ تأكيد الكتابة ، أيّ رقم ترتيب). لا تحتاجها في هذه الدورة.GET pratique-mini/_doc/1ما يطلبه الاستعلام : أعطني البطاقة رقم 1 من pratique-mini، مباشرة ، بدون بحث.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 1,
"_seq_no": 0,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document"
}
}انظر إلى : "found": true، و _source، بطاقتك كما كتبتها ، بالحرف الواحد. معادل SQL : SELECT * FROM pratique_mini WHERE id = 1.
جرّب بطاقة غير موجودة : GET pratique-mini/_doc/3.
{
"_index": "pratique-mini",
"_id": "3",
"found": false
}لا خطأ ، لا _source : "found": false، شارة 404 - Not Found. فهم Elasticsearch السؤال ؛ الجواب هو « لا يوجد شيء بهذا الرقم ».
POST pratique-mini/_update/1
{
"doc": {
"auteur": "Alice",
"note": 5
}
}ما يطلبه الاستعلام : حدّث (_update) البطاقة 1 بـ إضافة هذين الحقلين. ما لم يُذكَر (titre) يبقى كما هو.
{
"_index": "pratique-mini",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1
}انظر إلى : "result": "updated"، "_version": 2. أعد قراءة البطاقة بـ GET pratique-mini/_doc/1 :
{
"_index": "pratique-mini",
"_id": "1",
"_version": 2,
"_seq_no": 1,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document",
"note": 5,
"auteur": "Alice"
}
}ثلاثة حقول. العنوان لا يزال موجودًا. معادل SQL : UPDATE pratique_mini SET auteur = 'Alice', note = 5 WHERE id = 1، بفرق أنّه في SQL يجب أن تكون الأعمدة auteur و note موجودة مسبقًا. هذه استجابتك-تسليمتك : احتفظ بها.
doc في المتن تعني « ها هي الحقول التي يجب دمجها ». بدونها ، لا يعرف _update ماذا يفعل.GET pratique-mini/_mapping الآن auteur (text + keyword، كـ titre) و note من نوع long، عدد صحيح. استنتج Elasticsearch النوع من 5. لو كتبت "note": "5" بين علامتي اقتباس ، لأعلن نصًّا ، ولم تعد قادرًا على حساب متوسّط عليه. هذا موضوع درس الربط في الوحدة 2._version تعدّ الكتابات على هذه البطاقة ، لا القراءات : GET لا يزيدها أبدًا.PUT يستبدل كلّ شيءأعد إرسال استعلام الخطوة 3 بالضبط :
PUT pratique-mini/_doc/1
{
"titre": "Mon premier document"
}{
"_index": "pratique-mini",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 3,
"_primary_term": 1
}انظر إلى : "result": "updated" (ليس created : البطاقة 1 كانت موجودة) و "_version": 3. ثم أعد قراءتها :
{
"_index": "pratique-mini",
"_id": "1",
"_version": 3,
"_seq_no": 3,
"_primary_term": 1,
"found": true,
"_source": {
"titre": "Mon premier document"
}
}اختفى auteur و note. PUT _doc/1 لا يُعدّل البطاقة 1 : يستبدلها بما ترسله. لإكمالها دون خسارة ، الطريقة هي POST _update/1 مع doc. احتفظ بالقاعدة مع الفعلين : PUT يستبدل ، _update يُكمّل. أعِد الحقلين بطلب الخطوة 5 قبل الاستمرار (تحصل على _version: 4).
PUT pratique-mini/_doc/2
{
"titre": "Deuxième document, écrit par Bob",
"auteur": "Bob",
"note": 3
}الاستجابة : "_id": "2"، "result": "created"، "_version": 1. ثم عدّ :
GET pratique-mini/_count{
"count": 2,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
}
}معادل SQL : SELECT COUNT(*) FROM pratique_mini. الآن ، انظر إلى كلّ ما يحتويه :
GET pratique-mini/_searchما يطلبه الاستعلام : بحث في pratique-mini، بدون معيار ، إذن كلّ شيء.
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "pratique-mini",
"_id": "2",
"_score": 1.0,
"_source": {
"titre": "Deuxième document, écrit par Bob",
"auteur": "Bob",
"note": 3
}
},
{
"_index": "pratique-mini",
"_id": "1",
"_score": 1.0,
"_source": {
"titre": "Mon premier document",
"note": 5,
"auteur": "Alice"
}
}
]
}
}انظر إلى : hits.total.value: 2 (كم بطاقة تُجيب) ثم hits.hits، قائمة البطاقات ، كلّ واحدة بـ _id و _source خاصّتها. يمكن أن يتغيّر ترتيب الاثنتين : بدون معيار ، كلّها بنفس _score يساوي 1.0. معادل SQL : SELECT * FROM pratique_mini.
وأخيرًا ، ابحث عن كلمة :
GET pratique-mini/_search
{
"query": {
"match": {
"titre": "premier"
}
}
}ما يطلبه الاستعلام : البطاقات التي يحتوي حقل titre فيها على كلمة premier.
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.3788134,
"hits": [
{
"_index": "pratique-mini",
"_id": "1",
"_score": 0.3788134,
"_source": {
"titre": "Mon premier document",
"note": 5,
"auteur": "Alice"
}
}
]
}
}انظر إلى : بطاقة واحدة فقط ، الـ 1 ، و _score ليست 1.0 بعد الآن : إنّها الصلة ، « إلى أيّ حدّ تُجيب هذه البطاقة على السؤال ». الوحدة 3 مخصّصة لهذا الرقم. معادل SQL تقريبيّ : SELECT * FROM pratique_mini WHERE titre LIKE '%premier%'، إلّا أنّ match ستجد أيضًا Premier بحرف كبير ، وستُفسّر لك الوحدة 2 السبب.
_count 0 أو 1 مباشرة بعد كتابة؟ يجعل Elasticsearch البطاقات الجديدة مرئيّة للبحث كلّ ثانية، لا فورًا. أعد تشغيل _count : أصبح محدَّثًا. GET _doc/1، هي دائمًا فوريّة لأنّها لا تبحث ، تذهب مباشرة إلى الرقم. إذا أردت إجبار الرؤية الفوريّة في اختبار : PUT pratique-mini/_doc/2?refresh=true.took هو زمن البحث بالميلّي ثانية. timed_out: false : انتهى في الوقت المحدَّد.GET مع متن؟ هذه خاصيّة لدى Elasticsearch : البحث قراءة ، إذن GET، لكنّ السؤال يتّسع في متن JSON. يعمل POST pratique-mini/_search بالمتن نفسه أيضًا ؛ الاثنان مقبولان.DELETE pratique-mini/_doc/2{
"_index": "pratique-mini",
"_id": "2",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 4,
"_primary_term": 1
}انظر إلى : "result": "deleted". GET pratique-mini/_count يُعيد 1 (بعد ثانية). معادل SQL : DELETE FROM pratique_mini WHERE id = 2.
ثم احذف الخزانة كاملة ، بما فيها البطاقات :
DELETE pratique-mini{
"acknowledged": true
}الدليل على أنّها لم تعد موجودة ، GET pratique-mini/_doc/1 :
{
"error": {
"root_cause": [
{
"type": "index_not_found_exception",
"reason": "no such index [pratique-mini]",
"resource.type": "index_or_alias",
"resource.id": "pratique-mini",
"index_uuid": "_na_",
"index": "pratique-mini"
}
],
"type": "index_not_found_exception",
"reason": "no such index [pratique-mini]",
"resource.type": "index_or_alias",
"resource.id": "pratique-mini",
"index_uuid": "_na_",
"index": "pratique-mini"
},
"status": 404
}انظر إلى : الفرق مع الخطوة 4. بطاقة غائبة في خزانة موجودة : "found": false، بلا خطأ. خزانة غائبة : index_not_found_exception، 404. الاثنان استجابتان طبيعيّتان لخدمة تعمل. معادل SQL : DROP TABLE pratique_mini.
GET _cat/indices/pratique-*?vالاستجابة المتوقَّعة : سطر العنوان وحده. لا شيء لك مُتبقٍّ في المجموعة ، و GET _cat/indices/cours,avis,acces?v يعرض دائمًا 504، 609، 12000.
pratique-mini وتعرف لماذا كان أصفر ، ثم أخضر.PUT _doc/1 وأعدت قراءتها بـ GET _doc/1.auteur و note بـ POST _update/1 دون فقدان titre.PUT _doc/1 يحذف الحقلين ، وتعرف قول القاعدة : PUT يستبدل ، _update يُكمّل._count 2، سرد _search البطاقتين ، احتفظ match بواحدة فقط.pratique-* فارغ.GET pratique-mini/_doc/1 بثلاثة حقول (الخطوة 5) كتسليمة.400 مع Unexpected character أو was expecting double-quote to start field name → متن JSON غير سليم : كلّ اسم حقل وكلّ نصّ بين علامتي اقتباس مزدوجتين "، فاصلة بين الحقول ، بلا فاصلة بعد الأخير. يُظلّل Dev Tools المكان.400 مع resource_already_exists_exception على PUT pratique-mini → الفهرس موجود بالفعل (أعدت الخطوة 1). استمرّ إلى الخطوة 2 ، أو DELETE pratique-mini للبدء من الصفر.400 مع no handler found for uri → خطأ إملائيّ في كلمة بـ _ : _serch، _doc/ مُنسيّ ، _udpate. يتحقّق Elasticsearch من المسار قبل كلّ شيء آخر.405 مع Incorrect HTTP method for uri [/pratique-mini/_update/1] and method [GET], allowed: [POST] → فعل خاطئ لهذا المسار. تقول الرسالة نفسها أيّ فعل مقبول.400 مع [UpdateRequest] unknown field [titre] → أرسلت الحقول مباشرة إلى _update، بدون تغليفها في "doc": { … }. أضف الغلاف._count أو _search البطاقة التي كتبتها للتوّ → انتظر ثانية وأعد التشغيل (انظر « لفهم أعمق » في الخطوة 7). GET _doc/1 يراها فورًا."result": "noop" على _update → كانت القيم المُرسَلة هي نفسها بطاقة موجودة بالفعل ؛ لا شيء يجب تغييره ، لم تتحرّك _version. ليس خطأً."status": "yellow" في GET _cluster/health بعد الخطوة 2 → فهرس آخر لك لا يزال بـ rep 1. GET _cat/indices?v&health=yellow يُحدّده ؛ طبّق عليه نفس _settings، أو احذفه..\labo.ps1 etat أو ./labo.sh etat، ثم الدرس 04.