שימוש ב-ETL הפוך כדי לטעון נתונים מ-BigQuery ל-Spanner Graph

במאמר הזה מוסבר איך להשתמש בצינורות להעברת נתונים הפוכה של ETL (חילוץ, טרנספורמציה וטעינה) כדי להעביר נתונים של גרפים מ-BigQuery ל-Spanner Graph ולסנכרן אותם באופן רציף. הוא כולל את ההיבטים העיקריים הבאים:

כדי להשתמש ב-ETL הפוך לייצוא נתונים מ-BigQuery ל-Spanner, אפשר לעיין במאמר ייצוא נתונים ל-Spanner.

‫BigQuery מבצע מניפולציות מורכבות של נתונים בקנה מידה גדול כפלטפורמה לעיבוד אנליטי, בעוד ש-Spanner מותאם לתרחישי שימוש שדורשים QPS גבוה וחביון נמוך של הצגת נתונים. ‫Spanner Graph ו-BigQuery משתלבים בצורה יעילה כדי להכין נתוני גרף בצינורות ניתוח נתונים של BigQuery, וכך מאפשרים ל-Spanner להציג מעברים בגרף עם השהיה נמוכה.

לפני שמתחילים

  1. יוצרים מכונה של Spanner עם מסד נתונים שמכיל נתוני גרפים. מידע נוסף זמין במאמר הגדרה של Spanner Graph ושליחת שאילתות.

  2. ב-BigQuery, יוצרים מקום שמור (slot) ברמה Enterprise או Enterprise Plus. כדי להפחית את עלויות החישוב ב-BigQuery, אפשר להריץ ייצוא ל-Spanner Graph. כדי לעשות זאת, מגדירים קיבולת בסיסית של אפס יחידות קיבולת ומפעילים התאמה אוטומטית לעומס.

  3. צריך להקצות תפקידים בניהול הזהויות והרשאות הגישה (IAM) שנותנים למשתמשים את ההרשאות הנדרשות לביצוע כל משימה שמופיעה במאמר הזה.

התפקידים הנדרשים

כדי לקבל את ההרשאות שנדרשות לייצוא נתוני גרף של BigQuery אל Spanner Graph, צריך לבקש מהאדמין להקצות לכם בפרויקט את תפקידי ה-IAM הבאים:

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

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

תרחישים לדוגמה של העברת נתונים הפוכה של ETL

הנה כמה תרחישים לדוגמה: אחרי שמנתחים ומעבדים נתונים ב-BigQuery, אפשר להעביר את הנתונים ל-Spanner Graph באמצעות ETL הפוך.

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

טרנספורמציה של נתונים והעשרה שלהם – אפשר להשתמש ב-BigQuery כדי לנקות ולתקנן נתונים שמתקבלים ממקורות נתונים שונים.

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

עיבוד מקדים של פיצ'רים והנדסת פיצ'רים – ב-BigQuery, משתמשים בפונקציה ML.TRANSFORM כדי לבצע טרנספורמציה של נתונים, או בפונקציה ML.FEATURE_CROSS כדי ליצור שילובי פיצ'רים של פיצ'רים של קלט. לאחר מכן, משתמשים ב-ETL הפוך כדי להעביר את הנתונים שמתקבלים אל Spanner Graph.

הסבר על צינור ה-ETL ההפוך

הנתונים מועברים מ-BigQuery ל-Spanner Graph בצינור ETL הפוך בשני שלבים:

  1. ‫BigQuery משתמש במשבצות זמן שהוקצו למשימת צינור הנתונים כדי לחלץ ולשנות את נתוני המקור.

  2. צינור ה-ETL ההפוך של BigQuery משתמש בממשקי API של Spanner כדי לטעון נתונים למופע Spanner שהוקצה.

בתרשים הבא מוצגים השלבים בצינור עיבוד נתונים של ETL הפוך:

דיאגרמה שמציגה את שלושת השלבים העיקריים כשנתונים מועברים מ-BigQuery ל-Spanner Graph בפייפליין של ETL הפוך.

איור 1. תהליך צינור ה-ETL ההפוך ב-BigQuery

ניהול שינויים בנתוני הגרף

אפשר להשתמש ב-ETL הפוך כדי:

  • טעינת מערך נתונים של גרף מ-BigQuery אל Spanner Graph.

  • סנכרון נתוני Spanner Graph עם עדכונים שוטפים ממערך נתונים ב-BigQuery.

מגדירים צינור עיבוד נתונים של reverse ETL עם שאילתת SQL כדי לציין את נתוני המקור ואת השינוי שרוצים להחיל. צינור הנתונים טוען את כל הנתונים שעומדים בתנאי של סעיף WHERE בהצהרת SELECT ל-Spanner באמצעות פעולת upsert. פעולת upsert שוות ערך להצהרות INSERT OR UPDATE. הוא מוסיף שורות חדשות ומעדכן שורות קיימות בטבלאות שמאחסנות נתוני גרף. הצינור מתבסס על מפתח ראשי של טבלת Spanner כדי ליצור שורות חדשות ולעדכן שורות קיימות.

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

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

סכימת טבלת הקלט של הגרף בדוגמה הבאה משתמשת בטבלה משולבת ובאילוץ של מפתח זר כדי ליצור מודל של הקשר בין אדם לבין החשבונות שלו:

CREATE TABLE Person (
  id    INT64 NOT NULL,
  name  STRING(MAX)
) PRIMARY KEY (id);

CREATE TABLE Account (
  id           INT64 NOT NULL,
  create_time  TIMESTAMP,
  is_blocked   BOOL,
  type        STRING(MAX)
) PRIMARY KEY (id);

CREATE TABLE PersonOwnAccount (
  id           INT64 NOT NULL,
  account_id   INT64 NOT NULL,
  create_time  TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id)
) PRIMARY KEY (id, account_id),
  INTERLEAVE IN PARENT Person ON DELETE CASCADE;

CREATE PROPERTY GRAPH FinGraph
  NODE TABLES (
    Person,
    Account
  )
  EDGE TABLES (
    PersonOwnAccount
      SOURCE KEY (id) REFERENCES Person
      DESTINATION KEY (account_id) REFERENCES Account
      LABEL Owns
  );

בסכימה לדוגמה הזו, PersonOwnAccount היא טבלה משולבת ב-Person. טוענים את הרכיבים בטבלה Person לפני הרכיבים בטבלה PersonOwnAccount. בנוסף, אילוץ המפתח הזר ב-PersonOwnAccount מבטיח שקיים שורה תואמת ב-Account, היעד של קשר הקצה. לכן, צריך לטעון את הטבלה Account לפני הטבלה PersonOwnAccount. הרשימה הבאה מסכמת את התלות בסדר הטעינה של הסכימה הזו:

כדי לטעון את הנתונים:

  1. טעינה של Person לפני PersonOwnAccount.
  2. טעינה של Account לפני PersonOwnAccount.

‫Spanner אוכף את אילוצי השלמות הרפרנציאלית בסכימה לדוגמה. אם צינור העיבוד מנסה ליצור שורה בטבלה PersonOwnAccount בלי שורה תואמת בטבלה Person או בטבלה Account, ‏ Spanner מחזיר שגיאה. הפייפליין נכשל.

בצינור הזה של ETL הפוך נעשה שימוש בהצהרות EXPORTDATA ב-BigQuery כדי לייצא נתונים מהטבלאות Person,‏ Account ו-PersonOwnAccount במערך נתונים, כדי לעמוד בתלות של סדר הטעינה:

BEGIN
EXPORT DATA OPTIONS (
    uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
    format='CLOUD_SPANNER',
    spanner_options="""{
      "table": "Person",
      "priority": "LOW",
      "tag" : "graph_data_load_person"
    }"""
  ) AS
  SELECT
    id,
    name
  FROM
    DATASET_NAME.Person;

EXPORT DATA OPTIONS (
  uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
  format='CLOUD_SPANNER',
  spanner_options="""{
    "table": "Account",
    "priority": "LOW",
    "tag" : "graph_data_load_account"
  }"""
) AS
SELECT
  id,
  create_time,
  is_blocked,
  type
FROM
  DATASET_NAME.Account;

EXPORT DATA OPTIONS (
  uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
  format='CLOUD_SPANNER',
  spanner_options="""{
    "table": "PersonOwnAccount",
    "priority": "LOW",
    "tag" : "graph_data_load_person_own_account"
  }"""
) AS
SELECT
  id,
  account_id,
  create_time
FROM
  DATASET_NAME.PersonOwnAccount;
END;

סנכרון נתונים

כדי לסנכרן את BigQuery עם Spanner Graph, משתמשים בצינורות ETL הפוכים. אתם יכולים להגדיר את צינור הנתונים כך שיבצע אחת מהפעולות הבאות:

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

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

אילוצים של שלמות רפרנציאלית

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

תהליך ה-Reverse ETL מקבץ באופן אוטומטי את הנתונים למנות שלא חורגות מהמגבלה המקסימלית של שינויים לכל פעולת Commit, ומחיל את המנות על טבלת Spanner בסדר שרירותי. אם אצווה מכילה נתונים שנכשלים בבדיקת שלמות רפרנציאלית, Spanner לא טוען את האצווה הזו. דוגמאות לכשלים כאלה כוללות שורת צאצא שמשולבת בשורות אחרות וחסרה לה שורת הורה, או עמודה של מפתח זר שנאכף ואין בה ערך תואם בעמודה שאליה היא מפנה. אם אצווה נכשלת בבדיקה, הצינור נכשל עם שגיאה, והצינור מפסיק לטעון אצוות.

הסבר על שגיאות של אילוצי תקינות רפרנציאלית

בדוגמאות הבאות מוצגות שגיאות של אילוץ שלמות רפרנציאלית שאולי תיתקלו בהן:

פתרון שגיאות של אילוץ מפתח זר
  • שגיאה: "ההגבלה של מפתח זר FK_Account הופרה בטבלה PersonOwnAccount. לא ניתן למצוא את הערכים שהופנו אליהם ב-Account(id)"

  • הסיבה: הוספת שורה לטבלה PersonOwnAccount נכשלה כי חסרה שורה תואמת בטבלה Account, שנדרשת על ידי המפתח הזר FK_Account.

פתרון שגיאות שקשורות לשורת הורה חסרה
  • שגיאה: "חסרה שורת האב של שורה [15,1] בטבלה PersonOwnAccount"

  • הסיבה: הוספת שורה ל-PersonOwnAccount (id: 15 ו-account_id: 1) נכשלה כי חסרה שורת אב בטבלה Person (id: 15).

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

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

הסרת מגבלות על שלמות רפרנציאלית

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

  • אתם יכולים ליצור טבלאות משולבות עם פסקה INTERLEAVE IN כדי להשתמש באותן מאפיינים של שילוב שורות פיזי. אם משתמשים ב-INTERLEAVE IN במקום ב-INTERLEAVE IN PARENT, מערכת Spanner לא אוכפת את שלמות ההפניה, אבל השאילתות נהנות ממיקום משותף של טבלאות קשורות.

  • אפשר ליצור מפתחות זרים אינפורמטיביים באמצעות האפשרות NOT ENFORCED. האפשרות NOT ENFORCED מספקת יתרונות של אופטימיזציה של שאילתות. עם זאת, Spanner לא אוכף את השלמות ההפניה.

לדוגמה, כדי ליצור את טבלת הקלט של הקצה בלי בדיקות שלמות רפרנציאלית, אפשר להשתמש ב-DDL הזה:

CREATE TABLE PersonOwnAccount (
  id          INT64 NOT NULL,
  account_id  INT64 NOT NULL,
  create_time TIMESTAMP,
  CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id) NOT ENFORCED
) PRIMARY KEY (id, account_id),
INTERLEAVE IN Person;

שמירה על תקינות הנתונים בצינורות ETL הפוכים

כדי לוודא שצינור הנתונים טוען רק שורות שעומדות בבדיקות שלמות ההפניה, צריך לכלול רק שורות PersonOwnAccount שיש להן שורות תואמות בטבלאות Person ו-Account. לאחר מכן, שומרים על סדר הטעינה, כך ש-Spanner טוען את השורות Person ו-Account לפני השורות PersonOwnAccount שמתייחסות אליהן.

EXPORT DATA OPTIONS (
  uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
  format='CLOUD_SPANNER',
    spanner_options="""{
      "table": "PersonOwnAccount",
      "priority": "LOW",
      "tag" : "graph_data_load_person_own_account"
    }"""
  ) AS
  SELECT
    poa.id,
    poa.account_id,
    poa.create_time
  FROM `PROJECT_ID.DATASET_NAME.PersonOwnAccount` poa
    JOIN `PROJECT_ID.DATASET_NAME.Person` p ON (poa.id = p.id)
    JOIN `PROJECT_ID.DATASET_NAME.Account` a ON (poa.account_id = a.id)
  WHERE poa.id = p.id
    AND poa.account_id = a.id;

מחיקת רכיבים בתרשים

צינורות להעברת נתונים הפוכה של ETL משתמשים בפעולות upsert. מכיוון שפעולות upsert שוות להצהרות INSERT OR UPDATE, צינור יכול לסנכרן רק שורות שקיימות בנתוני המקור בזמן הריצה. כלומר, הצינור לא כולל שורות שנמחקו. אם מוחקים נתונים מ-BigQuery, צינור reverse ETL לא יכול להסיר ישירות את אותם נתונים מ-Spanner Graph.

אפשר להשתמש באחת מהאפשרויות הבאות כדי לטפל במחיקות מטבלאות מקור ב-BigQuery:

ביצוע מחיקה לוגית או מחיקה רכה במקור

כדי לסמן שורות למחיקה באופן לוגי, משתמשים בדגל deleted ב-BigQuery. לאחר מכן יוצרים עמודה בטבלת Spanner של היעד שאליה אפשר להעביר את הדגל. כש-ETL הפוך מחיל את העדכונים של צינור הנתונים, הוא מוחק שורות עם הדגל הזה ב-Spanner. אפשר למצוא ולמחוק שורות כאלה באופן מפורש באמצעות partitioned DML. לחלופין, אפשר למחוק שורות באופן מרומז על ידי הגדרת עמודה של TTL (אורך חיים) עם תאריך שתלוי בעמודת דגל המחיקה. כדי להחריג את השורות שנמחקו לוגית, כותבים שאילתות Spanner. כך תוכלו לוודא ש-Spanner יחריג את השורות האלה מהתוצאות לפני המחיקה המתוזמנת. אחרי שצינור ה-ETL ההפוך פועל עד הסוף, המחיקות הלוגיות משתקפות בשורות ב-Spanner. לאחר מכן תוכלו למחוק שורות מ-BigQuery.

בדוגמה הזו, מוסיפים עמודה is_deleted לטבלה PersonOwnAccount ב-Spanner. לאחר מכן, היא מוסיפה עמודה expired_ts_generated שתלויה בערך is_deleted. התאריך בעמודה שנוצרה מוקדם יותר מערך הסף DELETION POLICY, ולכן השורות שמושפעות ממדיניות ה-TTL מתוזמנות למחיקה.

ALTER TABLE PersonOwnAccount
  ADD COLUMN is_deleted BOOL DEFAULT (FALSE);

ALTER TABLE PersonOwnAccount ADD COLUMN
  expired_ts_generated TIMESTAMP AS (IF(is_deleted,
    TIMESTAMP("1970-01-01 00:00:00+00"),
    TIMESTAMP("9999-01-01 00:00:00+00"))) STORED HIDDEN;

ALTER TABLE PersonOwnAccount
  ADD ROW DELETION POLICY (OLDER_THAN(expired_ts_generated, INTERVAL 0 DAY));

שימוש בהיסטוריית השינויים ב-BigQuery לפעולות INSERT, ‏ UPDATE ומחיקות לוגיות

אפשר לעקוב אחרי שינויים בטבלה ב-BigQuery באמצעות היסטוריית השינויים שלה. אפשר להשתמש בפונקציה CHANGES של GoogleSQL כדי למצוא שורות שהשתנו במרווח זמן מסוים. לאחר מכן, משתמשים בפרטים של השורה שנמחקה עם צינור עיבוד נתונים הפוך של ETL. אפשר להגדיר את צינור העיבוד כך שיגדיר אינדיקטור, כמו דגל מחיקה או תאריך תפוגה, בטבלת Spanner. האינדיקטור הזה מסמן שורות למחיקה בטבלאות של Spanner.

אפשר להשתמש בתוצאות של פונקציית הסדרות העיתיות CHANGES כדי להחליט אילו שורות מטבלת המקור לכלול בהעלאה של צינור ה-ETL ההפוך.

הצינור כולל שורות עם _CHANGE_TYPE כ-INSERT או UPDATE כ-upserts אם השורה קיימת בטבלת המקור. השורה הנוכחית מטבלת המקור מספקת את הנתונים העדכניים ביותר.

משתמשים בשורות עם _CHANGE_TYPE בתור DELETE שלא כוללות שורות קיימות בטבלת המקור כדי להגדיר אינדיקטור בטבלת Spanner, כמו דגל של שורה שנמחקה או תאריך תפוגה של שורה.

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

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

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

בדוגמה הבאה אפשר לראות איך מוסיפים עמודה לאחסון תאריכי התפוגה של השורות בטבלה.

ALTER TABLE PersonOwnAccount ADD COLUMN expired_ts TIMESTAMP;

ALTER TABLE PersonOwnAccount
  ADD ROW DELETION POLICY (OLDER_THAN(expired_ts, INTERVAL 1 DAY));

כדי להשתמש בפונקציה CHANGES בטבלה ב-BigQuery, צריך להגדיר את האפשרות enable_change_history של הטבלה לערך TRUE:

ALTER TABLE `PROJECT_ID.DATASET_NAME.PersonOwnAccount`
  SET OPTIONS (enable_change_history=TRUE);

בדוגמה הבאה אפשר לראות איך משתמשים ב-ETL הפוך כדי לעדכן שורות חדשות או שורות ששונו, וכדי להגדיר את תאריך התפוגה של שורות שמסומנות למחיקה. ביצוע של left join עם הטבלה PersonOwnAccount מספק לשאילתה מידע על הסטטוס הנוכחי של כל שורה.

EXPORT DATA OPTIONS (
  uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
    format='CLOUD_SPANNER',
    spanner_options="""{
      "table": "PersonOwnAccount",
      "priority": "LOW",
      "tag" : "graph_data_delete_via_reverse_etl"
    }"""
  ) AS
SELECT
  DISTINCT
   IF (changes._CHANGE_TYPE = 'DELETE', changes.id, poa.id) AS id,
   IF (changes._CHANGE_TYPE = 'DELETE', changes.account_id, poa.account_id) AS account_id,
   IF (changes._CHANGE_TYPE = 'DELETE', changes.create_time, poa.create_time) AS create_time,
   IF (changes._CHANGE_TYPE = 'DELETE', changes._CHANGE_TIMESTAMP, NULL) AS expired_ts
FROM
  CHANGES(TABLE `PROJECT_ID.DATASET_NAME.PersonOwnAccount`,
    TIMESTAMP_TRUNC(TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY), DAY),
    TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), DAY)) changes
LEFT JOIN `PROJECT_ID.DATASET_NAME.PersonOwnAccount` poa
  ON (poa.id = changes.id
  AND poa.account_id = changes.account_id)
WHERE (changes._CHANGE_TYPE = 'DELETE'
   AND poa.id IS NULL)
   OR (changes._CHANGE_TYPE IN ( 'UPDATE', 'INSERT')
   AND poa.id IS NOT NULL );

השאילתה לדוגמה משתמשת ב-LEFT JOIN עם טבלת המקור כדי לשמור על הסדר. הצירוף הזה מבטיח שרשומות השינויים של DELETE יתעלמו משורות שנמחקו ואז נוצרו מחדש בתוך מרווח הזמן של היסטוריית השינויים של השאילתה. הצינור שומר את השורה החדשה התקינה.

כשמוחקים שורות, צינור הנתונים מאכלס את העמודה expired_ts בשורה המתאימה בגרף Spanner באמצעות חותמת הזמן DELETE מהעמודה _CHANGE_TIMESTAMP. מדיניות מחיקת שורות (מדיניות TTL) ב-Spanner מוחקת כל שורה שבה הערך של expired_ts הוא יותר מיום אחד בעבר.

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

בדוגמה הזו מוצג המרווח start_timestamp ו-end_timestamp של שאילתות יומיות שמתעדות את כל השינויים בטבלת BigQuery מהיום הקודם לפי UTC. מכיוון שמדובר בשאילתת אצווה ולפונקציה CHANGES יש מגבלות, הערך של end_timestamp צריך להיות לפחות 10 דקות לפני השעה הנוכחית. לכן, מומלץ לתזמן את השאילתה הזו כך שתפעל לפחות 10 דקות אחרי חצות לפי שעון UTC. פרטים נוספים זמינים במסמכי התיעוד של CHANGES.

שימוש בעמודות TTL עם חותמת זמן של הפעם האחרונה שהמשתמש נראה

בצינור reverse ETL, העמודה last_seen_ts מוגדרת לחותמת הזמן הנוכחית עבור כל שורה בטבלת Spanner. כשמוחקים שורות ב-BigQuery, המערכת לא מעדכנת את השורות התואמות ב-Spanner, והעמודה last_seen_ts לא משתנה. לאחר מכן, מערכת Spanner מסירה שורות עם last_seen_ts לא עדכני באמצעות מדיניות TTL או DML עם חלוקה למחיצות, על סמך סף מוגדר. לפני המחיקה המתוזמנת, שאילתות Spanner יכולות לסנן שורות עם last_seen_ts שגדול מהסף הזה. הגישה הזו יעילה במקרים שבהם נתוני הגרף מתעדכנים באופן שוטף, ועדכונים חסרים מצביעים על נתונים לא עדכניים שצריך למחוק.

ביצוע רענון מלא

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

תחזוקה של צינור עיבוד נתונים של ETL הפוך באצווה מתוזמנת

אחרי ההרצה הראשונית של צינור ה-ETL ההפוך, נתונים נטענים מ-BigQuery ל-Spanner Graph בכמות גדולה, ונתונים מהעולם האמיתי ממשיכים להשתנות. מערכי הנתונים משתנים, וצינור הנתונים מוסיף או מסיר רכיבי תרשים לאורך זמן. הצינור מגלה צמתים חדשים ומוסיף קשרים חדשים בין קצוות, או שהסקת מסקנות מ-AI יוצרת אותם.

כדי לוודא שמסד הנתונים של Spanner Graph יישאר עדכני, קובעים תזמון ורצף לתזמור פייפליינים של BigQuery באמצעות אחת מהאפשרויות הבאות:

BigQuery Pipelines מאפשר לכם לפתח, לבדוק, לשלוט בגרסאות ולפרוס תהליכי עבודה מורכבים של טרנספורמציה של נתוני SQL ב-BigQuery. הוא מטפל באופן מובנה בתלות בין הזמנות על ידי הגדרת קשרים בין השאילתות בצינור. ‫Dataform בונה עץ תלות ומריץ את השאילתות בסדר הנכון. כך מוודאים שהתלות במעלה הזרם הושלמה לפני שהמשימות במורד הזרם מתחילות.

Workflows שמופעלים על ידי Cloud Scheduler מספקים פתרון שימושי וגמיש לניהול רצפים של שירותיGoogle Cloud , כולל שאילתות BigQuery. הגדרת תהליך עבודה כסדרה של שלבים, שכל אחד מהם מריץ משימה ב-BigQuery. אפשר להשתמש ב-Cloud Scheduler כדי להפעיל את תהליכי העבודה האלה לפי לוח זמנים מוגדר. אפשר לנהל תלויות באמצעות הגדרת תהליך העבודה כדי לציין את סדר הביצוע, להטמיע לוגיקה מותנית, לטפל בשגיאות ולהעביר פלטים משאילתה אחת לשאילתה אחרת.

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

תהליך ETL הפוך עם שאילתות רציפות ב-BigQuery

התכונה BigQuery continuous queries מאפשרת להריץ פעולות ב-BigQuery כמעט בזמן אמת. שילוב של EXPORT DATA עם שאילתות רציפות מספק שיטה חלופית להפעלת צינורות ETL הפוך, שמונעת משימות אצווה מתוזמנות.

שאילתה מתמשכת היא שאילתה שפועלת לאורך זמן ומנטרת טבלה ב-BigQuery כדי לזהות שורות חדשות. כש-BigQuery מזהה שורות חדשות שנוספו לטבלה, הוא מעביר את תוצאות השאילתה ל-operation‏ EXPORT DATA.

לגישה הזו יש כמה יתרונות:

  • סנכרון נתונים כמעט בזמן אמת: שורות חדשות ב-BigQuery משתקפות ב-Spanner עם עיכוב מינימלי.

  • צמצום התקורה של עיבוד ברצף (batch processing): שאילתה מתמשכת מבטלת את הצורך במשימות באצווה תקופתיות, וכך מצמצמת את התקורה של החישוב.

  • עדכונים מבוססי-אירועים: עדכוני נתונים ב-Spanner בתגובה לשינויים בפועל ב-BigQuery.

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

יצירת שאילתה מתמשכת עם העברת נתונים הפוכה של ETL מ-BigQuery ל-Spanner

מגדירים את הפרמטר start_timestamp של הפונקציה APPENDS כדי להתחיל לעבד את הנתונים מהמקום שבו טעינת האצווה הסתיימה. הפונקציה הזו מתעדת את כל השורות שנוצרו בחלון הזמן הספציפי. בדוגמה הבאה, צינור הנתונים (pipeline) קובע באופן שרירותי את נקודת ההתחלה כ-10 דקות לפני CURRENT_TIME. חותמת הזמן הזו צריכה להיות בטווח של חלון הנסיעה בזמן ב-BigQuery.

יש כמה שיטות להפעלת פייפליין של שאילתות מתמשכות, כולל:

  1. ב-BigQuery Studio, לוחצים על עוד ובוחרים באפשרות שאילתה מתמשכת בקטע בחירת מצב שאילתה.

  2. משתמשים ב-CLI של bq ומספקים את האפשרות --continuous=true.

EXPORT DATA OPTIONS ( uri="https://spanner.googleapis.com/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID",
  format="CLOUD_SPANNER",
  spanner_options="""{
      "table": "PersonOwnAccount",
      "priority": "LOW",
      "tag": "reverse-etl-continuous",
      "change_timestamp_column": "create_time"
   }"""
)
AS SELECT id, account_id, _CHANGE_TIMESTAMP as create_time
  FROM
APPENDS(TABLE `PROJECT_ID.DATASET_NAME.PersonOwnAccount`,
  CURRENT_TIMESTAMP() - INTERVAL 10 MINUTE )

אין ערובה לסדר הטעינה

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

אינטגרציה עם צינורות עיבוד נתונים קיימים

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

שימוש בשאילתה מתמשכת של BigQuery כדי ליצור פייפליינים רספונסיביים ועדכניים של ETL הפוך לסנכרון נתונים בין BigQuery לבין Spanner Graph.

שיקולים לגבי שאילתות מתמשכות

  • עלות: שאילתות רציפות כרוכות בעלויות של הרצת שאילתות שוטפת ושל הזרמת נתונים.

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

  • מחיקות ועדכונים לא מטופלים: הפונקציה APPENDS מתעדת רק הוספות. הוא לא מתעד מחיקות או עדכונים.

שימוש בשיטות המומלצות ל-ETL הפוך

כדי לקבל את התוצאות הכי טובות, כדאי לפעול לפי ההנחיות הבאות.

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

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

  • פועלים לפי ההמלצות לאופטימיזציה של ייצוא ב-Spanner.

  • אם אתם טוענים כמות גדולה של נתונים, כדאי לחלק את צינור הנתונים לכמה צינורות קטנים יותר כדי לא לחרוג ממכסת הזמן שמוגדרת כברירת מחדל לביצוע שאילתות ב-BigQuery (שש שעות). מידע נוסף זמין במאמר מגבלות על עבודות של שאילתות ב-BigQuery.

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

  • הפעלת התאמה אוטומטית לעומס ב-Spanner כדי לקצר את זמני טעינת הנתונים למופע. מידע נוסף זמין במאמרים סקירה כללית של שינוי גודל אוטומטי ב-Spanner, הגדרת ייצוא באמצעות האפשרות spanner_options וRequestOptions.priority.

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

  • מגדירים את עדיפות הבקשה ב-Spanner לטעינת הנתונים בהגדרת הצינור.

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