ניהול נתונים ב-Google Health API

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

  • האם אתם כותבים נתונים ל-Google Health API? רק קוראים? או גם וגם?
  • האם מאגר הנתונים מקומי באפליקציה או במכשיר? או בענן משלכם?
  • האם צריך לסנכרן נתונים מ-Google Health API בין האפליקציה של המשתמש לבין מכשיר לביש? באיזו תדירות אתם מסנכרנים מכשירים?
  • אילו סוגי נתונים יש לך? ספירות בסיסיות? יחידות מידה? סדרות עם שיעורי דגימה שונים?
  • האם יש לך תוכניות לקרוא נתונים בזמן שהאפליקציה פועלת ברקע?
  • האם אתם מתכננים לעבוד עם נתונים היסטוריים שתועדו לפני שהאפליקציה קיבלה הרשאות משתמש?

כדי להבין איך הכול משתלב, כדאי לעיין במחזור החיים של הסנכרון של Google Health API. יש שני סוגים של מחזור חיים: רגיל (קריאה וכתיבה) וקריאה בלבד.

מחזור החיים של סנכרון רגיל

מחזור חיים רגיל של סנכרון ב-Google Health API
איור 1: מחזור חיים סטנדרטי של סנכרון ב-Google Health API

שילוב עם Google Health API כולל העתקה של נתונים לאפליקציה או למאגר נתונים של backend. כדי להקל על השימוש במסמכי התיעוד האלה, נקרא למאגר הנתונים הזה מאגר הנתונים למפתחים.

המונח 'העתקה' כאן יכול להחליף כל פעילות נפרדת, כמו קריאה מ-Google Health API (העתקה למאגר הנתונים של המפתחים) או כתיבה ל-Google Health API (העתקה ל-Google Health API). ביצוע הפעולות האלה שוב ושוב בסדר מסוים הוא מחזור החיים של הסנכרון.

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

כתיבה

  1. הכנת נתונים חדשים לכתיבה – העברת נתונים ממכשיר או מאפליקציה חיצוניים ועיצוב נקודות נתונים לייצוגים בפורמט JSON שתואמים לסוגי הנתונים של Google Health API. שימו לב: בשלב הזה, Health API לא תומך במזהים מותאמים אישית שהלקוח מקצה לפעולות כתיבה. אפשר לציין מזהים כאלה ב-POST, אבל המערכת מתעלמת מהם.
  2. Upsert records – שליחת נקודות נתונים ל-Google Health API באמצעות נקודות קצה של REST. משתמשים ב-POST כדי ליצור רשומות, וב-PATCH כדי להוסיף ולעדכן רשומות קיימות. המזהים שנדרשים לפעולה PATCH הגיעו מפעולה קודמת POST (השלב הבא במחזור הקודם).
  3. עיבוד מזהי משאבים שמוחזרים – כשמשתמשים במזהים שנוצרים בשרת, צריך לחלץ את המשאב name או המזהה שמוחזרים מהשרת ולשמור אותם במאגר הנתונים של המפתחים כדי לאפשר עדכונים (PATCH) או מחיקות (DELETE) בעתיד. מידע נוסף על שני הסוגים זמין במאמר בנושא אסטרטגיות זיהוי.

קריאה

  1. קריאת רשומות – שליפת נתונים חדשים ושינויים בנתונים קיימים מ-Google Health API באמצעות נקודות קצה של REST (‫GET עם פרמטרים של שאילתות filter וחלוקה לדפים pageToken, או נקודות קצה של צבירה כמו rollUp ו-dailyRollUp), או קבלת התראות בזמן אמת באמצעות מינויים ל-Webhook ‏ (projects.subscribers). התראה מציינת רק שיש נתונים חדשים, ולא מה הנתונים בפועל.
  2. התאמה של מאגר הנתונים של המפתחים – התאמה של הנתונים החדשים והמעודכנים למאגר הנתונים של המפתחים. במכשירים מקושרים יכולים להיות מרווחי זמן חופפים במהלך סנכרון. במאמר חותמות זמן של מרווחים וסנכרון של מכשירים מחוברים מוסבר איך Google Health API פותר את הבעיות האלה.

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

שיטות זיהוי

אם אתם מתכוונים לכתוב נתונים ל-Google Health API, לפני שאתם יוצרים את השילוב עם Google Health APIs, אתם צריכים לבחור אסטרטגיה לזיהוי משאבים כשאתם יוצרים נקודות נתונים (היחידה הבסיסית של הנתונים).

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

  1. מזהים שנוצרו על ידי השרת (אפשרות ברירת המחדל): הלקוח שולח נתונים ללא מזהה, והבק-אנד של Google Health API יוצר ומחזיר מזהה מערכת ייחודי.
  2. מזהים מותאמים אישית שהוקצו על ידי הלקוח (לפי AIP-133, עדיין לא נתמך): אפליקציית הלקוח יוצרת מזהה ייחודי (לדוגמה, מזהה UUID או מפתח ראשי של מסד נתונים מקומי) ומספקת אותו בנתיב המשאב בזמן היצירה.

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

תכונה מזהים שנוצרו על ידי השרת מזהים מותאמים אישית שהוקצו על ידי הלקוח
יצירת מזהים השרת יוצר מזהה מערכת אקראי במהלך הביצוע של POST. הלקוח יוצר מזהה יציב באופן מקומי (UUID v4 / מפתח ראשי פנימי) לפני הכתיבה.
נתיב משאב .../dataPoints/{server_id} (מוחזר בתגובה) .../dataPoints/{custom_id}
Post-Write Local Step חובה. צריך לאחסן את הערך המוחזר server_id במסד נתונים מקומי כדי לאפשר עדכונים או מחיקות בעתיד. ללא. האפליקציה כבר בבעלות המזהה.
טבלת מיפוי מזהים חובה. הלקוח צריך לשמור על מיפוי דו-כיווני (local_idserver_id). אין צורך. הלקוח משתמש ישירות במפתח הראשי שלו.
התנהגות של ניסיון חוזר (רשת חלשה) סיכון לכפילויות. ניסיון חוזר של POST שפג הזמן שלו יוצר רשומה כפולה עם מזהה שרת חדש. בטוח ואידמפוטנטי. ניסיון חוזר של POST עם אותו custom_id מונע יצירה כפולה (מחזיר 409 ALREADY_EXISTS).
תמיכה בסנכרון אופליין מוגבלת. צריך להמתין לתגובה מהשרת כדי לקבל מזהי משאבים רשמיים לפני שמתייחסים אליהם. מלאה. אפשר ליצור ישויות ולשנות אותן במצב אופליין עם מזהים יציבים, ואז לסנכרן אותן בצורה חלקה כשמתחברים מחדש.
מגבלות פורמט הטיפול מתבצע כולו בשרת. חייב להיות בהתאם ל-^[a-z0-9-]{4,63}$ (4-63 אותיות קטנות אלפאנומריות ומקפים).
מתי כדאי לבחור

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

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

מומלץ לבחור מזהים מותאמים אישית אם:

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

מחזור החיים של סינכרון לקריאה בלבד

מחזור החיים של סנכרון לקריאה בלבד ב-Google Health API
איור 2: מחזור החיים של סנכרון לקריאה בלבד ב-Google Health API

אפליקציה שרוצה רק לקרוא נתונים מ-Google Health API צריכה להעתיק נתונים למאגר הנתונים של המפתחים ולטפל בחלק של ההתאמה במחזור החיים.

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

איור 2 מציג את מחזור החיים של קריאה בלבד.

חותמות זמן של מרווחים וסנכרון של מכשירים מחוברים

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

חותמות זמן של מרווחים (startTime ו-endTime) מציגות התנהגויות ייחודיות כשעובדים עם נתונים של מרווחים. בקטע הזה מוסבר למה יש חפיפה בין מרווחי הזמן, ומוצגות השוואות בין נקודות הקצה list ו-reconcile.

מרווחי זמן חופפים ממכשירים מחוברים

מכשירים מחוברים כמו צמידי Fitbit ו-Google Pixel Watch אוספים באופן רציף נתונים ביומטריים בתדירות גבוהה בזמן שהם על הגוף. אחרי שמכשיר מסנכרן נקודות נתונים עם Google Health, הוא לא משנה רטרואקטיבית את הרשומות הקיימות האלה. חותמות הזמן של המרווחים שמאוחסנות לא ישתנו.

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

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

  1. במהלך הסנכרון הראשון, המכשיר מעלה נקודה על הגרף שמכסה את התקופה 10:00:00Z עד 10:14:59Z.
  2. אחרי חישוב מחדש במכשיר, מתבצע סנכרון שני שמעלה עוד נקודה על הגרף שכוללת את התקופה 10:14:00Z עד 10:28:59Z.

שני הרשומות מאוחסנות באופן עצמאי ב-backend של Google Health. כתוצאה מכך, שתי נקודות הנתונים מכסות את המרווח שבין 10:14:00Z ל-10:14:59Z. כך נוצרת חפיפה של 59 שניות כשמבצעים שאילתה על רשומות גולמיות.

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

אפשר לטפל במרווחי הזמן החופפים האלה באמצעות נקודת הקצה list או reconcile. בוחרים את נקודת הקצה שמתאימה לדרישות של האפליקציה:

תכונה נקודת קצה (list) נקודת קצה (reconcile)
שיטת HTTP GET https://health.googleapis.com/v4/users/me/dataTypes/<var>dataType</var>/dataPoints GET https://health.googleapis.com/v4/users/me/dataTypes/<var>dataType</var>/dataPoints:reconcile
התנהגות חפיפה הפונקציה מחזירה את כל הרשומות שנשמרו כרשומות שהועלו, ללא ביטול כפילויות. אם יש חפיפה בין פרקי הזמן, שתי הרשומות מוחזרות. הוא פותר התנגשויות ומבטל כפילויות של רשומות חופפות במכשירים ובסשנים של סנכרון, כך שמתקבל זרם רציף אחד.
יתרונות מספקת נתיב ביקורת מלא ולא משונה של כל רשומה שהועלתה על ידי כל מכשיר וכל קבוצת סנכרון. ההגדרה הזו מפשטת את העיבוד של ציר הזמן ואת החישובים של משך הזמן, כי היא מטפלת אוטומטית במרווחי זמן חופפים ובסכסוכים בין מכשירים.
חסרונות באחריות האפליקציה לזהות ולפתור חפיפות בין מרווחי זמן, התנגשויות בין מכשירים ותקופות שבהן השעון לא על היד. רשומות חופפות משניות מושמטות מהתגובה, כך שאי אפשר לבצע ביקורת על קבוצות של סנכרון מכשירים בנפרד.

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

תהליך ההתאמה פותר סתירות בין סשנים על ידי בחירת הרשומה הסמכותית במקום ליצור איחוד מלאכותי של זמנים. לדוגמה, המערכת לא תמזג את 11:00:00Z עם 11:30:00Z ואת 11:20:00Z עם 11:50:00Z ל-11:00:00Z עד 11:50:00Z. התשובה המאוחדת מחזירה את נקודת הנתונים המנצחת עם המרווח המקורי שבו היא נרשמה. כך שומרים על התקינות של הטלמטריה והמדדים שנמדדו באותו סשן.

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

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

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

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

שינוי חותמת הזמן ועדכונים של הבעלים

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

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

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