סקירה כללית של שאילתות גרף

באמצעות BigQuery Graph אתם יכולים לכתוב שאילתות של תרשימים כדי להתאים דפוסים של צמתים, קצוות ונתיבים, ולעבור בין קשרים באמצעות Graph Query Language‏ (GQL). הדוגמאות במסמך הזה מתייחסות לתרשים בשם FinGraph, שמציג את הקשרים בין אנשים, החשבונות שבבעלותם והעברות בין חשבונות. למידע על הגדרת התרשים, ראו דוגמה ל-FinGraph.

מבנה השאילתה

שאילתת תרשים מורכבת משם התרשים, ואחריו הצהרת שאילתה לינארית אחת או יותר. כל שאילתה לינארית מכילה הצהרה אחת או יותר, שמאפשרת לעבוד עם נתוני תרשים כדי למצוא התאמות לדפוסים, להגדיר משתנים, לסנן ולשנות נתוני ביניים ולהחזיר תוצאות. מריצים שאילתת תרשים באותו אופן שבו מריצים שאילתת SQL ב-BigQuery.

מבנה של שאילתת גרף לדוגמה.
דוגמה למבנה של שאילתת תרשים.

התאמת תבניות בגרפים

התאמת דפוסים בתרשים מוצאת דפוסים ספציפיים בתרשים. התבניות הבסיסיות ביותר הן תבניות של רכיבים, כמו תבניות של צמתים שתואמות לצמתים ותבניות של קצוות שתואמות לקצוות.

תבניות של צמתים

תבנית צומת תואמת לצמתים בתרשים. התבנית הזו מכילה סוגריים תואמים, שיכולים לכלול משתנה של תבנית גרף, ביטוי תווית ומסנני מאפיינים.

למצוא את כל הצמתים

השאילתה הבאה מחזירה את כל הצמתים בתרשים. המשתנה n, משתנה של תבנית תרשים, נקשר לצמתים התואמים. במקרה כזה, תבנית הצומת תואמת לכל הצמתים בתרשים.

GRAPH graph_db.FinGraph
MATCH (n)
RETURN LABELS(n) AS label, n.id;

השאילתה הזו מחזירה את label ו-id:

label id
Account 7
Account 16
Account 20
Person 1
Person 2
Person 3

חיפוש כל הצמתים עם תווית ספציפית

השאילתה הבאה תואמת לכל הצמתים בתרשים שיש להם את התווית Person. השאילתה מחזירה את התווית וכמה מאפיינים של הצמתים התואמים.

GRAPH graph_db.FinGraph
MATCH (p:Person)
RETURN LABELS(p) AS label, p.id, p.name;

השאילתה הזו מחזירה את המאפיינים הבאים של הצמתים התואמים:

label id name
Person 1 Alex
Person 2 Dana
Person 3 Lee

חיפוש כל הצמתים שתואמים לביטוי של תווית

אפשר ליצור ביטוי תווית עם אופרטור לוגי אחד או יותר. לדוגמה, השאילתה הבאה תואמת לכל הצמתים בתרשים שיש להם את התווית Person או Account. המשתנה n של תבנית התרשים חושף את כל המאפיינים מצמתים עם התווית Person או Account.

GRAPH graph_db.FinGraph
MATCH (n:Person|Account)
RETURN LABELS(n) AS label, n.id, n.birthday, n.create_time;

שימו לב לפרטים הבאים בתוצאות של השאילתה הזו:

  • לכל הצמתים יש את המאפיין id.
  • לצמתים שתואמים לתווית Account יש את המאפיין create_time אבל אין להם את המאפיין birthday. המאפיין birthday הוא NULL בצמתים האלה.
  • לצמתים שתואמים לתווית Person יש את המאפיין birthday אבל אין להם את המאפיין create_time. המאפיין create_time הוא NULL בצמתים האלה.
label id birthday create_time
Account 7 NULL 2020-01-10T14:22:20.222Z
Account 16 NULL 2020-01-28T01:55:09.206Z
Account 20 NULL 2020-02-18T13:44:20.655Z
Person 1 1991-12-21T08:00:00Z NULL
Person 2 1980-10-31T08:00:00Z NULL
Person 3 1986-12-07T08:00:00Z NULL

חיפוש כל הצמתים שתואמים לביטוי התווית ולמסנן המאפיינים

השאילתה הבאה תואמת לכל הצמתים בתרשים עם התווית Person והמאפיין id ששווה ל-1:

GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})
RETURN LABELS(p) AS label, p.id, p.name, p.birthday;

התוצאה אמורה להיראות כך:

label id name birthday
Person 1 Alex 1991-12-21T08:00:00Z

אפשר להשתמש בסעיף WHERE כדי ליצור תנאי סינון מורכבים יותר בתוויות ובמאפיינים.

השאילתה הבאה משתמשת בסעיף WHERE כדי לסנן צמתים שבהם המאפיין birthday הוא לפני 1990-01-10:

GRAPH graph_db.FinGraph
MATCH (p:Person WHERE p.birthday < '1990-01-10')
RETURN LABELS(p) AS label, p.name, p.birthday;

התוצאה אמורה להיראות כך:

label name birthday
Person Dana 1980-10-31T08:00:00Z
Person Lee 1986-12-07T08:00:00Z

תבניות קצה

תבנית קשתות תואמת לקשתות או לקשרים בין צמתים. תבניות קצוות מוקפות בסוגריים מרובעים ([]) וכוללות סמלים כמו -,‏ -> או <- כדי לציין כיוונים. תבנית קשת יכולה לכלול משתנה של תבנית גרף כדי לקשר לקשתות תואמות.

חיפוש כל הקצוות עם תוויות תואמות

השאילתה הזו מחזירה את כל הקצוות בתרשים עם התווית Transfers. השאילתה מקשרת את משתנה תבנית התרשים e לקצוות התואמים.

GRAPH graph_db.FinGraph
MATCH -[e:Transfers]->
RETURN e.Id as src_account, e.order_number;

התוצאה אמורה להיראות כך:

src_account order_number
7 304330008004315
7 304120005529714
16 103650009791820
20 304120005529714
20 302290001255747

חיפוש כל הקצוות שתואמים לביטוי התווית ולמסנן המאפיינים

תבנית הקצה בשאילתה הבאה משתמשת בביטוי תווית ובמסנן מאפיינים כדי למצוא את כל הקצוות עם התווית Transfers שתואמים למספר הזמנה מסוים:

GRAPH graph_db.FinGraph
MATCH -[e:Transfers {order_number: "304120005529714"}]->
RETURN e.Id AS src_account, e.order_number;

התוצאה אמורה להיראות כך:

src_account order_number
7 304120005529714
20 304120005529714

חיפוש כל הקצוות באמצעות כל דפוס של קצה כיוון

אפשר להשתמש בתבנית הקצה any direction (-[]-) בשאילתה כדי להתאים קצוות בכל כיוון. השאילתה הבאה מוצאת את כל ההעברות עם חשבון חסום:

GRAPH graph_db.FinGraph
MATCH (account:Account)-[transfer:Transfers]-(:Account {is_blocked:true})
RETURN transfer.order_number, transfer.amount;

התוצאה אמורה להיראות כך:

order_number amount
304330008004315 300
304120005529714 100
103650009791820 300
302290001255747 200

תבניות נתיבים

תבנית נתיב מורכבת מתבניות של צמתים וקצוות לסירוגין.

חיפוש כל הנתיבים מצומת ספציפי באמצעות תבנית נתיב

השאילתה הבאה מוצאת את כל ההעברות לחשבון שהתחילו מחשבון שבבעלות Person, כאשר id שווה ל-2.

כל תוצאה תואמת מייצגת נתיב מצומת Person כאשר id שווה ל-2 דרך צומת Account מחובר באמצעות קצה Owns, לצומת Account אחר באמצעות קצה Transfers.

GRAPH graph_db.FinGraph
MATCH
  (p:Person {id: 2})-[:Owns]->(account:Account)-[t:Transfers]->
  (to_account:Account)
RETURN
  p.id AS sender_id, account.id AS from_id, to_account.id AS to_id;

התוצאה אמורה להיראות כך:

sender_id from_id to_id
2 20 7
2 20 16

תבניות נתיבים כמותיות

תבנית מכומתת חוזרת על תבנית בטווח מסוים.

התאמה של תבנית קצה מכומתת

כדי למצוא נתיבים באורך משתנה, אפשר להחיל כַּמָּת על תבנית קצה. השאילתה הבאה מדגימה את זה על ידי חיפוש חשבונות יעד שנמצאים במרחק של העברה אחת עד שלוש העברות ממקור Account עם ערך id של 7.

השאילתה מחילה את הכַּמָּת {1, 3} על תבנית הקצה -[e:Transfers]->. ההוראה הזו מנחה את השאילתה להתאים נתיבים שחוזרים על תבנית הקצה Transfers פעם אחת, פעמיים או שלוש פעמים. הסעיף WHERE משמש להחרגת חשבון המקור מהתוצאות. הפונקציה ARRAY_LENGTH משמשת כדי לגשת אל group variable e.

GRAPH graph_db.FinGraph
MATCH (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account)
WHERE src != dst
RETURN src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length, dst.id AS dst_account_id;

התוצאה אמורה להיראות כך:

src_account_id path_length dst_account_id
7 1 16
7 1 16
7 3 16
7 3 16
7 2 20
7 2 20

חלק מהשורות בתוצאות חוזרות על עצמן. הסיבה לכך היא שיכולים להיות כמה נתיבים שתואמים לתבנית בין אותם צומתי מקור ויעד, והשאילתה מחזירה את כולם.

התאמה לתבנית נתיב עם כמות

השאילתה הבאה מוצאת נתיבים בין צומתי Account עם קשת אחת או שתיים של Transfers דרך חשבונות ביניים חסומים.

תבנית הנתיב בסוגריים מכומתת, והסעיף WHERE שלה מציין תנאים לתבנית החוזרת.

GRAPH graph_db.FinGraph
MATCH
  (src:Account)
  ((a:Account)-[:Transfers]->(b:Account {is_blocked:true}) WHERE a != b){1,2}
    -[:Transfers]->(dst:Account)
RETURN src.id AS src_account_id, dst.id AS dst_account_id;

התוצאה אמורה להיראות כך:

src_account_id dst_account_id
7 20
7 20
20 20

משתני קבוצה

משתנה של תבנית גרף שמוצהר בתבנית מכומתת הופך למשתנה קבוצתי כשניגשים אליו מחוץ לתבנית הזו. לאחר מכן הוא נקשר למערך של רכיבי תרשים תואמים.

אפשר לגשת למשתנה קבוצתי כמערך. רכיבי התרשים נשמרים לפי סדר ההופעה שלהם בנתיבים התואמים. אתם יכולים לצבור משתנה קבוצתי באמצעות צבירה אופקית.

משתנה של קבוצת גישה

בדוגמה הבאה, הגישה למשתנה e מתבצעת באופן הבא:

  • כמשתנה של תבנית גרף שקשור לקצה אחד בסעיף WHERE e.amount > 100 כשהוא נמצא בתוך התבנית הכמותית.
  • כמשתנה קבוצה שקשור למערך של רכיבי קצה ב-ARRAY_LENGTH(e) בהצהרה RETURN כשהוא מחוץ לתבנית הכמותית.
  • כמשתנה קבוצתי שקשור למערך של רכיבי קצה, שנצבר על ידי SUM(e.amount) מחוץ לתבנית הכמותית. זו דוגמה לצבירה אופקית.
GRAPH graph_db.FinGraph
MATCH
  (src:Account {id: 7})-[e:Transfers WHERE e.amount > 100]->{0,2}
  (dst:Account)
WHERE src.id != dst.id
LET total_amount = SUM(e.amount)
RETURN
  src.id AS src_account_id, ARRAY_LENGTH(e) AS path_length,
  total_amount, dst.id AS dst_account_id;

התוצאה אמורה להיראות כך:

src_account_id path_length total_amount dst_account_id
7 1 300 16
7 2 600 20

קידומות לחיפוש נתיבים

כדי להגביל את הנתיבים התואמים בתוך קבוצות שחולקות צומתי מקור ויעד, אפשר להשתמש בקידומת החיפוש של הנתיב ANY,‏ ANY SHORTEST או ANY CHEAPEST. אפשר להחיל את הקידומות האלה רק לפני תבנית נתיב שלמה, ואי אפשר להחיל אותן בתוך סוגריים.

התאמה באמצעות ANY

השאילתה הבאה מוצאת את כל החשבונות הייחודיים שאפשר להגיע אליהם, שנמצאים במרחק של Transfers אחד או שניים מצומת Account נתון.

הקידומת ANY לחיפוש נתיב מבטיחה שהשאילתה תחזיר רק נתיב אחד בין זוג ייחודי של צומתי src ו-dst ב-Account. בדוגמה הבאה, למרות שאפשר להגיע לצומת Account עם {id: 16} בשני נתיבים שונים מצומת המקור Account, השאילתה מחזירה רק נתיב אחד.

GRAPH graph_db.FinGraph
MATCH ANY (src:Account {id: 7})-[e:Transfers]->{1,2}(dst:Account)
LET ids_in_path = ARRAY_CONCAT(ARRAY_AGG(e.Id), [dst.Id])
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ids_in_path;

התוצאה אמורה להיראות כך:

src_account_id dst_account_id ids_in_path
7 16 7,16
7 20 7,16,20

התאמה באמצעות ANY SHORTEST

הקידומת ANY SHORTEST לחיפוש נתיבים מחזירה נתיב אחד לכל זוג של צומתי מקור ויעד, שנבחר מבין אלה עם המספר המינימלי של קצוות.

לדוגמה, השאילתה הבאה מוצאת את אחד הנתיבים הקצרים ביותר בין צומת Account עם ערך id של 7 לבין צומת Account עם ערך id של 20. השאילתה מתייחסת לנתיבים עם קצה אחד עד שלושה קצוות של Transfers.

GRAPH graph_db.FinGraph
MATCH ANY SHORTEST (src:Account {id: 7})-[e:Transfers]->{1, 3}(dst:Account {id: 20})
RETURN src.id AS src_account_id, dst.id AS dst_account_id, ARRAY_LENGTH(e) AS path_length;

התוצאה אמורה להיראות כך:

src_account_id dst_account_id path_length
7 20 2

התאמה באמצעות ANY CHEAPEST

הקידומת ANY CHEAPEST לחיפוש נתיבים מבטיחה שלכל זוג של חשבונות מקור וחשבון יעד, השאילתה תחזיר רק נתיב אחד עם עלות המחשוב הכוללת המינימלית.

השאילתה הבאה מוצאת נתיב עם עלות המחשוב הכוללת המינימלית בין צומתי Account. העלות הזו מבוססת על סכום המאפיין amount של הקצוות Transfers. החיפוש מתייחס לנתיבים עם קצה אחד עד שלושה קצוות של Transfers.

GRAPH graph_db.FinGraph
MATCH ANY CHEAPEST (src:Account)-[e:Transfers COST e.amount]->{1,3}(dst:Account)
LET total_cost = sum(e.amount)
RETURN src.id AS src_account_id, dst.id AS dst_account_id, total_cost;

התוצאה אמורה להיראות כך:

src_account_id dst_account_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

תבניות של תרשימים

תבנית גרף מורכבת מתבנית נתיב אחת או יותר, שמופרדות באמצעות פסיק (,). תבניות גרף יכולות להכיל סעיף WHERE, שמאפשר לגשת לכל משתני תבנית הגרף בתבניות הנתיב כדי ליצור תנאי סינון. כל תבנית נתיב יוצרת אוסף של נתיבים.

התאמה באמצעות תבנית גרף

השאילתה הבאה מזהה חשבונות מתווכים ואת הבעלים שלהם שמעורבים בעסקאות בסכומים של יותר מ-200, שדרכם מועברים כספים מחשבון מקור לחשבון חסום.

תבניות הנתיבים הבאות יוצרות את תבנית התרשים:

  • התבנית הראשונה מוצאת נתיבים שבהם ההעברה מתבצעת מחשבון אחד לחשבון חסום באמצעות חשבון ביניים.
  • התבנית השנייה מוצאת נתיבים מחשבון לאדם שבבעלותו החשבון.

המשתנה interm משמש כקישור משותף בין שתי תבניות הנתיב, ולכן interm צריך להפנות לאותו צומת רכיב בשתי תבניות הנתיב. כך נוצרת פעולת equi-join שמבוססת על המשתנה interm.

GRAPH graph_db.FinGraph
MATCH
  (src:Account)-[t1:Transfers]->(interm:Account)-[t2:Transfers]->(dst:Account),
  (interm)<-[:Owns]-(p:Person)
WHERE dst.is_blocked = TRUE AND t1.amount > 200 AND t2.amount > 200
RETURN
  src.id AS src_account_id, dst.id AS dst_account_id,
  interm.id AS interm_account_id, p.id AS owner_id;

התוצאה אמורה להיראות כך:

src_account_id dst_account_id interm_account_id owner_id
20 16 7 1

הצהרות שאילתה לינאריות

אפשר לשרשר כמה הצהרות גרף כדי ליצור הצהרת שאילתה לינארית. ההצהרות מבוצעות באותו סדר שבו הן מופיעות בשאילתה.

  • כל הצהרה מקבלת את הפלט מההצהרה הקודמת כקלט. הקלט ריק בהצהרה הראשונה.

  • הפלט של ההצהרה האחרונה הוא התוצאה הסופית.

לדוגמה, אפשר להשתמש בהצהרות של שאילתות לינאריות כדי למצוא את ההעברה המקסימלית לחשבון חסום. השאילתה הבאה מאתרת את החשבון ואת הבעלים שלו עם ההעברה הגדולה ביותר לחשבון חסום.

GRAPH graph_db.FinGraph
MATCH (src_account:Account)-[transfer:Transfers]->(dst_account:Account {is_blocked:true})
ORDER BY transfer.amount DESC
LIMIT 1
MATCH (src_account:Account)<-[owns:Owns]-(owner:Person)
RETURN src_account.id AS account_id, owner.name AS owner_name;

בטבלה הבאה מוצג התהליך הזה, עם תוצאות הביניים שמועברות בין כל הצהרה. כדי לקצר, מוצגים רק חלק מהמאפיינים.

תדפיס תוצאת ביניים (מקוצרת)
MATCH
  (src_account:Account)
    -[transfer:Transfers]->
  (dst_account:Account {is_blocked:true})
src_account העברה dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}

ORDER BY transfer.amount DESC
src_account העברה dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}
{id: 20} {amount: 200.0} {id: 16, is_blocked: true}
{id: 7} {amount: 100.0} {id: 16, is_blocked: true}

LIMIT 1
src_account העברה dst_account
{id: 7} {amount: 300.0} {id: 16, is_blocked: true}

MATCH
  (src_account:Account)
    <-[owns:Owns]-
  (owner:Person)
src_account העברה dst_account owns owner
{id: 7} {amount: 300.0} {id: 16, is_blocked: true} {person_id: 1, account_id: 7} {id: 1, name: Alex}
RETURN
  src_account.id AS account_id,
  owner.name AS owner_name
        
account_id owner_name
7 Alex

התוצאה אמורה להיראות כך:

account_id owner_name
7 Alex

פקודת חזרה

ההצהרה RETURN מציינת מה להחזיר מהתבניות התואמות. הוא יכול לגשת למשתנים של תבניות גרפים ולכלול ביטויים וסעיפים אחרים, כמו ORDER BY ו-GROUP BY.

ב-BigQuery Graph אי אפשר להחזיר רכיבי תרשים כתוצאות של שאילתות. כדי להחזיר את כל רכיב התרשים, משתמשים בפונקציה TO_JSON.

החזרת רכיבי תרשים כ-JSON

GRAPH graph_db.FinGraph
MATCH (n:Account {id: 7})
-- Returning a graph element in the final results is NOT allowed. Instead, use
-- the TO_JSON function or explicitly return the graph element's properties.
RETURN TO_JSON(n) AS n;

התוצאה אמורה להיראות כך:

n
{"identifier":"mUZpbkdyYXBoLkFjY291bnQAeJEO","kind":"node","labels":["Account"],"properties":{"create_time":"2020-01-10T14:22:20.222Z","id":7,"is_blocked":false,"nick_name":"Vacation Fund"}}

יצירת שאילתות גדולות יותר באמצעות מילת המפתח NEXT

אפשר לשרשר כמה הצהרות של שאילתות לינאריות של תרשים באמצעות מילת המפתח NEXT. ההצהרה הראשונה מקבלת קלט ריק, והפלט של כל הצהרה עוקבת הופך לקלט של ההצהרה הבאה.

בדוגמה הבאה, כדי למצוא את הבעלים של החשבון עם הכי הרבה העברות נכנסות, משורשרות כמה הצהרות לינאריות של תרשים. אפשר להשתמש באותו משתנה, למשל account, כדי להתייחס לאותו רכיב בתרשים בכמה הצהרות לינאריות.

GRAPH graph_db.FinGraph
MATCH (:Account)-[:Transfers]->(account:Account)
RETURN account, COUNT(*) AS num_incoming_transfers
GROUP BY account
ORDER BY num_incoming_transfers DESC
LIMIT 1

NEXT

MATCH (account:Account)<-[:Owns]-(owner:Person)
RETURN account.id AS account_id, owner.name AS owner_name, num_incoming_transfers;

התוצאה אמורה להיראות כך:

account_id owner_name num_incoming_transfers
16 Lee 3

אפשר גם לשלב הצהרות של שאילתות לינאריות עם אופרטורים של קבוצות.

פונקציות וביטויים

בשאילתות גרפים אפשר להשתמש בכל הפונקציות (פונקציות צבירה ופונקציות סקלריות), האופרטורים והביטויים המותנים של GoogleSQL. ב-BigQuery Graph יש גם תמיכה בפונקציות GQL ובאופרטורים של GQL שאפשר להשתמש בהם רק בשאילתות של תרשימים.

השאילתה הבאה כוללת שילוב של פונקציות ואופרטורים של GQL ו-SQL בתוך שאילתת גרף:

GRAPH graph_db.FinGraph
MATCH (person:Person)-[o:Owns]->(account:Account)
WHERE person IS SOURCE OF o
RETURN person, ARRAY_AGG(account.nick_name) AS accounts
GROUP BY person

NEXT

RETURN
  LABELS(person) AS labels,
  accounts,
  CONCAT(person.city, ", ", person.country) AS location,
  TO_JSON(person) AS person
LIMIT 1;

התוצאה אמורה להיראות כך:

labels חשבונות location אדם
Person ["Vacation Fund"] Adelaide, Australia {"identifier":"mUZpbkdyYXBoLlBlcnNvbgB4kQI=","kind":"node","labels":["Person"],"properties":{"birthday":"1991-12-21T08:00:00Z","city":"Adelaide","country":"Australia","id":1,"name":"Alex"}}

שאילתות משנה

שאילתת משנה היא שאילתה שמוטמעת בתוך שאילתה אחרת. הכללים הבאים חלים על שאילתות משנה בתוך שאילתות תרשים:

  • שאילתת משנה מוקפת בזוג סוגריים מסולסלים {}.
  • שאילתת משנה מתחילה בסעיף GRAPH כדי לציין את התרשים בהיקף. התרשים שצוין לא חייב להיות זהה לתרשים שנעשה בו שימוש בשאילתה החיצונית.
  • אי אפשר להצהיר שוב על משתנה של תבנית גרף שהוצהר מחוץ להיקף של שאילתת המשנה בתוך שאילתת המשנה, אבל אפשר להפנות אליו בביטויים או בפונקציות בתוך שאילתת המשנה.

משתמשים בשאילתת משנה כדי למצוא את המספר הכולל של ההעברות מכל חשבון

השאילתה הבאה ממחישה את השימוש בשאילתת המשנה VALUE. שאילתת המשנה מוקפת בסוגריים מסולסלים {} עם הקידומת של מילת המפתח VALUE. השאילתה מחזירה את המספר הכולל של ההעברות שהתחילו מחשבון.

GRAPH graph_db.FinGraph
MATCH (p:Person)-[:Owns]->(account:Account)
RETURN p.name, account.id AS account_id, VALUE {
  GRAPH graph_db.FinGraph
  MATCH (a:Account)-[transfer:Transfers]->(:Account)
  WHERE a = account
  RETURN COUNT(transfer) AS num_transfers
} AS num_transfers;

התוצאה אמורה להיראות כך:

name account_id num_transfers
Alex 7 2
Dana 20 2
Lee 16 1

רשימה של ביטויי שאילתות משנה נתמכים מופיעה במאמר שאילתות משנה של BigQuery Graph.

פרמטרים של שאילתה

אתם יכולים לשלוח שאילתות ל-BigQuery Graph עם פרמטרים. למידע נוסף, קראו על התחביר ועל הרצת שאילתות עם פרמטרים.

השאילתה הבאה תואמת לצומתי Person שיש להם ערך id שתואם לפרמטר של שאילתה:

GRAPH graph_db.FinGraph
MATCH (person:Person {id: @id})
RETURN person.name;

הרצת שאילתות על תרשימים וטבלאות ביחד

אפשר לשלב שאילתות גרף ושאילתות SQL באמצעות האופרטור GRAPH_TABLE.

האופרטור GRAPH_TABLE מקבל שאילתת גרף לינארי ומחזיר את התוצאה שלה בטבלה שאפשר לשלב בשאילתת SQL. יכולת הפעולה ההדדית הזו מאפשרת להעשיר את תוצאות השאילתות בגרף בתוכן שלא שייך לגרף, ולהפך.

לדוגמה, אפשר ליצור טבלה בשם CreditReports ולהוסיף כמה דוחות אשראי, כמו בדוגמה הבאה:

CREATE TABLE graph_db.CreditReports (
  person_id     INT64 NOT NULL,
  create_time   TIMESTAMP NOT NULL,
  score         INT64 NOT NULL,
  PRIMARY KEY (person_id, create_time) NOT ENFORCED
);
INSERT INTO graph_db.CreditReports (person_id, create_time, score)
VALUES
  (1,"2020-01-10 06:22:20.222", 700),
  (2,"2020-02-10 06:22:20.222", 800),
  (3,"2020-03-10 06:22:20.222", 750);

בשלב הבא, אתם יכולים לזהות אנשים ספציפיים באמצעות התאמת דפוסים בגרף ב-GRAPH_TABLE, ולצרף את תוצאות השאילתה בגרף לטבלה CreditReports כדי לאחזר את דירוגי האשראי.

SELECT
  gt.person.id,
  credit.score AS latest_credit_score
FROM GRAPH_TABLE(
  graph_db.FinGraph
  MATCH (person:Person)-[:Owns]->(:Account)-[:Transfers]->(account:Account {is_blocked:true})
  RETURN DISTINCT person
) AS gt
JOIN graph_db.CreditReports AS credit
  ON gt.person.id = credit.person_id
ORDER BY credit.create_time;

התוצאה אמורה להיראות כך:

person_id latest_credit_score
1 700
2 800

שיטות מומלצות

כדי לשפר את ביצועי השאילתות, אתם יכולים לבנות את שאילתות ה-GQL כך שיצמצמו את כמות הנתונים שנסרקים ואת מספר תוצאות הביניים.

התחלת מעבר בנתיב מצמתים בעלי עוצמה נמוכה

כדי לשמור על קבוצות קטנות של תוצאות ביניים ולהאיץ את ביצוע השאילתות, כדאי לכתוב את שאילתות התרשים כך ש-Path traversal יתחיל מצמתים עם עוצמה נמוכה יותר, בלי קשר לכיוון של ה-Path traversal. בהצהרת ה-MATCH הבאה נעשה שימוש במסנני מאפיינים כדי לצמצם את מספר הצמתים ההתחלתיים האפשריים, במקום לחשב את כל ההתאמות ואז לסנן:

MATCH (p:Person {id: 10})-[own:Owns]->(a:Account)

זה חשוב במיוחד לשאילתות של נתיבים מכומתים:

MATCH (p:Person {id: 10})-[own:Owns]->{1,3}(a:Account)

שימוש במעבר בין נתיבים כיווניים

הסכימות של BigQuery Graph הן כיווניות, כלומר לכל קשת יש צומת מקור וצומת יעד. למרות שתחביר השאילתה של התרשים מאפשר מעבר בנתיב בכל כיוון (לדוגמה, -[edge]-), מומלץ להשתמש במעבר בנתיב כיווני (לדוגמה, -[edge]-> או <-[edge]-) כדי לשפר את הביצועים. מעבר בנתיב בכל כיוון עלול לגרום לפגיעה בביצועים.

ההצהרה הבאה של MATCH משלבת שתי תנועות כיווניות עם UNION ALL:

MATCH (a1:Account {id: 7})-[t:Transfers]->(a2:Account)
...
UNION ALL
...
MATCH (a1:Account  {id: 7})<-[t:Transfers]-(a2:Account)

שימוש בתחביר ANY או ANY SHORTEST לבדיקות קישוריות

שאילתות של נתיבים מכומתים יכולות להחזיר נתיבים כפולים בין צומתי מקור לצומתי יעד. אם המטרה שלכם היא לבדוק את הקישוריות ואתם לא צריכים את כל הנתיבים האפשריים, השתמשו ב-ANY או ב-ANY SHORTEST כדי לצמצם חישובים מיותרים ולשפר את היעילות של חיפוש הנתיבים. לדוגמה, בהצהרת MATCH הבאה נעשה שימוש ב-ANY SHORTEST כדי לשמור רק נתיב אחד בין כל זוג צמתים:

MATCH ANY SHORTEST (a1:Account)-[t:Transfers]->{1,3}(a2:Account)

ציון תוויות באופן מפורש

אם משמיטים תוויות של צמתים או קצוות בשאילתה, BigQuery Graph מונה את כל התוויות של הצמתים והקצוות שעומדות בתנאים. הספירה הזו עלולה לגרום לסריקה של יותר תוויות מהנדרש. כדי למנוע את זה, כדאי לציין תוויות לכל הצמתים והקצוות בשאילתה, כשאפשר.

לדוגמה, בשאילתה הבאה מצוינות התוויות Account ו-Transfers:

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[t:Transfers]->(a2:Account)
RETURN COUNT(*) AS num_transfers;

כדאי להימנע מהשמטת תוויות, כי זה עלול לגרום לסריקה של קשרים אחרים לא נחוצים בין צמתים. בשאילתה הבאה, a1 יכול לייצג חשבון או אדם, ו-t יכול לייצג העברה או בעלות על חשבון.

GRAPH graph_db.FinGraph
MATCH (a1)-[t]->(a2)
RETURN COUNT(*) AS num_transfers;

שימוש בהצהרת MATCH אחת

ב-BigQuery Graph אפשר לכלול כמה הצהרות MATCH בשאילתת תרשים אחת. ההצהרות האלה מקושרות באמצעות משתנים שהוצהרו כמה פעמים ומייצגים את אותו צומת או קצה. עם זאת, שימוש בכמה הצהרות MATCH יכול להפחית את היתרונות של עוצמה בין הצהרות. כדי לשפר את הביצועים, מומלץ להשתמש בהצהרת MATCH אחת.

לדוגמה, השאילתות הבאות זהות, אבל הראשונה פועלת טוב יותר כי היא משתמשת בהצהרת MATCH אחת:

-- Preferred syntax.
GRAPH graph_db.FinGraph
MATCH
  (p:Person {id: 1})-[o:Owns]->
  (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
-- Avoid this syntax.
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})-[o:Owns]->(a:Account)
MATCH (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;

הגבלת הקצוות שעוברים דרך צמתים עם עוצמה גבוהה

כששולחים שאילתות לתרשימים, יכול להיות שלצמתים מסוימים יהיה מספר גדול משמעותית של קצוות נכנסים או יוצאים בהשוואה לצמתים אחרים. הצמתים האלה עם עוצמה גבוהה נקראים לפעמים צומתי-על או צומתי רכזת. צומתי-על יכולים לגרום לבעיות בביצועים, כי מעבר דרכם עשוי לכלול עיבוד של כמויות גדולות של נתונים, מה שמוביל לחלוקת נתונים לא מאוזנת (partition skew) ולזמני ביצוע ארוכים.

כדי לבצע אופטימיזציה של שאילתה בתרשים עם צומתי-על, משתמשים בפונקציה ROW_NUMBER() בתוך משפט FILTER או משפט WHERE ב-MATCH כדי להגביל את מספר הקצוות שהשאילתה עוברת מצומת או אליו. השיטה הזו שימושית במיוחד כשלא צריך פירוט מלא של כל החיבורים מצומת-על או אליו.

לדוגמה, אם בחלק מהחשבונות ב-FinGraph יש מספר גדול של עסקאות, אפשר להשתמש ב-ROW_NUMBER() כדי להגביל את מספר הקצוות של Transfers שצריך להביא בחשבון לכל Account, וכך להימנע משאילתה לא יעילה:

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers WHERE e1 IN {
  GRAPH graph_db.FinGraph
  -- Sample 5 edges per source node
  MATCH -[selected_e:Transfers]->
    FILTER ROW_NUMBER() OVER (
      PARTITION BY SOURCE_NODE_ID(selected_e)) < 5
    RETURN selected_e
}]->{1,3}(a2:Account)
RETURN COUNT(*) AS cnt;

דגימת צמתים או קצוות ביניים בשאילתות עם כמה דילוגים

כדי לשפר את יעילות השאילתות, אפשר להשתמש ב-ROW_NUMBER() כדי לדגום צמתים ביניים בשאילתות עם כמה דילוגים. השיטה הזו מגבילה את מספר הנתיבים שהשאילתה בוחנת לכל צומת ביניים. כדי לעשות את זה, צריך לפצל שאילתה עם כמה דילוגים לכמה הצהרות MATCH שמופרדות באמצעות NEXT, ולהחיל את ROW_NUMBER() בנקודת האמצע שבה רוצים לדגום:

GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers]->(a2:Account)
-- Sample 5 destination nodes per a1 source node
FILTER ROW_NUMBER() OVER (PARTITION BY ELEMENT_ID(a1)) < 5
RETURN a1, a2
NEXT
MATCH (a2)-[e2:Transfers]->(a3:Account)
RETURN a1.id AS src_id, a2.id AS mid_id, a3.id AS dst_id;

המאמרים הבאים