在 BigQuery 中分析物件擴充功能

在 BigQuery 中使用 SQL 查詢 object enrichments,即可在數百萬個儲存的物件中搜尋、篩選及分析中繼資料,不必逐一檢查每個物件。

設定 儲存空間分析 資料集後,Cloud Storage 會自動將物件清單和中繼資料 (包括 AI 模型生成的 object enrichments) 直接匯出至 BigQuery。本頁說明 Cloud Storage 如何在 BigQuery 中建構物件擴充功能。此外,也提供 SQL 方案,可用於尋找標籤、偵測臉部、識別煽情露骨內容、擷取定界框,以及分類 PDF 文件。

取得必要角色

如要取得在 BigQuery 查詢物件擴充所需的權限,請要求管理員在專案中授予您下列 IAM 角色:

如要進一步瞭解如何授予角色,請參閱「管理專案、資料夾和組織的存取權」。

這些預先定義的角色具備在 BigQuery 中查詢 object enrichments 所需的權限。如要查看確切的必要權限,請展開「Required permissions」(必要權限) 部分:

所需權限

您必須具備下列權限,才能在 BigQuery 中查詢物件擴充功能:

  • bigquery.jobs.create
  • bigquery.tables.getData

您或許還可透過自訂角色或其他預先定義的角色取得這些權限。

物件擴充功能如何與 Storage Insights 整合

為專案設定 儲存空間分析資料集後,Cloud Storage 會定期將 bucket 庫存和物件內容匯出至 BigQuery 資料集。

在 BigQuery 中,您的資料會顯示在object_contexts_catalog_view檢視畫面中。這個檢視畫面會提供儲存物件的統一目錄。每列都包含物件屬性 (project、bucket、name、generation) 和重複的 contexts 記錄陣列:

  • contexts.key:專屬情境 ID。Cloud Storage 產生的機器學習擴充功能一律會以 google:annotation: 前置字元開頭 (例如 google:annotation:label-detector-v1 或 google:annotation:face-detector-v1)。
  • contexts.value:擴充的模型執行狀態 (例如 SUCCESS 或 FAILURE)。
  • contexts.extendedData:包含模型擴充功能酬載的 JSON 資料欄,例如偵測到的標籤、臉部地標、多邊形頂點和類別路徑。

如需完整的表格結構和資料欄說明,請參閱「物件內容目錄結構定義」。

瞭解查詢模式:UNNEST 與 EXISTS

一個物件可以有多個情境,每個模型也可以輸出多個偵測結果 (例如多個標籤或偵測到的臉孔)。查詢 object_contexts_catalog_view 檢視表時,通常會使用下列其中一種 SQL 模式:

  • 每列一項偵測結果 (UNNEST):在重複的 contexts 記錄陣列和模型的內部 JSON 陣列上,使用 UNNEST 運算子 (透過 JSON_QUERY_ARRAY 函式)。取消巢狀結構會將重複的擴充內容攤平,讓每個偵測到的特徵產生自己的資料列。如需檢查個別標籤、擷取定界框座標,或計算各項偵測結果的統計資料,請使用這個方法。
  • Row-per-object (EXISTS):使用相關的 EXISTS 子查詢,測試物件是否包含特定標籤、模型輸出或門檻。這種做法會評估重複的內容,而不會在外部查詢中取消巢狀結構。無論有多少偵測結果相符,每個物件都只會傳回一列。

查詢範例

下列 SQL 範例說明如何查詢及篩選物件擴充功能,以用於常見的資料管理和分析工作流程。

在每筆查詢中,替換下列內容:

  • PROJECT_ID: Google Cloud 專案的 ID。
  • DATASET_ID:BigQuery 資料集的名稱,儲存空間分析會將資料匯出至該資料集。

尋找含有特定標籤的圖片

如要搜尋 label-detector 模型評估的圖片,您可以將每個相符的標籤傳回為個別資料列,或傳回包含該標籤的不重複圖片。

傳回相符的標籤 (將資料列扁平化)

下列查詢會攤平 contexts 和 labelAnnotations 陣列,為圖片中找到的每個相符標籤傳回獨立資料列:

SELECT
  t.project,
  t.bucket,
  t.name,
  t.generation,
  STRING(label.description) AS label_description,
  FLOAT64(label.score) AS confidence_score
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t,
  UNNEST(t.contexts) AS context,
  UNNEST(JSON_QUERY_ARRAY(context.extendedData.labelAnnotationGroup.labelAnnotations)) AS label
WHERE
  context.key = 'google:annotation:label-detector-v1'
  AND LOWER(STRING(label.description)) = 'car'
  AND FLOAT64(label.score) > 0.75
LIMIT 10;

傳回不重複的圖片 (避免重複的資料列)

如果圖片包含多個相符標籤,取消巢狀結構會為該物件產生多個資料列。如要讓每張圖片只傳回一列,請在 EXISTS 子查詢中檢查標籤是否存在:

SELECT
  project,
  bucket,
  name,
  generation
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t
WHERE
  EXISTS(
    SELECT 1
    FROM
      UNNEST(t.contexts) AS context,
      UNNEST(JSON_QUERY_ARRAY(context.extendedData.labelAnnotationGroup.labelAnnotations)) AS label
    WHERE
      context.key = 'google:annotation:label-detector-v1'
      AND LOWER(STRING(label.description)) = 'car'
      AND FLOAT64(label.score) > 0.75
  )
LIMIT 10;

尋找主體面帶微笑的肖像和自拍照 (臉部偵測)

您可以結合多種臉部特徵 (例如情緒表達、頭部方向角度和定界框尺寸),找出特定類型的相片。

下列查詢會使用一般資料表運算式 (CTE) 計算臉部定界框涵蓋範圍。這項功能會篩選出正面拍攝的微笑人像,且主體至少占圖片的 60%:

WITH
  face_stats AS (
    SELECT
      t.project,
      t.bucket,
      t.name,
      t.generation,
      -- Extract the joy likelihood score (0.0 to 1.0)
      FLOAT64(face.joyProbability) AS joy_probability,
      -- Extract head pose orientation angles (degrees)
      FLOAT64(face.rollAngle) AS roll_angle,
      FLOAT64(face.panAngle) AS pan_angle,
      FLOAT64(face.tiltAngle) AS tilt_angle,
      -- Calculate the bounding box area relative to total image area (0.0 to 1.0)
      (
        SELECT AS STRUCT
          (MAX(FLOAT64(v.x)) - MIN(FLOAT64(v.x)))
          * (MAX(FLOAT64(v.y)) - MIN(FLOAT64(v.y))) AS coverage
        FROM
          UNNEST(JSON_QUERY_ARRAY(face.boundingPoly.normalizedVertices)) AS v
      ).coverage AS face_coverage_percentage
    FROM
      `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t,
      UNNEST(t.contexts) AS context,
      UNNEST(
        JSON_QUERY_ARRAY(
          context.extendedData.faceAnnotationGroup.faceAnnotations)) AS face
    WHERE
      context.key = 'google:annotation:face-detector-v1'
  )
SELECT
  project,
  bucket,
  name,
  generation,
  joy_probability,
  face_coverage_percentage
FROM
  face_stats
WHERE
  joy_probability > 0.5
  AND roll_angle BETWEEN -10 AND 10
  AND pan_angle BETWEEN -10 AND 10
  AND tilt_angle BETWEEN -10 AND 10
  AND face_coverage_percentage >= 0.60
LIMIT 10;

這項查詢會套用下列篩選器:

  • joy_probability > 0.5:選取評估結果為快樂或微笑的臉部。
  • BETWEEN -10 AND 10:限制 roll、pan 和 tilt 角度,讓臉部直接朝向相機。
  • face_coverage_percentage >= 0.60:使用正規化多邊形頂點 (0.0 至 1.0),篩選出占畫面 60% 以上的人臉。

找出含有內容安全標記的圖片

content-safety 模型會評估圖片是否含有成人和暴力內容。模型會為每個類別指派可能性評分,例如 VERY_UNLIKELY、UNLIKELY、POSSIBLE、LIKELY 或 VERY_LIKELY。

以下查詢會傳回模型以高信賴度標示為成人內容的獨特圖片:

SELECT
  project,
  bucket,
  name,
  generation
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t
WHERE
  EXISTS(
    SELECT 1
    FROM
      UNNEST(t.contexts) AS context
    WHERE
      context.key = 'google:annotation:content-safety-v1'
      AND STRING(context.extendedData.contentSafetyAnnotation.adultContentLikelihood) = 'VERY_LIKELY'
  )
LIMIT 10;

如要篩選暴力內容或不同敏感程度的內容,請將 adultContentLikelihood 欄位替換為 violentContentLikelihood 欄位,或檢查 'LIKELY' 分級。

計算含有特定標籤的圖片數量

如要計算含有特定標籤的不重複圖片總數,且不重複計算符合多個標籤的圖片,請使用 COUNT(*) 搭配 EXISTS 子查詢:

SELECT
  COUNT(*) AS image_count
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t
WHERE
  EXISTS(
    SELECT 1
    FROM
      UNNEST(t.contexts) AS context,
      UNNEST(
        JSON_QUERY_ARRAY(
          context.extendedData.labelAnnotationGroup.labelAnnotations)) AS label
    WHERE
      context.key = 'google:annotation:label-detector-v1'
      AND LOWER(STRING(label.description)) = 'ristretto'
      AND FLOAT64(label.score) > 0.5
  );

擷取偵測到物件的定界框座標

object-detector 模型會偵測圖片中的實體物件,並提供正規化的定界多邊形 (boundingPoly),指出物件在影格中的位置。

下列查詢會擷取名為 Drink 的偵測物件,並建構頂層定界框座標欄 (x_min、y_min、x_max、y_max):

SELECT
  t.project,
  t.bucket,
  t.name,
  t.generation,
  STRING(object.name) AS object_name,
  FLOAT64(object.score) AS confidence_score,
  -- Calculate bounding box boundaries from normalized vertices
  (
    SELECT AS STRUCT
      MIN(FLOAT64(v.x)) AS x_min,
      MIN(FLOAT64(v.y)) AS y_min,
      MAX(FLOAT64(v.x)) AS x_max,
      MAX(FLOAT64(v.y)) AS y_max
    FROM
      UNNEST(JSON_QUERY_ARRAY(object.boundingPoly.normalizedVertices)) AS v
  ).*
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t,
  UNNEST(t.contexts) AS context,
  UNNEST(
    JSON_QUERY_ARRAY(
      context.extendedData.objectAnnotationGroup.objectAnnotations)) AS object
WHERE
  context.key = 'google:annotation:object-detector-v1'
  AND LOWER(STRING(object.name)) = 'drink'
  AND FLOAT64(object.score) > 0.5
LIMIT 10;

子查詢會計算每個多邊形的最小和最大正規化座標,而 .* 運算式會將 x_min、y_min、x_max 和 y_max 座標欄位直接解壓縮至結果集。

比對多個模型中的物件

Cloud Storage 會將各模型的擴充內容,附加為同一物件的獨立情境,因此您可以彙整多個模型的結果,找出高度特定的內容。

下列查詢會取消巢狀結構 contexts 兩次,找出 label-detector 模型分類為 Ristretto 的圖片,且圖片包含 object-detector 模型識別的本地化 Drink 物件:

SELECT
  t.project,
  t.bucket,
  t.name,
  t.generation,
  STRING(object.name) AS object_name,
  FLOAT64(object.score) AS object_score,
  STRING(label.description) AS label_description,
  FLOAT64(label.score) AS label_score,
  (
    SELECT AS STRUCT
      MIN(FLOAT64(v.x)) AS x_min,
      MIN(FLOAT64(v.y)) AS y_min,
      MAX(FLOAT64(v.x)) AS x_max,
      MAX(FLOAT64(v.y)) AS y_max
    FROM
      UNNEST(JSON_QUERY_ARRAY(object.boundingPoly.normalizedVertices)) AS v
  ).*
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t,
  -- Match the label detection context
  UNNEST(t.contexts) AS label_ctx,
  UNNEST(
    JSON_QUERY_ARRAY(
      label_ctx.extendedData.labelAnnotationGroup.labelAnnotations)) AS label,
  -- Match the object detection context on the same object
  UNNEST(t.contexts) AS object_ctx,
  UNNEST(
    JSON_QUERY_ARRAY(
      object_ctx.extendedData.objectAnnotationGroup.objectAnnotations)) AS object
WHERE
  label_ctx.key = 'google:annotation:label-detector-v1'
  AND LOWER(STRING(label.description)) = 'ristretto'
  AND FLOAT64(label.score) > 0.5
  AND object_ctx.key = 'google:annotation:object-detector-v1'
  AND LOWER(STRING(object.name)) = 'drink'
  AND FLOAT64(object.score) > 0.5
LIMIT 10;

依分類類別篩選 PDF 文件

pdf-classification 模型會將階層式類別 (例如 /Finance/Accounting & Auditing 或 /Law & Government/Legal Services) 指派給儲存的 PDF 文件。

下列查詢會找出分類在 /Finance 分支底下,且可信度分數大於 0.5 的 PDF 物件:

SELECT
  t.project,
  t.bucket,
  t.name,
  t.generation,
  STRING(category.label) AS category_name,
  FLOAT64(category.score) AS confidence_score
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t,
  UNNEST(t.contexts) AS context,
  UNNEST(
    JSON_QUERY_ARRAY(
      context.extendedData.pdfClassificationCategoryList.categories)) AS category
WHERE
  context.key = 'google:annotation:pdf-classification-v1'
  AND STARTS_WITH(STRING(category.label), '/Finance')
  AND FLOAT64(category.score) > 0.5
LIMIT 10;

如需支援的分類類別完整清單,請參閱「PDF 分類類別」。

依分類類別匯總 PDF 文件

如要分析封存檔中的文件分布情形,請依類別匯總及計算 PDF 物件:

SELECT
  STRING(category.label) AS category_name,
  COUNT(*) AS document_count
FROM
  `PROJECT_ID.DATASET_ID.object_contexts_catalog_view` AS t,
  UNNEST(t.contexts) AS context,
  UNNEST(
    JSON_QUERY_ARRAY(
      context.extendedData.pdfClassificationCategoryList.categories)) AS category
WHERE
  context.key = 'google:annotation:pdf-classification-v1'
GROUP BY
  category_name
ORDER BY
  document_count DESC
LIMIT 10;

對查詢結果採取行動

查詢中繼資料通常是自動化資料管理、法規遵循稽核或政策執行的第一步。在 BigQuery 中找出特定物件組合後,您可以將這些結果饋送至下游工作流程,如下所示:

  • 精選機器學習資料集:將查詢結果匯出至新的 BigQuery 資料表或 CSV 檔案,為自訂模型建立目標訓練和驗證集。
  • 隔離或移除違反政策的物件:將安全性查詢識別出的物件名稱和 bucket 位置,輸入儲存空間批次作業,將物件移至受限的隔離 bucket,或大量刪除。
  • 稽核內容分配情形並降低成本:彙整物件分類、維度和類別,瞭解整個機構的儲存空間分配情形,並建立目標生命週期管理規則。

後續步驟