דוגמאות לטרנספורמציות

אפשר לשנות את נתוני CloudEvents באמצעות כתיבת ביטויי שינוי ב-CEL. מידע נוסף זמין במאמר בנושא טרנספורמציה של אירועים שהתקבלו.

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

תרחישים סטנדרטיים לדוגמה

ריכזנו כאן כמה תרחישי שימוש סטנדרטיים להמרת נתוני אירועים.

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

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

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "orderId": "12345",
    "customer": {
      "firstName": "Alex",
      "lastName": "Taylor",
      "address": {
        "street": "1800 Amphibious Blvd.",
        "city": "Mountain View"
      }
    }
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "orderId": "12345",
    "customerFirstName": "Alex",
    "customerLastName": "Taylor",
    "customerStreet": "1800 Amphibious Blvd.",
    "customerCity": "Mountain View"
  }
}
פתרון 1:

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

message.setField("data",
{
  "orderId": message.data.orderId,
  "customerFirstName": message.data.customer.firstName,
  "customerLastName": message.data.customer.lastName,
  "customerStreet": message.data.customer.address.street,
  "customerCity": message.data.customer.address.city,
})
פתרון 2:

משתמשים בפונקציה בביטוי. הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון. הפונקציה denormalize מיישרת מבנים עמוקים לרשימה של צמדי מפתח וערך. שמות השדות מופרדים באמצעות נקודה (.) כדי לפלח את ההיררכיה של המבנה. לדוגמה:

message.setField("data", message.data.denormalize())

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

{
  "data": {
    "orderId": "12345",
    "customer.firstName": "Alex",
    "customer.lastName": "Taylor",
    "customer.address.street": "1800 Amphibious Blvd.",
    "customer.address.city": "Mountain View"
  }
}

הסתרת נתונים

צריך להסוות נתונים רגישים במטען ייעודי (payload) של אירוע לפני שהוא נשלח לסביבה פחות מאובטחת.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "userId": "user123",
    "email": "alex@example.com",
    "creditCardNumber": "1234-5678-9012-3456"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "userId": "user123",
    "email": "a***@example.com",
    "creditCardNumber": "xxxx-xxxx-xxxx-3456"
  }
}
פתרון:

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

message
      .setField("data.email",
          re.extract(message.data.email,
                    "(^.).*@(.*)",
                    "\\1***@\\2"))

      .setField("data.creditCardNumber",
          re.extract(message.data.creditCardNumber,
                    "(\\d{4})\\D*$",
                    "xxxx-xxxx-xxxx-\\1"))

השמטת נתונים

אתם צריכים להסיר שדות ספציפיים ממטען ייעודי (payload) של אירוע על סמך תנאים מסוימים.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "orderId": "12345",
    "customerType": "gold",
    "discountCode": "VIP"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  {
  "orderId": "12345",
  "customerType": "gold"
  }
}
פתרון:

משתמשים בביטוי שמצנזר את השדה discountCode אם הערך של customerType הוא gold. הפונקציה removeFields מסירה שדות ספציפיים מאירוע. לדוגמה:

message.data.customerType == "gold" ?
      message.removeFields(["data.discountCode"]) :
      message

המרת נתונים

אתם צריכים להמיר נתונים מפורמט או מסוג אחד לפורמט או לסוג אחר.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "orderDate": "2024-10-31T12:00:00Z",
    "totalAmount": "1500"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "orderDate": 1704086400,
    "totalAmount": 1500.00
  }
}
פתרון:

משתמשים בביטוי שממיר את orderDate לחותמת זמן של UNIX, ואת הסוג totalAmount מ-string ל-double (מספר נקודה צפה). הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון. אפשר להשתמש בפונקציות לשינוי מחרוזות כדי להמיר את התוצאות של המחרוזות. לדוגמה:

message
      .setField("data.orderDate", int(timestamp(message.data.orderDate)))
      .setField("data.totalAmount", double(message.data.totalAmount))

ניתוב מותנה

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

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "eventType": "order.created",
    "orderValue": 200
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "eventType": "order.created",
    "orderValue": 200,
    "routingKey": "highValue"
  }
}
פתרון:

משתמשים בביטוי שמוסיף שדה routingKey עם הערך highValue אם orderValue גדול מ-100, אחרת הערך הוא "normal". אפשר להשתמש בשדה routingKey כדי לקבוע את נתיב הניתוב. הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון. לדוגמה:

message.data.orderValue > 100 ?
      message.setField("data.routingKey", "highValue") :
      message.setField("data.routingKey", "normal")

טיפול בערך ברירת מחדל

צריך לוודא שלשדות מסוימים במטען הייעודי (payload) של האירוע יש ערכי ברירת מחדל אם הם לא קיימים.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "itemName": "Product A"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "itemName": "Product A",
    "quantity": 1
  }
}
פתרון:

משתמשים בביטוי שמוסיף שדה quantity עם ערך ברירת מחדל של 1 אם השדה עדיין לא קיים. המאקרו has בודק אם שדה מסוים זמין. הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון. לדוגמה:

has(message.data.quantity)  ?
    message :
    message.setField("data.quantity", 1)

מניפולציה של מחרוזות

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

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "customerEmail": "alex@example.com"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "customerEmail": "alex@example.com",
    "emailDomain": "example.com"
  }
}
פתרון:

משתמשים בביטוי שמחלץ את שם הדומיין ("example.com") מהשדה customerEmail ומאחסן אותו בשדה חדש emailDomain. הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון. הפונקציה של הביטוי הרגולרי extract פועלת לפי התחביר של RE2. לדוגמה:

message
  .setField("data.emailDomain",
re.extract(message.data.customerEmail, "(^.*@)(.*)", "\\2"))

פעולות ברשימה ובמפה

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

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "productIds": [
      "product123",
      "product456"
    ]
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "productIds": [
      "product123",
      "product456"
    ],
    "productFound": true
  }
}
פתרון:

משתמשים בביטוי שבודק אם 'product456' קיים ברשימה productIds ומאחסן את התוצאה (true או false) בשדה חדש productFound. הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון. המאקרו exists בודק אם פרדיקט מתקיים עבור כל הרכיבים ברשימה ומשלב את התוצאות עם האופרטור 'או'. לדוגמה:

message.setField("data.productFound",
        message.data.productIds.exists(id, id == "product123"))

טיפול בשגיאות

צריך לטפל בצורה נכונה בשגיאות פוטנציאליות או בנתונים לא צפויים במטען הייעודי (payload) של אירוע.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "quantity": "abc"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "quantity": 0,
    "error": "Invalid quantity"
  }
}
פתרון:

משתמשים בביטוי שמנסה להמיר את השדה quantity למספר שלם. אם ההמרה נכשלת, צריך להגדיר את השדה quantity לערך 0 ולהוסיף שדה error חדש עם הערך Invalid quantity (כמות לא תקינה).

  • פקודת המאקרו has בודקת אם שדה מסוים זמין.
  • הפונקציה type מחזירה את סוג הערך.
  • פונקציית הביטוי הרגולרי matches פועלת לפי התחביר של RE2.
  • הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון.

לדוגמה:

// Check if data.quantity exists
has(message.data.quantity) &&
// Check if data.quantity is a string
type(message.data.quantity) == string &&
// Check if string consists of digits
message.data.quantity.matches(r'^-?[0-9]+$') ?
  // If data.quantity is valid, use message
  message :
  // If data.quantity is invalid, set to 0 and generate error
  message
    .setField("data.quantity", 0)
    .setField("data.error", "Invalid quantity")

תרחישים מורכבים לדוגמה

ריכזנו כאן כמה תרחישי שימוש מורכבים להמרת נתוני אירועים.

התאמת נתונים

צריך לבצע כמה טרנספורמציות על נתוני אירועים מוטמעים.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "orderId": "12345",
    "customer": {
      "firstName": "Alex",
      "lastName": "Taylor",
      "email": "alex@example.com",
      "address": {
        "street": "1800 Amphibious Blvd.",
        "city": "Mountain View",
        "state": "CA"
      }
    },
    "items": [
      {
        "itemId": "item1",
        "price": 10.00,
        "quantity": 2
      },
      {
        "itemId": "item2",
        "price": 5.00,
        "quantity": 1
      }
    ]
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "orderId": "12345",
    "customer.firstName": "Alex",
    "customer.lastName": "Taylor",
    "customer.email": "a***@example.com",
    "customer.address.city": "Mountain View",
    "customer.address.state": "CA"
  }
}
פתרון:

משתמשים בביטוי שמחלץ את העיר והמדינה מהכתובת, ומסתיר את כתובת האימייל.

  • הפונקציה setField מוסיפה או מחליפה שדה של האירוע במפתח נתון.
  • הפונקציה toMap ממירה רשימה של מפות CEL למפת CEL אחת.
  • פונקציית הביטוי הרגולרי extract פועלת לפי התחביר של RE2.
  • הפונקציה removeFields מסירה שדות ספציפיים מאירוע.
  • הפונקציה denormalize משטחת מבנים עמוקים לרשימה של צמדי מפתח וערך. שמות השדות מופרדים באמצעות נקודה (.) כדי לפלח את ההיררכיה של המבנה.

לדוגמה:

message
.setField("data",
  message.data.setField("customer.address",
    message.data.customer.address.map(key, key == "city" || key == "state",
          { key: message.data.customer.address[key] }).toMap())
  .setField("customer.email",
        re.extract(message.data.customer.email, "(^..?).*@(.*)", "\\1***@\\2"))
  .removeFields(["items"])
  .denormalize()
)

פורמט הנתונים והניתוב שלהם

צריך לעצב את נתוני האירועים, להוסיף פרטי מוצרים ואז לנתב את הודעת האירוע.

תרחיש:

בהינתן נתוני CloudEvents הבאים:

{
  "data": {
    "productId": "p123",
    "productName": "Example Product",
    "category": "electronics"
  }
}

אתם רוצים לכתוב ביטוי CEL שיוביל לפלט הבא:

{
  "data": {
    "productId": "electronics-p123",
    "productName": "EXAMPLE PRODUCT",
    "category": "electronics",
    "routingKey": "electronics"
  }
}
פתרון:

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

message
.setField("data.productId",
message.data.category + "-" + message.data.productId)
.setField("data.productName", message.data.productName.upperAscii())
.setField("data.routingKey", message.data.category)