זה הפוסט הרביעי בסדרה העוסקת במערכות BI של כ"א. הפוסט הקודם עסק במידול המתקדם של הפרויקט בו פירטתי את המבנה הטבלאי של מחסן הנתונים וכיצד ניתן לענות על רוב השאלות תוך שימוש במידול שהצעתי. בפוסט הזה אמשיך ואציג נושא מורכב יותר בעולם הכ"א - תהליכים וניקוי רשומות. אציג את הנושא ואיך מידלתי את מחסן הנתונים באופן כזה שיתמוך בתהליכים ובניקוי רשומות.
אני ממליץ לקרוא את הפוסט הקודם לפני קריאת הפוסט הזה כדי להבין טוב יותר את הדברים. נסכם מה שעשינו בפוסט הקודם: הגענו למסקנה שכדי לענות בצורה יעילה על כל השאלות שנשאלו בנושא כ"א יש לבנות טבלת Fact "רחבה" מאוד (כלומר עם הרבה עמודות) המכילה את כל הנתונים מכל הנגררות הרלוונטיות. הראיתי גם את בעית חוסר הרלוונטיות וכיצד פותרים אותה ע"י הכנסת הערך N/A במקום null במקומות בהן הנגררת עדיין לא התחילה.
בעצם לאחר שעשינו את המתואר סיימנו 90% מהפרויקט. הבעיה היא שהייתה עוד דרישה בסיסית (שהייתה יוזמה ורעיון שלנו ולא של הלקוח) שלא הצגתי בפוסטים הקודמים מהסיבה הפשוטה שלא רציתי לבלבל את הקורא בשלב מוקדם של הסדרה. הדרישה היא לנקות את היומן האישי של האדם מרשומות שאינן רלוונטיות ולזהות תהליכים. אסביר לקורא המבולבל את משמעות הדברים (בשלב זה השימוש בדוגמא של אוניברסיטה קצת פחות רלוונטי ולכן אני מתנצל מראש על הדוגמאות ההזויות):
ניקוי רשומות
לשם הדוגמא, נניח שהמשכורת של המרצה משתנה מספר פעמים במשך החודש אך תמיד בתחילת החודש (לפני שהכסף נכנס לבנק...) המשכורת מתייצבת חזרה. אגב, כבר ראיתי דברים יותר מוזרים במערכות פיננסיות כך שהדוגמא לא לגמרי דמיונית. אם נביא ליומן של המרצה את הנתונים כפי שהם במערכות המקור נקבל מספר בעיות:
- אם במקרה המשתמש יסנן את הדו"ח/שאילתא שלו על התאריך שבו המרצה מקבל את המשכורת הזמנית שלו (זו שלא באמת נכנסת לבנק בסוף החודש), המשתמש יראה כאילו זו המשכורת של המרצה בעוד זו אינה המשכורת ה"אמיתית" שלו ("אמיתית" היא מושג בעייתי ותלוי בנקודת-מבט. אעסוק בזה בהמשך).
- כמות השינויים הגדולה בנגררת שכר של המרצה גורמת ל"ניפוח" גם ביומן האישי של המרצה. נתעלם מהבעיה של נפח הנתונים משום שבדר"כ נפח נתונים אינו בעיה כיום, אך הגידול בכמות הרשומות גורם להרעה בביצועים. יותר מזה - היומן המוצג למשתמש מזובל ואינו מציג בצורה נוחה את המשכורת של המרצה.
- מאידך גיסא, ישנם משתמשים (אנליסטים לרוב) שירצו לתחקר דווקא את הנתונים הבעיתיים הללו, כך שמחסן הנתונים לא יכול פשוט להעלים את הנתונים המקוריים...
זיהוי תהליכיםפעמים רבות קורה בעולם הכ"א שאדם עובר תהליך מהותי בקריירה שלו הגורם למספר שינויים במספר נגררות תוך מספר ימים מועט, אך מבחינה מהותית האדם עבר תהליך אחד. לדוגמא, כאשר מתרגל הופך למרצה הוא משנה את המעמד שלו (סטודנט/מתרגל -> מרצה), את הקורסים שלו (בדר"כ הוא סיים את כל הקורסים שלו ומתחיל ללמד קורסים אחרים) וכמובן את השכר שלו (מן הסתם הוא עולה באופן משמעותי).
אם נסתכל בנגררות שהרגע ציינו, נמצא שלאדם המדובר התווספו רשומות בכל הנגררות ומדובר באותם הימים פלוס-מינוס. למה פלוס-מינוס? כי בהחלט ייתכן שהשינוי בשכר יקרה רק לפני התשלום החודשי, בעוד השינוי במעמד יחול מיידית ברגע המינוי. כלומר, מבחינה טכנית האדם בסה"כ שינה כמה נגררות שלו, אך מבחינה מהותית, מה שנקרא from the business view, האדם עבר תהליך. הדרישה היא שהמערכת תזהה ותציף את השינויים הללו ואף תאפשר תחקור וסינון על פיהם.
בשפה המקצועית הדבר הזה נקרא Super Transaction. אתם מוזמנים לקרוא עוד בנושא אצל
קימבל.
אז איך עושים את כל זה? בייחוד, איך מאפשרים למשתמש גם לראות את הנתונים המקוריים וגם את הנתונים המטוייבים? נענה על כל השאלות לפי סדר הצגתם, אך קודם נציג את המידול באופן כללי:
כללי - מידול
כדי לממש את הדרישות הללו נגדיר את שלושת מצבי העבודה שהמשתמש יכול לראות בכל עת.
- מצב מלא - במצב זה הנתונים זהים לחלוטין לנתונים במערכות המקור. לא מתבצעים סינונים וזיהוי תהליכים.
- מצב מסונן - במצב זה הנתונים מטויבים לפי כללים קבועים מראש (יפורט בהמשך) וכמו-כן מוצגים תהליכים.
- מצב משולב - במצב זה המשתמש רואה הן את הנתונים המקוריים והן את רשומות התהליך ויכול אף לראות אילו רשומות סוננו במהלך הסינונים. מצב זה מאפשר הבנה טובה יותר של תהליך הסינון.
נחזור לחשיבה של מנתח המערכות. אם נסנן את הרשומות בהתאם למצב העבודה שבחר המשתמש, ניתקל בבעיה. כל רשומה יכולה להיות שייכת לכמה מצבי עבודה: רשומה שאיננה נמחקת בתהליך הסינון תהיה שייכת לכל המצבים. רשומה שמסוננת בתהליך הסינון שייכת למצב המסונן ולמצב המשולב. רשומה תהליכית (רשומה המציינת תהליך, יפורט בהמשך) שייכת למצב המסונן והמשולב. הפתרון ה"נאיבי" אומר להוסיף ליומן שלוש אינדיקציות (boolean) המציינות לאילו מצבים הרשומה שייכת ולסנן ע"פ האינדיקציות הללו כשהמשתמש בוחר מצב עבודה מסוים. הבעיה הגדולה היא שחייבים להגדיר אינדקסים על השדות הללו (אחרת נחווה הרעה איומה בביצועים) והאינדקסים הללו מאוד לא יעילים כי השונות בין הערכים מזערית (הרי מדובר בשדה boolean).
הפתרון שיישמנו הוא פיצול של היומן לשלוש טבלאות שונות, כאשר כל מצב נמצא בטבלה אחרת. שינוי מצב עבודה ע"י המשתמש משנה את ה-connection וגורם לתצוגה להתמפות מעל טבלה אחרת. היתרון הגדול של הפתרון הזה הוא שיפור בביצועים. השליפה מתמפה מעל טבלה מסוימת ולא צריכה לדאוג לסינון רשומות בכל הנוגע למצבי עבודה. כמובן שצריך כלי Reporting שתומך בזה, אך אני מאמין שבכל כלי קצת Workarounds יכולים לעשות את העבודה. ב-Reporting Services עושים זאת ע"י הגדרה של Stored Procedure כ-Data Source ושליחת פרמטר אליו המגדיר את הסכמה המבוקשת (קוד
כאן). ב-OBIEE עושים זאת ע"י value-based fragmentation (הוראות
כאן). החסרון הוא תפיסת נפח מיותר לכאורה, אך אנחנו שמים ביצועים לפני נפחים.
לתהליך ה-ETL יש שלוש טבלאות מטרה, אחת עבור כל מצב עבודה. המסננים שבתוך תהליך הטעינה מגדירים לאילו יומנים, או טבלאות כל רשומה צריכה להגיע.
טיוב נתונים, או ניקוי רשומותנתחיל מהדבר הכי חשוב: חשוב מאוד להבהיר למשתמשים בתחילת הדרך שמערכת BI היא לא מערכת בינה מלאכותית ואין לה אפשרות לנחש אילו רשומות צריך לסנן ואילו לא. אין לה את האינטלגנציה האנושית ולכן היא לא יודעת לסנן דברים שנראים לנו פשוטים למראה עין. צריך להבהיר שהמערכת יודעת לפעול ע"פ
כללים מוגדרים מראש. לכן, השלב המקדים הוא גם הקשה מכולם. יש לנסות להגדיר כללים, לבחון אותם, לטייב את הכללים, לבחון שוב וכן הלאה עד שמגיעים לכללים מספיק טובים כך שיכסו כמה שיותר מצבים. דוגמא לכלל טוב יכול להיות שבנגררות מסוימות (בפועל כמעט בכולן) אם יש שינוי שארך יום אחד או פחות, יש לסנן אותו. הכלל הפשוט הזה יכול לסנן הרבה זבל/רעש כי קורה הרבה מאוד במערכות מכוננות שמשתמש מזין ערך שגוי ומתקן אותו מיד או למחרת והמערכת מוסיפה רשומה חדשה ולא מעדכנת את הישנה. נכון יהיה לא להציף את הרשומה המזובלת הזו.
לאחר שהבהרנו למשתמשים איך עובדת המערכת ולאחר שהגדרנו יחד איתם את הכללים, אפשר לממש את הסינון בתהליך הטעינה. השלב הזה יכול להיות קשה מאוד או קל מאוד, תלוי בכלי ה-ETL איתו אתם עובדים ובייחוד במורכבות הכללים. בעוד שכלי ETL מסתכלים בדר"כ על רשומה בודדת, הכללים נוגעים בדר"כ ליחס של הרשומה עם הרשומה שלפניה, אחריה או אפילו מעבר לכך. בשלב זה כדאי לשבת ולתכנן איך לממש ב-ETL את הכללים לפני שמבצעים בפועל. הכי חשוב הוא לבדוק שאכן התוצאות תואמות את מה שהגדרנו. צפו לבעיות ביצועים כאן, אך אפשר לשפר אותן בשלב מאוחר יותר (אני תמיד מעדיף נכונות נתונים בשלב מוקדם של הפרויקט ושיפור ביצועים בשלב מאוחר יותר, אבל זה רק טעמי האישי). כאמור, לאחר שמחליטים ב-ETL האם הרשומה צריכה להיות מסוננת או לא, מעבירים אותה דרך מסנן (filter) שיחליט לאילו טבלאות (מצבי עבודה) תגיע הרשומה.
זיהוי תהליכים, או: מי זו אסתי?הגענו לחלק המורכב יותר - זיהוי תהליכים. נזכיר שוב מהו תהליך, גם מבחינת ה-Business והפעם גם מהפן הטכני: תהליך, או Super Transaction בעגה המקצועית (ולכן קראנו לזה ST או אסתי המכוערת :-) הוא אירוע מהותי שהתרחש אצל הפרט, המתבטא בדר"כ על-פני מספר נגררות ופעמים רבות גם מתרחש על-פני מספר ימים הקרובים אחד לשני. אזכיר שוב את הדוגמא שהבאתי לגבי מתרגל שהופך למרצה ומשנה תוך מספר ימים קצר את המעמד, הקורסים והשכר שלו. דרישת הלקוח היא להציף למשתמש שהתרחש כאן תהליך ולא רק עוד כמה שינויים בנגררות של האדם.
נעבור לפן הטכני. ישנן כמה שאלות בסיסיות בנוגע לתהליכים:
- מה דינן של הרשומות המוכלות בתוך התהליכים? רשומה מוכלת בתהליך היא רשומה שהיא חלק מהתהליך (לדוגמא שינוי השכר בתהליך מעבר ממתרגל למרצה). אם כל הרשומות שמרכיבות את התהליך התרחשו באותו היום, האם נסמן את אותה השורה ביומן (תזכורת: אם כמה שינויים התרחשו באותו היום הם יאוחדו לאותה הרשומה ביומן) כרשומת התהליך או שזו רשומה חדשה? אם השינויים התרחשו ע"פ מספר ימים, האם ניצור רשומת תהליך חדשה או שמא נסמן את אחת הרשומות כרשומת התהליך? איזו רשומה נסמן? מה יקרה עם שאר הרשומות המוכלות?
- מה דינן של רשומות שהתרחשו בזמן התהליך אך הן לא שייכות לו? לדוגמא, נניח שבין הזמן שבו המתרגל הפך למרצה ועד לזמן שבו הוא קיבל העלאה במשכורת במקרה גם נולד לו בן בשעה טובה. תיווצר בנגררת המשפחה שלו רשומה חדשה, אך היא איננה שייכת לתהליך. מה דינה של רשומה זו?
- האם זיהוי התהליכים מתרחש לפני או אחרי תהליך הסינון? זיהוי התהליכים מסנן רשומות, מה שיכול להשפיע על הרשומות שיופיעו בפני המנגנון שמזהה תהליכים ולכן החלטה זו תשפיע על התוצאות.
נתחיל לענות: חשבנו והגענו למסקנה שישנו קשר ישיר בין מצבי העבודה שהזכרנו מקודם לבין נושא התהליכים.
הגדרנו את המצב המלא כך שהוא משקף את הנתונים בצורה זהה לחלוטין למערכות המקור ולכן אנחנו לא נוסיף או נשנה רשומות כלשהן בטבלה של המצב המלא. מכאן שלא נוסיף או נסמן רשומות תהליכיות ע"מ לא לפגוע בשיוויון בין המצב המלא ב-DataWarehouse לבין מערכות המקור. החשש הגדול ביותר של מערכת BI הוא שהמשתמשים יגידו "היי, זה לא תואם למה שאני רואה במערכת (המקור) שלי. המערכת הזאת לא שווה כלום!!!"
לעומת זאת, המצב המסונן הוא המצב שבו הלוגיקה שהגדרנו נכנסת לתוקף והמערכת נעשית חכמה יותר, הן מהבחינה של ניקוי רשומות והן מהבחינה של זיהוי תהליכים. לכן, במצב זה נסמן רשומות כרשומות תהליכיות. למה נסמן ולא נוסיף רשומות? מכיוון שהוספת רשומות, אפילו מזן שונה (תהליכיות) שובר את הכלל הבסיסי ביותר של היומן האישי שאומר שכל רשומה מתייחסת ליום אחד בלבד ולא יכולות להיות לאותו אדם שתי רשומות עם אותו היום. הדגש פה הוא מהצד האפיוני ולא מהצד הטכני (יכולנו להוסיף עוד שדה Is_SuperTransaction למפתח של הטבלה). הוספנו שדה בשם ST_Name המציין את שם התהליך שהרשומה מציינת (אם הוא null סימן שזו אינה רשומה תהליכית).
איזו רשומה מבין כל הרשומות שמרכיבות את התהליך נסמן? פשוט מאוד: נחליט (יחד עם הלקוח, במסגרת הכלל שיוצר את התהליך) מהי הרשומה ה"מובילה", או ה"דומיננטית" של התהליך ואותה נסמן כרשומת התהליך. דרך אגב, זו הרשומה שבדר"כ תעזור לנו לזהות את התהליך כולו. אם נחזור שוב לדוגמא שלנו, הרשומה שעוזרת לנו לזהות את התהליך היא הרשומה שבה המרצה שינה את המעמד שלו ממתרגל למרצה. נסמן את הרשומה הזו עם ST_Name=Position_Change. כמובן שחשוב מאוד לא לשכוח לשנות את הרשומות המוכלות בתוך התהליך כמסוננות ובשדה שמציין מה השתנה ברשומת התהליך להוסיף גם את שאר הנגררות שהשתנו. חזרה לדוגמא שלנו, נסמן שברשומה זו השתנה גם השכר וגם הקורסים ונעדכן את הערכים שלהם בשדות המתאימים. את הרשומות המקוריות בהן השתנו השכר והקורסים נסמן כמסוננות.
ומה לגבי רשומות שהתרחשו באותו טווח הזמן אך לא שייכות לתהליך (כמו בן שנולד)? הפיתרון שלנו מכסה את המקרה הזה בצורה פשוטה מאוד. מנגנון זיהוי והחלת התהליך מתייחסים אך ורק לרשומות שהוגדרו (בכלל שהגדרנו בשלב האפיון) כמוכלות בתוך התהליך הזה. אפילו אם זה קרה באותו יום של הרשומה המובילה, זה לא יפריע כלל.
לגבי סדר ביצוע הפעולות (ניקוי רשומות או זיהוי תהליכים), דנו רבות בנושא והגענו למסקנה שיותר נכון לבצע קודם כל את ניקוי הרשומות מכיוון שזיהוי התהליכים צריך "לראות מול עיניו" את התמונה הבהירה והנכונה יותר ע"מ לקבוע שהתרחש תהליך. שמחנו לראות שבדיקות שהרצנו אוששו את הטענה הזו.
סיכוםניקוי הרשומות וזיהוי התהליכים שהמערכת מבצעת מהווה קפיצת מדרגה למערכת ה-BI. המערכת אינה משקפת רק את הנתונים המקוריים של מערכות המקור, אלא מוסיפה נדבך של "אינטיליגנציה מלאכותית" שמשפר את המידע המגיע למשתמש ועוזר לו למצוא תהליכים מרכזיים בבליל הנגררות והנתונים. בעצם, השכבה הזו
הופכת מידע לידע ובכך משדרגת את מערכת ה-BI. מאידך, המערכת אינה כופה את הלוגיקה שלה על המשתמש ומאפשרת לו לבחור האם הוא רוצה לראות את הנתונים כהוויתם או לאחר העיבוד של המערכת. חשוב להבין ולהסביר ללקוח שהשכבה הזו דינאמית והאפיון שלה (כלומר הכללים שעל-פיהם מתבצעים הסינונים וזיהוי התהליכים) עובר טיוב ושיוף עם הזמן: מוצאים כללים מדויקים יותר, מקרי-קצה ואף תהליכים חדשים שלא חשבו עליהם מקודם. בכך, מסרנו מוצר טוב ו"חושב" שמתקדם עם הזמן (ונותן לנו עוד עבודת תחזוקה ;-).
בפוסט הבא (שלדעתי יהיה האחרון) אתאר עוד כמה נקודות מעניינות בפרויקט, כגון אופן הטעינות ההפרשיות, איך מוצאים תהליכים וכמה מהדו"חות היותר מעניינים ומועילים שאפשר לעשות מעל מחסן הנתונים.