Pipelines לוולידציית נתונים: ארכיטקטורה לבדיקת דאטה אוטומטית בכל שכבה
מאת צוות מדיה דיל · 02.08.2026 · Data Engineering · 13 דק׳
מדריך מעמיק לבניית pipelines לוולידציית נתונים: Great Expectations מול dbt tests, contract-based validation, fail-fast מול quarantine, ואיך בונים שכבת בדיקה שלא הופכת לצוואר בקבוק.
הבדל מהותי אחד מפריד בין pipeline נתונים בוגר לבין pipeline שרץ 'על תקווה': קיומה, או היעדרה, של שכבת וולידציה שיטתית. וולידציה בהקשר הזה היא לא בדיקה חד-פעמית שמישהו מריץ ידנית — היא קוד שרץ אוטומטית כחלק אינטגרלי מכל ריצת pipeline, בודק שהנתונים תואמים ציפיות מוגדרות מראש, ועוצר או מתריע לפני שדאטה פגום מתקדם הלאה במערכת. השאלה המרכזית בבניית pipeline כזה היא לא 'האם לבדוק' אלא 'איפה בדיוק לבדוק, מה בדיוק לבדוק, ומה קורה כשבדיקה נכשלת' — ושלוש השאלות האלה הן בעצם כל הארכיטקטורה.
הבעיה: נתונים פגומים שמתקדמים בשקט
בלי שכבת וולידציה, pipeline נתונים הוא צינור עיוור: מה שנכנס בצד אחד יוצא בצד השני, לא משנה כמה פגום הוא. תרחיש נפוץ: API חיצוני משנה את פורמט השדה created_at משניות ל-מילישניות בלי הודעה מוקדמת, וכל חישוב שמבוסס על ההפרש בין שני תאריכים מתחיל להחזיר ערכים שגויים פי אלף — בלי שגיאה, בלי קריסה, רק מספרים שגויים בשקט מוחלט. וולידציה שיטתית תופסת בדיוק את הסוג הזה של בעיה, לפני שהוא מגיע לדוח שמישהו מקבל החלטה על סמכו. הנזק האמיתי לא נמדד רק במספר השגוי עצמו, אלא בזמן שלוקח לגלות אותו — לעיתים שבועות, ובמהלכם התקבלו כבר עשרות החלטות עסקיות שהתבססו על נתון שגוי, ואין דרך פשוטה לשחזר אילו החלטות בדיוק הושפעו ואיך לתקן אותן בדיעבד.
הארכיטקטורה: שלוש שכבות וולידציה
pipeline וולידציה בוגר בנוי משלוש שכבות, כל אחת עם מטרה שונה. Schema validation — הבדיקה הבסיסית ביותר: האם השדות קיימים, האם הטיפוסים נכונים, האם השם תואם למה שהוגדר. זו בדרך כלל הבדיקה הראשונה שרצה, מיד עם קבלת הנתונים, ולרוב אוטומטית לגמרי דרך schema registry או JSON Schema. Business rule validation — בדיקות שמייצגות לוגיקה עסקית: הזמנה חייבת amount חיובי, תאריך סיום לא יכול להיות לפני תאריך התחלה, סכום המע"מ חייב להיות אחוז מסוים מהסכום הכולל. אלה כללים שמישהו בעל ידע עסקי הגדיר, ולא ניתנים לגזירה אוטומטית משום schema, ולכן חייבים תיעוד ברור ובעלות מפורשת של מי מהצוות העסקי אחראי לעדכן אותם כשהמציאות משתנה. Statistical validation — בדיקות ברמת האגרגט, שבודקות שהתפלגות הנתונים הגיונית ביחס להיסטוריה, כמו אחוז ה-nulls בעמודה או ממוצע הערך היומי, ותופסות אנומליות שלא נראות בבדיקת שורה בודדת. שלוש השכבות האלה בדרך כלל רצות ברצף, כאשר כל שכבה מהווה שער שצריך לעבור לפני שהנתונים ממשיכים הלאה לשכבה הבאה, כך שכשל בשכבת ה-schema לא בכלל מגיע לבדיקות היקרות והמורכבות יותר של ה-statistical validation.
Great Expectations: framework ייעודי לוולידציה
Great Expectations הוא הכלי הפתוח המוביל לוולידציית נתונים, ומאפשר להגדיר 'ציפיות' (expectations) בקוד Python קריא:
import great_expectations as gx
validator.expect_column_values_to_not_be_null("customer_id")
validator.expect_column_values_to_be_between(
"amount", min_value=0, max_value=100000
)
validator.expect_column_values_to_match_regex(
"email", r"^[^@]+@[^@]+\.[^@]+$"
)
מה שמייחד את Great Expectations הוא שהוא לא רק מריץ בדיקות אלא גם מייצר תיעוד אוטומטי (Data Docs) — עמוד HTML שמראה בדיוק אילו ציפיות מוגדרות על כל dataset ומה התוצאה של הריצה האחרונה, מה שהופך את הוולידציה לשקופה לכל הצוות, לא רק למי שכתב את הקוד, ומאפשר גם לאנשי עסקים לא-טכניים להבין בעצמם מה נבדק ומה התוצאה, בלי לפנות לצוות ההנדסה בכל פעם שיש שאלה על מצב הנתונים.
Fail-fast מול quarantine: מה קורה כשבדיקה נכשלת
יש שתי אסטרטגיות עיקריות לטיפול בכשל וולידציה. Fail-fast — ה-pipeline כולו נעצר מיד כשמתגלה בעיה, ולא מאפשר לשום נתון להתקדם עד שהבעיה מטופלת. זה מבטיח שאף פעם לא ייכנסו נתונים פגומים למערכת, אבל המשמעות היא שגם דוח דחוף יכול להיחסם בגלל שורה בעייתית בודדת. Quarantine — הגישה החלופית: שורות שנכשלות בבדיקה מופרדות לטבלה נפרדת (dead letter table) לבדיקה ידנית מאוחרת, בעוד שאר הנתונים התקינים ממשיכים לזרום כרגיל. הבחירה ביניהן תלויה בחומרת הבעיה — כשל ב-primary key או בטיפוס נתונים בסיסי מצדיק fail-fast, בעוד חריגה סטטיסטית קלה יכולה לעבור ל-quarantine בלי לעצור הכל. יש גם גישת ביניים נפוצה בפועל: partial fail, שבה ה-pipeline ממשיך לרוץ על כל הטבלאות שלא הושפעו מהכשל, ורק המודל הספציפי שנכשל (וכל מה שתלוי בו במורד הזרימה) נעצר — כך אפשר להמשיך לספק ערך לחלק גדול מהארגון גם כשמתגלה בעיה מקומית בטבלה אחת, במקום להשבית את כל ה-pipeline בגלל תקלה שממוקדת בפינה קטנה שלו.
Contract-based validation: הזזת הבדיקה למקור
הגישה המתקדמת ביותר, שהולכת ותופסת תאוצה, היא data contracts — הסכם מפורש בין צוות שמייצר נתונים (למשל צוות backend שכותב לטבלת production) לבין צוות שצורך אותם, שמוגדר כ-schema פורמלי (Avro, Protobuf, JSON Schema) שנאכף כבר בזמן כתיבה, לא רק בזמן קריאה. היתרון: הבעיה נתפסת ברגע שהיא נוצרת, במקום להתגלות שעות מאוחר יותר בקצה ה-pipeline, כשכבר קשה הרבה יותר לאתר את המקור המדויק. dbt תומך כיום ב-model contracts שמאפשרים להצהיר טיפוסים צפויים ברמת המודל, וה-build נכשל מפורשות אם המקור לא תואם. מעבר לתמיכה הטכנית, data contracts דורשים גם שינוי תהליכי: כל שינוי בסכמת המקור צריך לעבור אישור מפורש של הצוות שצורך אותה, בדיוק כמו breaking change ב-API ציבורי — מה שהופך שינויי סכמה מאירוע מפתיע לתהליך מתוכנן עם תקופת מעבר ברורה.
Trade-offs: ביצועים מול כיסוי
וולידציה מקיפה יש לה מחיר ביצועים אמיתי — כל בדיקה נוספת היא query או iteration נוסף על הנתונים. ב-pipeline שרץ בזמן אמת, וולידציה כבדה מדי יכולה להוסיף latency שלא מתקבל על הדעת. הפתרון הפרקטי הוא לדרג בדיקות לפי חומרה ולהריץ רק את הקריטיות ביותר ב-hot path (למשל בזמן אמת), בעוד בדיקות סטטיסטיות מקיפות יותר רצות ב-batch נפרד, לא סינכרוני, שלא חוסם את הזרימה המיידית. שיקול נוסף שקל לפספס הוא עלות ה-compute של הוולידציה עצמה כשעובדים מול cloud warehouse — כל בדיקת Great Expectations או dbt test היא שאילתה בפני עצמה, ועל טבלה של מאות מיליוני שורות, הרצת עשרות בדיקות בכל build יכולה להכפיל את זמן וה-cost של ה-pipeline כולו, ולכן שווה למדוד את עלות הוולידציה בפני עצמה ולא רק את עלות הטרנספורמציה.
טעויות נפוצות
הטעות הראשונה: להגדיר בדיקות פעם אחת ולשכוח לעדכן אותן כשהלוגיקה העסקית משתנה — בדיקה שהייתה נכונה לפני שנה יכולה להיות שגויה היום ולחסום נתונים תקינים לגמרי. הטעות השנייה: להתעלם מבדיקות שנכשלות בעקביות, מה שיוצר 'רעש רגיל' שהצוות מתרגל אליו ומפסיק לשים לב כשבאמת קורה משהו חמור. הטעות השלישית: לבנות וולידציה רק בסוף ה-pipeline, כשכבר קשה מאוד לאתר איפה בדיוק בשרשרת הטרנספורמציות הבעיה נולדה — עדיף תמיד לבדוק כמה שיותר קרוב למקור. הטעות הרביעית, פחות מדוברת אך לא פחות נפוצה: לכתוב בדיקות בלי תיעוד ברור מה בדיוק הן בודקות ולמה — כשמישהו חדש בצוות נתקל בבדיקה שנכשלת בלי הקשר, הוא לא יודע אם מדובר בבאג אמיתי או בכלל שדורש עדכון, ומבזבז זמן יקר על ניחושים במקום על תיקון.
אינטגרציה עם CI/CD: וולידציה לפני deploy, לא רק בפרודקשן
שכבת וולידציה שרצה רק בפרודקשן תופסת בעיות מאוחר מדי — אחרי שהקוד כבר רץ על נתונים אמיתיים. הגישה הבשלה יותר משלבת וולידציה גם בתהליך ה-CI/CD עצמו: כשמפתח פותח pull request עם שינוי במודל dbt, ה-pipeline של CI מריץ את המודל על סביבת staging עם דגימת נתונים, מריץ את כל בדיקות הוולידציה עליו, ורק אם כולן עוברות מאשר merge. זה הופך את הוולידציה מרשת בטיחות תגובתית לשכבת מניעה יזומה — בדיוק כמו טסטים אוטומטיים בהנדסת תוכנה רגילה, שרצים לפני שקוד מגיע לפרודקשן ולא אחריו. צוותים שמטמיעים את זה נכון מדווחים על ירידה דרסטית במספר האירועים שמתגלים רק על ידי משתמשי קצה, כי רוב הבעיות נתפסות כבר בשלב הפיתוח.
מוניטורינג של שכבת הוולידציה עצמה
נקודה שקל לפספס: שכבת הוולידציה עצמה צריכה ניטור. אם job שמריץ בדיקות Great Expectations נכשל בשקט (למשל בגלל תקלת רשת או timeout), הוולידציה פשוט לא רצה, וזה עלול להתפרש בטעות כ'הכל תקין' כשבעצם שום דבר לא נבדק. הפרקטיקה הנכונה היא להבדיל במפורש בין שלוש תוצאות אפשריות: 'הבדיקה רצה ועברה', 'הבדיקה רצה ונכשלה', ו'הבדיקה בכלל לא רצה' — ולהתריע באותה חומרה, אם לא יותר, על המצב השלישי כמו על השני. ארגונים שלא עושים את ההבחנה הזו נופלים לעיתים למלכודת מסוכנת שבה הם חושבים שהם מכוסים, בעוד בפועל שכבת הבדיקה כבר לא פעילה כמה שבועות בגלל תקלה שאיש לא שם לב אליה.
וולידציה חוצת מקורות: כשהבעיה לא בטבלה אחת אלא ביחסים ביניהן
חלק מהבעיות המסוכנות ביותר לא נראות כשבודקים טבלה בודדת בבידוד, אלא רק כשמשווים בין שני מקורות שאמורים להיות עקביים זה עם זה. דוגמה טיפוסית: סכום ההזמנות בטבלת ה-orders אמור להיות שווה לסכום החיובים בטבלת ה-payments, אבל אם יש באג ב-pipeline שמעדכן רק אחת מהן, שתי הטבלאות ימשיכו להיראות 'תקינות' כל אחת בנפרד, בעוד שבפועל הן כבר לא מסונכרנות. בדיקות reconciliation כאלה — השוואת אגרגטים בין שני מקורות עצמאיים — הן קטגוריה נפרדת מהבדיקות הרגילות, ודורשות לרוב job ייעודי שרץ בתדירות נמוכה יותר (למשל פעם ביום) ומשווה במפורש בין המערכות, כדי לתפוס דריפט שמצטבר עם הזמן ואף אחת מהבדיקות הרגילות לא הייתה תופסת.
מתי כן ומתי לא
וולידציה מקיפה מוצדקת כשהדאטה מזין החלטות כספיות, דוחות רגולטוריים, או מודלי ML בפרודקשן. היא פחות קריטית ב-datasets ניסיוניים או פנימיים שנועדו לחקירה חד-פעמית ולא למערכת קבועה. הכלל הפרקטי: להתחיל עם schema validation בסיסי בכל מקום (זול וזה כמעט תמיד משתלם), ולהוסיף business rule, statistical, ו-reconciliation validation רק על ה-datasets שבאמת קריטיים, כדי לא להעמיס על הצוות עלות תחזוקה שלא מצדיקה את עצמה בכל מקום באופן שווה. צוותים קטנים יכולים להתחיל בהיקף מצומצם ולהרחיב בהדרגה ככל שהם לומדים אילו datasets באמת גורמים לכאב כשמשהו משתבש בהם.
סיכום
Pipeline וולידציה טוב הוא לא רשת בטיחות שמופעלת אחרי אירוע — הוא חלק אינטגרלי מהארכיטקטורה שרץ בכל ריצה, בכל שכבה, ומשולב גם בתהליך הפיתוח עצמו דרך CI/CD, ותופס בעיות לפני שהן הופכות לדוח שגוי שמישהו מקבל עליו החלטה. השילוב הנכון של schema, business rule, statistical, ו-reconciliation validation, יחד עם אסטרטגיית טיפול בכשל ברורה וניטור של שכבת הבדיקה עצמה, הוא ההבדל בין pipeline שאפשר לסמוך עליו לבין אחד שצריך לבדוק ידנית כל בוקר, ובעיקר ההבדל בין צוות שמגלה בעיה תוך דקות לבין צוות שמגלה אותה רק כשמנהל שואל למה הדוח לא הגיוני.
תגיות: data validation · Great Expectations · data contracts · schema validation · dbt tests · data pipeline · data quality · quarantine