בדף הזה מוסבר איך לעבוד עם נתיבי גרפים ב-Spanner Graph.
במסדי נתונים של גרפים, סוג הנתונים של נתיב הגרף מייצג רצף של צמתים שמשולבים עם קשתות, ומראה את הקשר בין הצמתים והקשתות האלה. מידע נוסף על סוג הנתונים של הנתיב זמין במאמר סוג נתונים של נתיב בגרף.
בעזרת Spanner Graph Language (GQL), אפשר ליצור נתיבי גרף ולהריץ עליהם שאילתות. הדוגמאות במסמך הזה משתמשות באותה סכימת Spanner Graph שמופיעה בדף הגדרה והרצת שאילתות ב-Spanner Graph.
בניית נתיב גרף
אפשר ליצור נתיב גרף על ידי יצירת משתנה נתיב בתבנית גרף או באמצעות הפונקציה PATH.
מומלץ ליצור נתיב גרף באמצעות משתנה הנתיב. הפורמט ליצירת משתנה נתיב הוא:
MATCH p = PATH_PATTERN
מידע נוסף זמין במאמר בנושא דפוסים בגרף.
דוגמה
בדוגמה הבאה, השאילתה מוצאת דפוסים של העברות כספים בין חשבונות בתוך FinGraph.
GRAPH FinGraph
MATCH p = (src:Account {id: 16})-[t:Transfers]->{2}(dst:Account {id: 7})
RETURN TO_JSON(p) AS full_path;
תוצאה
| full_path |
|---|
| [{"identifier": ..., "properties": {"id": 16, ...}, ...}, {"identifier": ..., "properties": {"amount": 300.0, ...}, ...}, ...] |
התוצאה מציינת שהשאילתה מצאה את התבנית Account -> Transfers -> Account
במסד הנתונים.
שאילתה של נתיב גרף
אפשר להשתמש בפונקציות הבאות שספציפיות לנתיב כדי לשלוח שאילתה לנתיב בתרשים. למידע כללי נוסף על שאילתות של Spanner Graph, אפשר לעיין בסקירה כללית של שאילתות.
EDGES
הפונקציה EDGES מחזירה את כל הקשתות בנתיב של גרף. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר בנושא EDGES.
דוגמה
השאילתה הזו מוצאת נתיב בין שני חשבונות שעובר דרך חשבון אמצעי.
הפונקציה מחזירה את הסכום של הקצה השני Transfers בנתיב, שיכול להיות בין src ל-mid או בין mid ל-dst.
GRAPH FinGraph
MATCH p = (src:Account {id: 7})-[t1:Transfers]->{1,3}(mid:Account)-[t2:Transfers]->
{1,3}(dst:Account {id: 16})
LET second_edge = EDGES(p)[1]
RETURN DISTINCT src.id AS src, dst.id AS dst, second_edge.amount AS second_edge_amount;
תוצאה
| src | dst | second_edge_amount |
|---|---|---|
| 7 | 16 | 300 |
NODES
הפונקציה NODES מחזירה את כל הצמתים בנתיב של גרף. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר NODES.
דוגמה
השאילתה הזו מוצאת את נתיב הגרף של שתי העברות, ואז מחזירה רשימת JSON שמייצגת את הנתיב.
GRAPH FinGraph
MATCH p = (src:Account)-[t:Transfers]->{2}(dst:Account)
RETURN TO_JSON(NODES(p)) AS nodes;
תוצאה
| צמתים |
|---|
| [{"identifier": "...", "properties": {"id": 16}, ...}, {"identifier": "...", "properties": {"id": 20, ...}, ...] |
| ... |
PATH_FIRST
הפונקציה PATH_FIRST מוצאת את הצומת הראשון בנתיב של גרף. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר PATH_FIRST.
דוגמה
השאילתה הזו מוצאת את הצומת הראשון בנתיב גרף של שני העברות. הפונקציה מחזירה את התווית של הצומת Account ואת הכינוי של החשבון.
GRAPH FinGraph
MATCH p = -[:Transfers]->{1,3}(dst:Account{id: 7})
RETURN DISTINCT PATH_FIRST(p).id AS can_reach_target;
תוצאה
| can_reach_target |
|---|
| 7 |
| 16 |
| 20 |
PATH_LAST
הפונקציה PATH_LAST מוצאת את הצומת האחרון בנתיב של גרף. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר PATH_LAST.
דוגמה
השאילתה הזו מוצאת את הצומת האחרון בנתיב גרף של שתי העברות. הפונקציה מחזירה את התווית של הצומת Account ואת הכינוי של החשבון.
GRAPH FinGraph
MATCH p =(start:Account{id: 7})-[:Transfers]->{1,3}
RETURN DISTINCT PATH_LAST(p).id as can_reach_target;
תוצאה
| can_reach_target |
|---|
| 7 |
| 16 |
| 20 |
PATH_LENGTH
הפונקציה PATH_LENGTH מחזירה את מספר הקשתות בנתיב בגרף. מידע נוסף על הסמנטיקה זמין במאמר PATH_LENGTH.
דוגמה
השאילתה הזו מוצאת את מספר הקשתות בנתיב של גרף שמכיל העברה אחת עד שלוש.
GRAPH FinGraph
MATCH p = (src:Account)-[e:Transfers]->{1,3}(dst:Account)
RETURN PATH_LENGTH(p) AS num_transfers, COUNT(*) AS num_paths;
תוצאה
| num_transfers | num_paths |
|---|---|
| 1 | 5 |
| 2 | 7 |
| 3 | 11 |
IS_ACYCLIC
הפונקציה IS_ACYCLIC בודקת אם יש נתונים חוזרים בנתיב של תרשים. היא מחזירה TRUE אם נמצאים נתונים חוזרים, אחרת היא מחזירה FALSE. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר IS_ACYCLIC.
דוגמה
השאילתה הזו בודקת אם יש צמתים חוזרים בנתיב הגרף הזה.
GRAPH FinGraph
MATCH p = (src:Account)-[t:Transfers]->{2}(dst:Account)
RETURN IS_ACYCLIC(p) AS is_acyclic_path,
ARRAY_TRANSFORM(NODES(p), n->n.id) AS account_ids;
תוצאה
| is_acyclic_path | account_ids |
|---|---|
| TRUE | 16,20,7 |
| TRUE | 20,7,16 |
| TRUE | 20,7,16 |
| לא נכון | 16,20,16 |
| TRUE | 7,16,20 |
| TRUE | 7,16,20 |
| לא נכון | 20,16,20 |
IS_TRAIL
הפונקציה IS_TRAIL בודקת אם יש נתיב בתרשים עם קצוות חוזרים. היא מחזירה TRUE אם נמצאת חזרה, אחרת היא מחזירה FALSE. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר IS_TRAIL.
דוגמה
השאילתה הזו בודקת אם יש חזרות על קשתות בנתיב הגרף הזה.
GRAPH FinGraph
MATCH p = (src:Account)-[t:Transfers]->{3}(dst:Account)
WHERE src.id < dst.id
RETURN IS_TRAIL(p) AS is_trail_path,
ARRAY_TRANSFORM(t, t->t.id) AS transfer_ids
תוצאה
| is_trail_path | transfer_ids |
|---|---|
| לא נכון | 16,20,16 |
| TRUE | 7,16,20 |
| TRUE | 7,16,20 |
מצבי נתיב
ב-Spanner Graph, התנהגות ברירת המחדל היא להחזיר את כל הנתיבים, כולל נתיבים עם צמתים וקשתות שחוזרים על עצמם. אפשר להשתמש במצבי הנתיב הבאים כדי לכלול או להחריג נתיבים עם צמתים וקצוות חוזרים. למידע מפורט על הסמנטיקה, אפשר לעיין במאמר בנושא מצב נתיב.
WALK
מצב הנתיב WALK מחזיר את כל הנתיבים, כולל נתיבים עם צמתים וקצוות חוזרים. WALK הוא מצב הנתיב שמוגדר כברירת מחדל.
דוגמה
השאילתה הבאה מדגימה את השימוש במצב הנתיב WALK בתבנית נתיב כמותית.
הנתיב הראשון בתוצאות כולל קצוות חוזרים.
GRAPH FinGraph
MATCH p = WALK (src:Account)-[t:Transfers]->{3}(dst:Account)
WHERE src.id < dst.id
RETURN ARRAY_TRANSFORM(t, t->t.id) AS transfer_ids
תוצאה
| transfer_ids |
|---|
| 16,20,16 |
| 7,16,20 |
| 7,16,20 |
ACYCLIC
מסננים בACYCLIC מצב הנתיב מסננים נתיבים עם צמתים חוזרים.
דוגמה
השאילתה הבאה מדגימה את השימוש במצב הנתיב ACYCLIC בתבנית נתיב כמותית.
הנתיב עם הצמתים src ו-dst שווים מסונן החוצה.
GRAPH FinGraph
MATCH p = ACYCLIC (src:Account)-[t:Transfers]->{2}(dst:Account)
RETURN ARRAY_TRANSFORM(NODES(p), n->n.id) AS account_ids
תוצאה
| account_ids |
|---|
| 16,20,7 |
| 20,7,16 |
| 20,7,16 |
| 7,16,20 |
| 7,16,20 |
TRAIL
מסנן TRAIL מצב הנתיב מסנן נתיבים עם קצוות חוזרים.
דוגמה
השאילתה הבאה מדגימה את השימוש במצב הנתיב TRAIL בתבנית נתיב כמותית.
המסלולים עם קצוות חוזרים מסוננים.
GRAPH FinGraph
MATCH p = TRAIL (src:Account)-[t:Transfers]->{3}(dst:Account)
WHERE src.id < dst.id
RETURN ARRAY_TRANSFORM(t, t->t.id) AS transfer_ids
תוצאה
| transfer_ids |
|---|
| 7,16,20 |
| 7,16,20 |
קידומת לחיפוש נתיב
אפשר להשתמש בקידומת של חיפוש נתיבים כדי להגביל את דפוס הנתיב כך שיוחזר הנתיב הקצר ביותר מכל מחיצת נתונים. למידע נוסף על הסמנטיקה, אפשר לעיין במאמר בנושא קידומת של חיפוש נתיבים.
ANY SHORTEST
הקידומת ANY SHORTEST של חיפוש הנתיב מחזירה את הנתיב הקצר ביותר (הנתיב עם המספר הקטן ביותר של קצוות) שתואם לתבנית מכל מחיצת נתונים. אם יש יותר מנתיב קצר אחד לכל מחיצה, הפונקציה מחזירה אחד מהם.
דוגמה 1
השאילתה הבאה מתאימה לכל נתיב קצר ביותר בין כל זוג של [a, b].
GRAPH FinGraph
MATCH p = ANY SHORTEST (a:Account {is_blocked:true})-[t:Transfers]->{1,4}(b:Account)
LET total_amount = SUM(t.amount)
RETURN a.id AS account1_id, total_amount, b.id AS account2_id;
תוצאה
| account1_id | total_amount | account2_id |
|---|---|---|
| 16 | 500 | 16 |
| 16 | 800 | 7 |
| 16 | 300 | 20 |
דוגמה 2
שאילתת ה-GQL הבאה משלבת משתנה נתיב עם קידומת חיפוש הנתיב ANY SHORTEST וממירה את הנתיב ל-JSON. השיטה הזו שימושית לאחזור של אובייקט מובנה יחיד שמכיל את הרצף המלא של הצמתים והקשתות שמרכיבים את הנתיב הקצר ביותר, במקום רק את נקודות הקצה או את אורך הנתיב. השאילתה מחזירה רק את הנתיב הקצר ביותר בין שני החשבונות.
GRAPH FinGraph
MATCH p = ANY SHORTEST (a:Account {id: 7})-[:Transfers]->{1,3}(d:Account {id: 20})
RETURN TO_JSON(p) AS results;
תוצאה
| תוצאות |
|---|
| [{"identifier": ..., "properties": {"id": 7, "is_blocked": false, "nick_name": "Vacation Fund"}, ...}, ...] |
ANY CHEAPEST
קידומת החיפוש של הנתיב ANY CHEAPEST מוודאת שכל שאילתה תחזיר רק נתיב אחד עם עלות החישוב הכוללת המינימלית, לכל צמד של חשבונות מקור ויעד. הנתיב הזול ביותר הוא הנתיב עם עלות החישוב הכוללת המינימלית,
שמחושבת מביטויי COST בקצוות של הנתיב. אם יש כמה נתיבים זולים בכל מחיצה, השאילתה מחזירה אחד מהם.
דוגמה
השאילתה הבאה מתאימה לאחד מהמסלולים הזולים ביותר בין כל זוג חשבונות, שמיוצגים על ידי a ו-b, על סמך סכום ההעברה.
GRAPH FinGraph
MATCH ANY CHEAPEST (a:Account)-[t:Transfers COST t.amount]->{1,3}(b:Account)
LET total_cost = sum(t.amount)
RETURN a.id AS account1_id, b.id AS account2_id, total_cost
תוצאה
| account1_id | account2_id | total_cost |
|---|---|---|
| 7 | 7 | 900 |
| 7 | 16 | 100 |
| 7 | 20 | 400 |
| 16 | 7 | 800 |
| 16 | 16 | 500 |
| 16 | 20 | 300 |
| 20 | 7 | 500 |
| 20 | 16 | 200 |
| 20 | 20 | 500 |
כללי המרה
מידע נוסף זמין במאמר כללי המרה של GRAPH_PATH.
דוגמה לתרחיש שימוש
בדוגמה הבאה לתרחיש שימוש, אפשר לראות שכל החשבונות מנותבים דרך חשבון אחד עד שלושה, החל ממזהה החשבון 20.
GRAPH FinGraph
MATCH p = (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;
תוצאה
| dst |
|---|
| 7 |
| 16 |
| 20 |
עם זאת, שאילתה שחוזרת למזהה החשבון 20 עשויה להיות שאילתה רחבה מדי כי היא מתחילה במזהה החשבון 20. כדי להציג תוצאות ספציפיות יותר, אפשר להגדיר שהשאילתה תציג רק נתיבים של גרף לא מחזורי ללא צמתים חוזרים. כדי לעשות זאת, אפשר:
- משתמשים ב-
MATCH p = ACYCLIC <path_pattern>או ב- - החלת מסנן
IS_ACYCLIC(p)בשאילתה
השאילתה הבאה משתמשת במונח MATCH p = ACYCLIC PATH_PATTERN:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN DISTINCT dst.id AS dst;
תוצאה
| dst |
|---|
| 7 |
| 16 |
אם אתם רוצים לדעת דרך איזה חשבון הכסף מועבר בפעם הראשונה, אתם יכולים להריץ את השאילתה הבאה:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})(-[:Transfers]->
(nexts:Account)){1,3}(dst:Account)
RETURN dst.id AS dst, ARRAY_AGG(DISTINCT nexts[0].id) AS unique_starts;
השאילתה הזו לא שגרתית כי היא מציגה משתנה חדש בתוך הנתיב הכמותי באמצעות nexts כדי לקבל את התוצאה. בעזרת משתני נתיב, אפשר לפשט את השאילתה:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id AS dst, ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS unique_starts;
השימוש ב-NODES(p) מחזיר את כל הצמתים לאורך הנתיב. מכיוון שהחשבון הראשון בצומת מוגדר כ-start, החשבון הבא (בקיזוז הראשון) הוא החשבון הראשון שדרכו מועבר הכסף.
תוצאה
| dst | unique_starts |
|---|---|
| 7 | 16, 7 |
הנתיבים שימושיים יותר כשיש כמה נתיבים עם ערכים כמותיים. אפשר להוסיף אילוץ שלפיו הנתיבים שנמצאו מ-start חייבים לעבור דרך מזהה החשבון 7:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->
{1,3}(mid:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
RETURN dst.id AS dst,
ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS unique_starts;
למרות שהמשפט MATCH השתנה, לא צריך לשנות את שאר השאילתה. בלי שימוש במשתני נתיב, יש מקרים שבהם Spanner לא יכול לדעת באופן סטטי איזה נתיב כמותי לבדוק.
באמצעות משתנה נתיב, אפשר לקבל את הסכום של כל ההעברות:
GRAPH FinGraph
MATCH p = ACYCLIC (start:Account {id: 20})-[:Transfers]->
{1,3}(mid:Account {id: 7})-[:Transfers]->{1,3}(dst:Account)
LET all_transfers = EDGES(p)
LET transfer_amounts = SUM(all_transfers.amount)
RETURN dst.id AS dst,
ARRAY_AGG(DISTINCT NODES(p)[OFFSET(1)].id) AS participating_neighbor_nodes, transfer_amounts;
תוצאה
| dst | participating_neighbor_nodes | transfer_amounts |
|---|---|---|
| 16 | 7 | 600 |
| 16 | 7 | 800 |