ממשקי API של חיפוש אסינכרוני

נתמך ב:

פלטפורמת החיפוש ב-Google Security Operations מאפשרת להשתמש בממשקי API אסינכרוניים לשאילתות ממושכות שמחזירות קבוצות גדולות של עד מיליון תוצאות. ממשקי ה-API האלה מאפשרים לכם להתחיל חיפושים במקורות נתונים, כולל אירועים, זיהויים, טבלאות נתונים ותרשים הקשר של ישויות (ECG) במודל הנתונים המאוחד (UDM), בלי לחסום את האפליקציה. כשמריצים שאילתת חיפוש באמצעות API של פעולה ממושכת (LRO), מקבלים מזהה פעולה. אתם יכולים להשתמש במזהה הזה כדי לעקוב אחרי סטטוס הפעולה ולקבל את התוצאות דף אחרי דף.

דרישות מוקדמות

כדי להשתמש בממשקי API של פעולות ממושכות, לחשבון המשתמש שמבצע את הקריאה החוזרת נדרשות הרשאות ספציפיות לניהול זהויות והרשאות גישה (IAM).

כדי לבצע את הפעולות הבאות, אתם צריכים את הרשאות ה-IAM המתאימות:

  • מפעילים חיפוש: chronicle.searchSessions.search
  • הצגת תוצאות: chronicle.searchedResults.list במשאב SearchSession.

מוודאים שלחשבון המשתמש שמבצע את הקריאה יש תפקיד שמעניק את ההרשאות האלה, למשל התפקיד "צפייה ב-Chronicle API", "עריכה ב-Chronicle API" או "אדמין של Chronicle API".

הרצת חיפוש באמצעות ממשקי API של LRO

כדי להריץ חיפוש באמצעות ממשקי ה-API של LRO:

  1. מפעילים את החיפוש.
  2. מעקב אחרי הפעולה.
  3. אחזור התוצאות.

שולחים בקשת POST ל-method המותאם אישית search במכונה של Google SecOps.

  • נקודת קצה (endpoint)‏: POST /{$api_version}/projects/{project}/locations/{location}/instances/{instance}:search
  • שיטה: Search
  • גוף הבקשה: SearchRequest

הדוגמה הבאה מציגה אובייקט SearchRequest:

{
  "parent": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID",
  "query": "metadata.event_type = \"USER_LOGIN\"",
  "time_range": {},
  "start_time": "2026-03-16T14:40:13Z",
  "endTime": "2026-03-16T15:40:13Z",
  "dialect": "YL2"
}

הבקשה דורשת את הפרמטרים העיקריים הבאים:

  • ‫query: המחרוזת של שאילתת החיפוש.
  • ‫time_range: מרווח הזמן של החיפוש.
  • ‫dialect: מציין את הניב של השפה בתור YL2.
    • הניב SQL לא נתמך לאחזור תוצאות LRO אסינכרוניות באמצעות ListSearchedResults (searchedResults.list).
    • הניב RAW_LOG נמצא בגרסת טרום-השקה (Preview) ויכול להיות שתופיע השגיאה 501 UNIMPLEMENTED אם הוא לא מופעל במכונה שלכם.
  • ‫result_limit: אופציונלי. מספר השורות המקסימלי להצגה. ערך ברירת המחדל הוא 10000, והערך המקסימלי הוא 1000000.
  • ‫simulated_data_visibility (או simulatedDataVisibility ב-JSON): אופציונלי. ההגדרה קובעת אם תוצאות החיפוש יכללו אירועים מדומים. מגדירים את הערך SIMULATED_DATA_INCLUDED כדי לכלול אירועים מדומים בתוצאות החיפוש. אם לא מציינים את הפרמטר הזה, ברירת המחדל היא SIMULATED_DATA_EXCLUDED, והיא לא כוללת אירועים מדומים.

הקריאה הזו מחזירה אובייקט google.longrunning.Operation.

בדוגמה הבאה מוצגת תגובה לפעולה שהצליחה:

{
  "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata)",
    "state": "RUNNING",
    "start_time": "2026-03-13T10:00:00Z"
  }
}

השדה state: RUNNING מציין שהחיפוש מתבצע.

מעקב אחרי הפעולה

בודקים את הסטטוס של ה-LRO באמצעות השיטה הרגילה GetOperation מהשירות google.longrunning.Operations. משתמשים בערך name מהתגובה הקודמת.

  • נקודת קצה (endpoint): GET /{$api_version}/projects/{project}/locations/{location}/instances/{instance}/operations/{operationID}

ממשיכים לבצע סקרים עד שהשדה done בתגובה של GetOperation מחזיר את הערך true.

  • אם הפעולה בוצעה ללא שגיאות, השדה metadata.state יחזיר את הערך SUCCEEDED, ושדה התגובה יכיל את המשאב SearchSession שנוצר.
  • אם הפעולה נכשלת, השדה done מחזיר את הערך true, והשדה error מכיל את פרטי הכישלון הרלוונטיים.

בדוגמה הבאה מוצגת תגובה תקינה של GetOperation:

{
  "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID",
  "metadata": {
    "@type": "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation) Metadata",
    "state": "SUCCEEDED",
    "startTime": "2026-03-16T15:42:11.037506921Z"
  },
  "endTime": "2026-03-16T15:42:17.504730842Z",
  "expireTime": "2026-03-17T15:42:17.504731874Z",
  "progress": 100,
  "done": true,
  "response": {
    "@type": "[type.googleapis.com/google.cloud.chronicle.v1main.SearchSession](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchSession)",
    "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID",
    "query": "metadata.event_type = \"USER_LOGIN\"",
    "timeRange": {},
    "startTime": "2026-03-16T14:40:13Z",
    "endTime": "2026-03-16T15:40:13Z",
    "dialect": "YL2",
    "metadata": {
      "operationId": "OPERATION_ID",
      "startTime": "2026-03-16T15:42:11.037506921Z",
      "endTime": "2026-03-16T15:42:17.504730842Z",
      "expireTime": "2026-03-17T15:42:17.504731874Z",
      "resultRowCount": 10000,
      "moreDataAvailable": true
    }
  }
}

הפורמט של שם המשאב SearchSession הוא projects/{project}/locations/{location}/instances/{instance}/searchSessions/{search_session}.

התגובה המוצלחת מכילה את שדות המפתח הבאים:

  • ‫done: כשהערך מוגדר בתור true, הפעולה הושלמה.
  • ‫state: כשהערך הוא SUCCEEDED, החיפוש הסתיים בהצלחה.
  • ‫response.name: שם המשאב של SearchSession. השתמשו בערך הזה כנכס ההורה בשלב הבא.
  • ‫response.metadata.resultRowCount: מספר השורות הכולל שנמצאו.
  • ‫response.metadata.moreDataAvailable: מציין שמספר התוצאות הזמינות חורג ממגבלת ההחזרה שהוגדרה.

הצגת רשימה של פעולות LRO

כדי להציג רשימה של פעולות LRO, משתמשים ב-method‏ ListOperations מהשירות google.longrunning.Operations. משתמשים בערך name מהתגובה הקודמת.

  • נקודת קצה (endpoint): GET /{$api_version}/projects/{project}/locations/{location}/instances/{instance}

כדי להציג רשימה של פעולות LRO של חיפוש מ-24 השעות האחרונות, מציינים את המסנן name:"operations/s-lro-", כולל המקף בסוף.

בדוגמה הבאה מוצגת בקשת ListOperations שהצליחה:

google.longrunning.ListOperationsRequest {
  name: "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID"
  filter: "name:\"operations/s-lro-\""
  page_size: 100
}

בדוגמה הבאה מוצגת תגובה תקינה של ListOperations:

{
  operations {
    name: "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID_1"
    metadata {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperation) Metadata"
      value: "\b\002\022\f\b\367\304\363\316\006\020\317\352\232\240\003\032\f\b\237\307\363\316\006\020\326\334\351\311\001\"\f\b\237\352\370\316\006\020\352\342\351\311\001(d"
    }
    done: true
    response {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchSession](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchSession)"
      value: "\n\213\001projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/OPERATION_ID_11022\bip != \"\"\032\020\n\006\b\251\255\334\316\006\022\006\b\351\345\336\316\006\0012\\\n*OPERATION_ID_1\022\f\b\367\304\363\316\006\020\317\352\232\240\003\032\f\b\237\307\363\316\006\020\326\334\351\311\001\"\f\b\237\352\370\316\006\020\352\342\351\311\001(\300\204=0\001"
    }
  }
  operations {
    name: "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/operations/OPERATION_ID_2"
    metadata {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchOperationMetadata)"
      value: "\b\002\022\f\b\200\305\363\316\006\020\324\262\367\225\001\032\v\b\241\307\363\316\006\020\321\261\333?\"\v\b\241\352\370\316\006\020\317\264\333?(d"
    }
    done: true
    response {
      type_url: "[type.googleapis.com/google.cloud.chronicle.v1main.SearchSession](https://type.googleapis.com/google.cloud.chronicle.v1main.SearchSession)"
      value: "\n\213\001projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/OPERATION_ID_2\022\bip != \"\"\0321020\n\006\b\251\255\334\316\006\022\006\b\351\345\336\316\006\0012Z\n*OPERATION_ID_2\022\f\b\200\305\363\316\006\0201324\262\367\225\001\032\v\b\241\307\363\316\006\020\321\261\333?\"\v\b\241\352\370\316\006\020\317\264\333?(\300\204=0\001"
    }
  }
}

אחזור התוצאות

אחרי שמצב הפעולה חוזר ל-SUCCEEDED, משתמשים ב-method‏ ListSearchedResults() כדי לאחזר את תוצאות החיפוש.

  • נקודת קצה (endpoint): GET /{$api_version}/{parent=projects/*/locations/*/instances/*/searchSessions/*}/searchedResults
  • שיטה: ListSearchedResults
  • פרמטרים של הבקשה: ListSearchedResultsRequest

בדוגמה הבאה מוצגת בקשת ListSearchedResultsRequest שמאחזרת שלוש תוצאות ומדלגת על חמש הראשונות:

// GET
/v1alpha/projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID/searchedResults?page_size=3&skip=5

הבקשה תומכת בפרמטרים הבאים של שאילתה:

  • ‫page_size: המספר המקסימלי של תוצאות שיוחזרו בכל דף. ערך ברירת המחדל הוא 100, והערך המקסימלי הוא 10,000.
  • ‫page_token: הטוקן מ-ListSearchedResultsResponse קודם שמשמש לאחזור הדף הבא.
  • ‫order_by (או orderBy ב-JSON): אופציונלי. השדה שמשמש למיון התוצאות. כשמשמיטים את order_by, תוצאות האירועים ב-UDM ממוינות לפי udm.metadata.event_timestamp בסדר יורד כברירת מחדל, והאירועים האחרונים מוחזרים קודם. כשמציינים נתיב שדה ב-order_by בלי סיומת כיוון, כמו udm.principal.hostname, התוצאות ממוינות בסדר עולה כברירת מחדל. אל תוסיפו את הסיומת asc, כי asc היא לא נתמכת ומחזירה שגיאת 400 INVALID_ARGUMENT. כדי למיין את התוצאות בסדר יורד, מוסיפים את הסיומת desc לנתיב השדה, למשל udm.metadata.event_timestamp desc. אין תמיכה במיון של כמה עמודות.

    • ‫UDM events (eventRecord): צריך להשתמש בנתיבים מוגדרים במלואם בשדה udm, כמו udm.metadata.event_timestamp desc או udm.principal.hostname. אפשר גם להשתמש בשמות של עמודות, כמו hostname,‏ user,‏ process name ו-event type.

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

    • ‫Entities / ECG (entityContextRecord): משתמשים בנתיבים בשדה entity, כמו graph.entity.ip או graph.entity.ip desc.

    • ‫data tables (dataTableRecord): צריך להשתמש בפורמט %<table_alias>.<column_name>. לדוגמה, %dt.user desc.

      ערך ברירת המחדל הוא העמודה הראשונה בטבלת הנתונים.

    • ‫Detections (DetectionRecord): משתמשים במילת המפתח detection ואחריה הנתיב, לדוגמה detection.id.

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

      לדוגמה:

      • ‫ECG (הצטרפות ל-UDM-ECG): ישות: $e1.graph.entity.hostname
      • ‫UDM (כל הצירופים עם UDM): $e1.principal.ip
      • טבלת נתונים (צירוף של UDM וטבלת נתונים): %<table_alias>.<column_name>

      יש גם תמיכה בכינויים מוגדרים מראש כמו hostname,‏ user,‏ process name ו-event type. במקרים כאלה, צריך להשתמש בפורמט $e1.hostname.at.

  • ‫skip: אופציונלי. מספר התוצאות שצריך לדלג עליהן. אין להשתמש בפרמטר הזה עם page_token.

    • מיון ברירת המחדל (udm.metadata.event_timestamp) לא ייחודי לאירועים עם אותה חותמת זמן. בנוסף, סדר המיון של תוצאות החיפוש מוגדר בקריאה הראשונה ל-ListSearchedResults (searchedResults.list).
    • כשמגדירים עימוד באמצעות skip, במיוחד בבקשות מקבילות, צריך לציין שדה מיון ייחודי כמו udm.metadata.id בפרמטר order_by. לחלופין, אפשר לאחזר את הדף הראשון לפני ששולחים בקשות skip מקבילות, כדי שסדר המיון כבר יהיה מוגדר.

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

{
  "searchedResults": [
    {
      "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID/searchedResults/RESULT_ID",
      "resultRow": {
        "eventRecord": {
          "event": {
            "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/events/EVENT_ID",
            "udm": {
              "metadata": {
                "eventTimestamp": "2026-03-16T14:45:18Z",
                "eventType": "USER_LOGIN",
                "vendorName": "Microsoft",
                "productName": "Azure AD"
              }
            }
          },
          "eventLogToken": "EVENT_LOG_TOKEN"
        }
      }
    },
    {
      "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID/searchedResults/RESULT_ID",
      "resultRow": {
        "eventRecord": {}
      }
    },
    {
      "name": "projects/PROJECT_NUMBER/locations/LOCATION/instances/INSTANCE_ID/searchSessions/SEARCH_SESSION_ID/searchedResults/RESULT_ID",
      "resultRow": {
        "eventRecord": {}
      }
    }
  ],
  "totalSize": 10000,
  "columnNames": [],
  "columnSchema": {},
  "nextPageToken": "CAKYASAB"
}

כדי לאחזר את דף התוצאות הבא, צריך להשתמש בערך nextPageToken שהוחזר בפרמטר השאילתה page_token של בקשת ה-ListSearchedResults הבאה. השדה resultRow מכיל את הנתונים עצמם.

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

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

למידע נוסף על שיטות, שדות של בקשות ותגובות וסוגים, עיינו במאמרי העזרה הבאים של ה-API:

הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.