كيف تقرأ هذه الصفحة. عشر خطوات ، استعلام واحد في كلّ مرّة. لكلّ خطوة : الاستعلام الذي تكتبه ، ما يعرضه Neo4j Browser ، وما يجب النظر إليه. اكتب كلّ استعلام بنفسك. فقرات « لفهم أعمق » اختياريّة. إذا لم يكن المختبر مُشغَّلًا أو إذا لم يقل
etatnœuds : 872، ارجع إلى التطبيق الموجّه، القسم بإيجاز (الحزمة :https://github.com/hrhouma2/aiopsatlas-recherche-graphes-labo-fr).
في التطبيق الموجّه ، عددت 872 عقدة و3712 علاقة حمَّلها نصّ برمجيّ ، ونظرت إلى فقّاعات وأسهم رسمها شخص آخر. هنا ، ترسم أنت خاصّتك. عقدة فارغة أوّلًا ، لترى أنّ العقدة هي هذا فقط ؛ ثم تُعطيها اسمًا وعمرًا ومدينة ؛ ثم عقدة ثانية ، وسهمًا بين الاثنتين ؛ ثم سهمًا نحو دورة من مجموعة البيانات الحقيقيّة. في النهاية ، يرتفع عدّاد etat إلى 874، وتُعيده إلى 872 بحذف ما أنشأته ، مع الخطأ الذي يجب رؤيته مرّة لفهم ما هي العلاقة.
العقدة هي فقّاعة. العلامة تقول من أيّ نوع هذه الفقّاعة (Personne, Cours, Ville) : وهي معادلة اسم الجدول. الخاصيّة هي قيمة مكتوبة في الفقّاعة (nom: "Alice", age: 30) : عمود. العلاقة هي سهم بين فقّاعتين ؛ لها نوع بحروف كبيرة (CONNAIT, AIME)، اتّجاه، ويمكن أن تحمل خصائصها الخاصّة. في SQL ، سيكون السهم مفتاحًا أجنبيًّا أو جدول ربط ؛ هنا إنّه كائن مستقلّ بذاته ، تُنشئه وتقرؤه وتحذفه كعقدة.
| Neo4j | قاعدة SQL كلاسيكيّة | في هذا التطبيق |
|---|---|---|
| عقدة | صفّ | أليس ، بوب |
| علامة | جدول | Personne |
| خاصيّة | عمود | nom, age, ville |
| علاقة | مفتاح أجنبيّ / جدول ربط | CONNAIT, AIME |
| نوع العلاقة | اسم جدول الربط | CONNAIT |
| خاصيّة العلاقة | عمود جدول الربط | depuis: 2024 |
قاعدتان في كتابة Cypher يجب حفظهما : تُكتَب الفقّاعة بين أقواس (p:Personne)، سهم بين أقواس معقَّفة بشرطة ورأس سهم -[:CONNAIT]->. الحرف قبل النقطتين (p, a, r) اسم مؤقّت تختاره لإعادة استخدام الكائن في الاستعلام نفسه.
افتح http://localhost:7474، سجّل الدخول (neo4j / aiopsatlas2026، URL localhost:7687). المحرّر هو السطر neo4j$ في الأعلى. تُرسل بـ Ctrl + Enter (Cmd + Enter على macOS) أو الزرّ ▶ إلى اليمين. يفتح كلّ استعلام إطارًا تحت المحرّر ، الأحدث في الأعلى.
يعرض الإطار شيئين. في الأعلى ، سطر أخضر للحصيلة : Created 1 node, added 1 label، Set 1 property، Deleted 2 nodes… هو من يقول لك ما غيّره الاستعلام. أدناه ، إذا كان للاستعلام RETURN، النتيجة بثلاث معاينات : Graph (الفقّاعات والأسهم)، Table (القيم في أعمدة)، Raw (JSON خام). استعلام بلا RETURN لا يعرض إلّا الحصيلة و Completed after … ms.
CREATE (p:Personne) RETURN pما يطلبه الاستعلام : أنشئ فقّاعة تحمل العلامة Personne، سمّها p طوال الاستعلام ، وأظهرها لي.
الحصيلة : Created 1 node, added 1 label، ثم Started streaming 1 record after 1 ms and completed after 2 ms.
انظر إلى : معاينة Graph ، فقّاعة واحدة فقط ، وإلى اليمين في Results overview : Nodes (1) مع الرقعة Personne (1). اضغط على الفقّاعة : لا يسرد اللوحة أيّ خاصيّة. هذه عقدة أدنى : علامة ، لا شيء آخر. معادل SQL : INSERT INTO personne DEFAULT VALUES، في جدول لا يمتلك أيّ عمود.
CREATE (n) بدون علامة ، يعمل أيضًا. يقبله Neo4j ، لكنّك لن تستطيع إيجادها بعد الآن إلّا بالمرور على كلّ فقّاعات الرسم البيانيّ : صفّ بلا جدول. لا تفعل ذلك ؛ علامة ، دائمًا.Personne علامة جديدة في هذا الرسم البيانيّ ، الذي لم يكن يعرف إلّا خمسة (Competence, Cours, Etudiant, Professeur, Ville). لم تحتَج إلى تعريف أيّ شيء : الفقّاعة الأولى التي تحمل علامة تُنشئها. كالربط في Elasticsearch ، في الورشة الأساسيّة 1.RETURN p ليست إلزاميّة. بدونها ، يُنشئ الاستعلام الفقّاعة ولا يعرض إلّا الحصيلة. إنّها هنا لتراها.MATCH (p:Personne) SET p.nom = 'Alice' RETURN pما يطلبه الاستعلام : اعثر على فقّاعات Personne (واحدة فقط) ، اكتب فيها nom = 'Alice'، أظهرها.
الحصيلة : Set 1 property.
انظر إلى : تحمل الفقّاعة الآن Alice كتسمية (يعرض Browser افتراضيًّا أوّل خاصيّة نصّيّة). اضغط عليها : nom: Alice. معادل SQL : UPDATE personne SET nom = 'Alice'.
MATCH قبل SET. لتعديل فقّاعة ، يجب إيجادها أوّلًا. MATCH (p:Personne) هو SELECT … FROM personne ؛ SET هو UPDATE. تسلسل Cypher الاثنين في الجملة نفسها.'Alice' (تعمل علامات الاقتباس المزدوجة أيضًا). تُكتَب الأرقام عارية : 30، ليس '30'.nom فارغ عند بوب بعد قليل : لن يمتلك ببساطة خاصيّة ville.MATCH (p:Personne {nom: 'Alice'}) SET p.age = 30, p.ville = 'Montréal' RETURN pما يطلبه الاستعلام : اعثر على الفقّاعة Personne التي nom فيها هو Alice، اكتب قيمتين إضافيّتين.
الحصيلة : Set 2 properties.
انظر إلى : الفقّاعة ، بالضغط عليها ، تُظهر nom: Alice، age: 30، ville: Montréal. الـ {nom: 'Alice'} بين الأقواس المُعقَّفة مرشِّح : « تلك التي nom فيها يساوي Alice »، وهو WHERE nom = 'Alice' في SQL. لا يُغيّر شيئًا هنا (Personne واحدة فقط) ، لكنّه يصبح لا غنى عنه من الخطوة التالية.
CREATE (b:Personne {nom: 'Bob', age: 25}) RETURN bما يطلبه الاستعلام : أنشئ فقّاعة Personne تحمل فورًا nom و age.
الحصيلة : Created 1 node, set 2 properties, added 1 label.
انظر الآن إلى فقّاعتيك في جدول :
MATCH (p:Personne) RETURN p.nom, p.age, p.villeمعاينة Table :
p.nom p.age p.ville
"Alice" 30 "Montréal"
"Bob" 25 nullانظر إلى : null لمدينة بوب : لا يمتلك هذه الخاصيّة. في SQL ستكون خليّة فارغة في عمود ville ؛ هنا ، الخانة غير موجودة على الإطلاق. معادل SQL : SELECT nom, age, ville FROM personne.
MATCH (a:Personne {nom: 'Alice'}), (b:Personne {nom: 'Bob'})
CREATE (a)-[:CONNAIT]->(b)ما يطلبه الاستعلام : اعثر على أليس ، سمّها a ؛ اعثر على بوب ، سمّه b ؛ أنشئ سهمًا من نوع CONNAIT ينطلق من a ويصل إلى b.
الحصيلة : Created 1 relationship، ثم Completed after … ms. لا نتيجة : لا يوجد RETURN.
انظر إلى السهم :
MATCH (a:Personne)-[r]->(b:Personne) RETURN a, r, bما يطلبه الاستعلام : كلّ الأسهم ، بغضّ النظر عن نوعها ([r] بدون :TYPE)، التي تذهب من Personne إلى Personne.
انظر إلى : معاينة Graph ، فقّاعتان وسهم مكتوب عليه CONNAIT، باتّجاه أليس → بوب. إلى اليمين ، Results overview : Nodes (2)، Relationships (1) مع الرقعة CONNAIT (1). معادل SQL : INSERT INTO connait (personne_source, personne_cible) VALUES (id_alice, id_bob)، في جدول ربط كان يجب إنشاؤه قبل ذلك.
MATCH في السطر الأوّل : بدونه ، CREATE (a)-[:CONNAIT]->(b) سيُنشئ فقّاعتين جديدتين وفارغتين و سهمًا بينهما. خطأ كلاسيكيّ._ : CONNAIT, A_SUIVI, ENSEIGNE. ليس إلزاميًّا ، إنّه ما يفعله الجميع.(a)-[:CONNAIT]->(b) : رأس السهم على b. لا توجد علاقة بلا اتّجاه في Neo4j ؛ عند القراءة ، بالمقابل ، يمكن تجاهل الاتّجاه (الخطوة 7).MATCH (:Personne {nom: 'Alice'})-[r:CONNAIT]->(:Personne {nom: 'Bob'})
SET r.depuis = 2024
RETURN rما يطلبه الاستعلام : اعثر على سهم CONNAIT الذي يذهب من أليس إلى بوب ، سمّه r، اكتب عليه depuis = 2024.
الحصيلة : Set 1 property.
اقرأ كلّ شيء في جدول :
MATCH (a:Personne)-[r:CONNAIT]->(b:Personne)
RETURN a.nom, type(r), r.depuis, b.noma.nom type(r) r.depuis b.nom
"Alice" "CONNAIT" 2024 "Bob"انظر إلى : type(r) يعطي نوع السهم ؛ r.depuis خاصيّته ، بالضبط كـ p.nom لفقّاعة. تُعامَل العلاقة كعقدة : نجدها ، نُسمّيها ، نقرأ ونكتب فيها. الفقّاعات بلا اسم مؤقّت ، (:Personne {…})، هي تلك التي لا تحتاجها بعد ذلك : يمكنك حذف الحرف.
MATCH (:Personne {nom: 'Bob'})-[:CONNAIT]->(x) RETURN x.nomما يطلبه الاستعلام : من يعرف بوب؟ الفقّاعات x في نهاية سهم CONNAIT ينطلق من بوب.
(no changes, no records)انظر إلى : صفر سطر. السهم الوحيد يذهب من أليس إلى بوب ؛ لا سهم ينطلق من بوب. الآن بدون رأس السهم :
MATCH (:Personne {nom: 'Bob'})-[:CONNAIT]-(x) RETURN x.nomx.nom
"Alice"-[:CONNAIT]- بدون > : « سهم CONNAIT بين بوب و x، في اتّجاه أو في الآخر ». تظهر أليس. احتفظ بـ : عند الكتابة ، الاتّجاه إلزاميّ ؛ عند القراءة ، تختار أخذه بالحسبان أو لا. هذا ما يجعل « من مرتبط بمن » قصيرًا جدًّا للكتابة في Cypher.
MATCH (a:Personne {nom: 'Alice'}), (c:Cours {id: 'C0001'})
CREATE (a)-[:AIME]->(c)ما يطلبه الاستعلام : اعثر على أليس ، اعثر على الدورة C0001 من مجموعة البيانات ، أنشئ سهمًا AIME من الأولى إلى الثانية.
الحصيلة : Created 1 relationship.
ارتبطت أليس الآن بفقّاعة كانت موجودة قبلك. انظر إلى كلّ ما ينطلق منها :
MATCH (a:Personne {nom: 'Alice'})-[r]->(x)
RETURN a.nom, type(r), labels(x)[0] AS type_cible, coalesce(x.nom, x.titre) AS ciblea.nom type(r) type_cible cible
"Alice" "AIME" "Cours" "Docker expliqué simplement"
"Alice" "CONNAIT" "Personne" "Bob"انظر إلى : سطران ، نوعان من السهم ، نوعان من الهدف. labels(x)[0] يعطي علامة الفقّاعة في النهاية ؛ coalesce(x.nom, x.titre) يأخذ nom إن وُجد ، وإلّا titre (لبوب nom، للدورة titre). هذا جدولك-تسليمتك : احتفظ به. في SQL ، سيكون مطلوبًا ربط لكلّ جدول هدف و UNION ؛ هنا ، سطر واحد فقط من MATCH.
انتقل إلى معاينة Graph على MATCH (a:Personne {nom: 'Alice'})-[r]->(x) RETURN a, r, x : أليس في المركز ، بوب على جانب ، الدورة على الآخر ، بلونين (واحد لكلّ علامة).
MATCH (n) RETURN count(n) AS noeudsnoeuds
874872 + فقّاعتاك. حسب العلامة :
MATCH (n) RETURN labels(n)[0] AS label, count(*) ORDER BY labellabel count(*)
"Competence" 22
"Cours" 504
"Etudiant" 300
"Personne" 2
"Professeur" 30
"Ville" 16انظر إلى : سطر سادس ، Personne 2. في طرفيّة ، يعرض .\labo.ps1 etat أو ./labo.sh etat الآن ✔ Neo4j répond — nœuds : 874. يعدّ النصّ البرمجيّ وNeo4j Browser الشيء نفسه بمسارين : هذا التحقّق المتبادل من التطبيق الموجّه ، مُطبَّق على ما أنشأته أنت بنفسك.
جرّب أوّلًا الحذف السطحيّ :
MATCH (p:Personne) DELETE pNeo.ClientError.Schema.ConstraintValidationFailed
Cannot delete node<874>, because it still has relationships. To delete this node, you must first delete its relationships.انظر إلى : إطار أحمر ، لم يُحذَف شيء. يرفض Neo4j مسح فقّاعة لديها أسهم متبقّية : سهم بلا فقّاعة في النهاية لن يكون له معنى. الرقم node<874> هو المعرّف الداخليّ لأوّل فقّاعة حاول حذفها ؛ عندك يختلف. هذا معادل انتهاك مفتاح أجنبيّ في SQL ، بفرق واحد : هنا ، العلاج في كلمة واحدة.
MATCH (p:Personne) DETACH DELETE pما يطلبه الاستعلام : اعثر على فقّاعات Personne، فُكّها (احذف أسهمها) ، ثم احذفها.
الحصيلة : Deleted 2 nodes, deleted 2 relationships.
عقدتان ، علاقتان : CONNAIT و AIME. لم يُلمَس الدرس C0001، اختفى فقط السهم الذي كان يقود إليه. تحقّق :
MATCH (n) RETURN count(n) AS noeudsnoeuds
872يُعيد MATCH (n) RETURN labels(n)[0] AS label, count(*) ORDER BY label خمسة أسطر من جديد ، بلا Personne، ويقول etat nœuds : 872.
DETACH DELETE هي الحركة الطبيعيّة لحذف عقدة في Neo4j ؛ DELETE وحدها لا تُستخدَم إلّا لعقدة تعرف أنّها معزولة ، أو لحذف علاقة : MATCH ()-[r:AIME]->() DELETE r يمحو السهم ويحتفظ بالفقّاعات.MERGE عوض CREATE : « أنشئ إذا لم يكن موجودًا ، وإلّا أعِد استخدامه ». هذا ما يسمح لنصّ charger-graphe البرمجيّ بإعادة التنفيذ دون تكرار. مع CREATE، إعادة تشغيل الخطوة 4 كانت ستصنع بوب ثانيًا.DELETE pratique-mini في الورشة الأساسيّة 1. اعتد على ذلك : ما تُنشئه للتعلّم ، تحذفه في النهاية.nom، ثم age و ville، بـ SET، بعد إيجادها أوّلًا بـ MATCH.null حيث تنقص خاصيّة.CONNAIT بين فقّاعتين موجودتين ، وضعت depuis عليها ، وقرأت type(r) و r.depuis في جدول.(Bob)-[:CONNAIT]->(x) لا يُعيد شيئًا و (Bob)-[:CONNAIT]-(x) يُعيد أليس.C0001 واحتفظت بالجدول ذي السطرين من الخطوة 8 كتسليمة.Cannot delete node … because it still has relationships، ثم أعطى DETACH DELETE Deleted 2 nodes, deleted 2 relationships.MATCH (n) RETURN count(n) و etat يقولان 872.Invalid input, expected … بالأحمر → خطأ صياغة. الأسباب الثلاثة الأكثر شيوعًا في القاعة : قوس ( مُغلَق بقوس معقَّف ]، رأس سهم مُنسيّ عند الكتابة (-[:CONNAIT]- في CREATE مرفوض : Only directed relationships are supported in CREATE)، علامة اقتباس مُنسيّة حول نصّ.Variable `r` not defined (أو a، p…) → تستخدم حرفًا في SET أو RETURN لم يُقدّمه أيّ MATCH أو CREATE من نفس الاستعلام. مثال : SET r.depuis = 2024 بينما كُتب السهم -[:CONNAIT]-> بدون r. أضف الحرف حيث يظهر الكائن : -[r:CONNAIT]->.Created 2 nodes, created 1 relationship، ويعرض Results overview * (4)) → كتبت CREATE (a)-[:CONNAIT]->(b) بدون MATCH قبله مباشرة ، أو بفاصلة منقوطة بين السطرين. كانا a و b مجهولين : لا يحتجّ Neo4j ، يخترعهما ، بلا علامة ولا خاصيّة. نظّف : MATCH (n) WHERE size(labels(n)) = 0 DETACH DELETE n، ثم أعِد الخطوة 5 في استعلام واحد.MATCH (p:Personne) RETURN count(p) يُعيد أكثر من 2) → أعدت تشغيل CREATE. MATCH (p:Personne) DETACH DELETE p وأعِد من الخطوة 1 ؛ ستُعلّمك الوحدة 6 MERGE، الذي يتجنّب ذلك.Cannot delete node … because it still has relationships → هذه الخطوة 10 ، مقصودة. DETACH DELETE.<id> عوض Alice → لا يعرف Browser بعد أيّ خاصيّة يعرض. اضغط على الرقعة Personne تحت الرسم البيانيّ واختر nom كتسمية ؛ أو اقرأ في معاينة Table.etat دائمًا nœuds : 872 بعد إنشاءاتك → أنت متّصل بقاعدة أخرى أو Neo4j آخر (neo4j مثبَّت محليًّا على المنفذ 7687؟). في Browser ، يجب أن يقول الشريط في الأعلى neo4j://localhost:7687 و Database: neo4j ؛ وإلّا ، أغلق Neo4j الآخر أو غيّر منفذه.Neo.ClientError.Security.Unauthorized → كلمة سرّ مرفوضة. هي aiopsatlas2026 ؛ إذا غيّرتها وفقدتها ، ./labo.sh reinitialiser ثم demarrer و charger-graphe (تُعاد بيانات الحزمة كما هي).