Analisar enriquecimentos de objetos no BigQuery

Consultar enriquecimentos de objetos com SQL no BigQuery permite pesquisar, filtrar e analisar metadados em milhões de objetos armazenados sem inspecionar cada um individualmente.

Ao configurar conjuntos de dados do Storage Insights, o Cloud Storage exporta automaticamente o inventário e os metadados de objetos, incluindo os enriquecimentos de objetos gerados por modelos de IA, diretamente para o BigQuery. Esta página explica como o Cloud Storage estrutura os enriquecimentos de objetos no BigQuery. Ela também fornece receitas de SQL para encontrar rótulos, detectar rostos, identificar conteúdo explícito, extrair caixas delimitadoras e categorizar documentos PDF.

Ter os papéis necessários

Para receber as permissões necessárias para consultar enriquecimentos de objetos no BigQuery, peça ao administrador para conceder a você os seguintes papéis do IAM no seu projeto:

Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

Esses papéis predefinidos contêm as permissões necessárias para consultar enriquecimentos de objetos no BigQuery. Para acessar as permissões exatas que são necessárias, expanda a seção Permissões necessárias:

Permissões necessárias

As seguintes permissões são necessárias para consultar enriquecimentos de objetos no BigQuery:

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

Essas permissões também podem ser concedidas com papéis personalizados ou outros papéis predefinidos.

Como os enriquecimentos de objetos são integrados ao Storage Insights

Ao configurar um conjunto de dados do Storage Insights para seu projeto, o Cloud Storage exporta periodicamente o inventário de buckets e os contextos de objetos para um conjunto de dados do BigQuery.

No BigQuery, os dados aparecem na object_contexts_catalog_view visualização. Essa visualização fornece um catálogo unificado dos objetos armazenados. Cada linha contém atributos de objeto (project, bucket, name, generation) e uma matriz de registros contexts repetida:

  • contexts.key: o identificador de contexto exclusivo. Os enriquecimentos de machine learning gerados pelo Cloud Storage sempre começam com o google:annotation: prefixo (por exemplo, google:annotation:label-detector-v1 ou google:annotation:face-detector-v1).
  • contexts.value: o status de execução do modelo para o enriquecimento (como SUCCESS ou FAILURE).
  • contexts.extendedData: uma coluna JSON que contém o payload de enriquecimento do modelo, como rótulos detectados, pontos de referência faciais, vértices de polígonos e caminhos de categorias.

Para conferir a estrutura completa da tabela e as descrições das colunas, consulte o esquema do catálogo de contextos de objetos.

Entender padrões de consulta: UNNEST x EXISTS

Um objeto pode ter vários contextos, e cada modelo pode gerar várias detecções (como vários rótulos ou rostos detectados). Ao consultar a visualização object_contexts_catalog_view, geralmente você usa um dos seguintes padrões de SQL:

  • Linha por detecção (UNNEST): use o operador UNNEST na matriz de registros contexts repetida e na matriz JSON interna do modelo (usando a função JSON_QUERY_ARRAY). A desaninhamento nivela os enriquecimentos repetidos para que cada recurso detectado produza sua própria linha. Use essa abordagem quando precisar inspecionar rótulos individuais, extrair coordenadas de caixa delimitadora ou calcular estatísticas em detecções.
  • Linha por objeto (EXISTS): use uma subconsulta EXISTS correlacionada para testar se um objeto contém um rótulo, saída do modelo ou limite específico. Essa abordagem avalia contextos repetidos sem desaninhá-los na consulta externa. Ela retorna exatamente uma linha por objeto, independentemente de quantas detecções correspondam.

Exemplos de consultas

Os exemplos de SQL a seguir mostram como consultar e filtrar enriquecimentos de objetos para fluxos de trabalho comuns de análise e curadoria de dados.

Em cada consulta, substitua o seguinte:

  • PROJECT_ID: o ID do Google Cloud projeto.
  • DATASET_ID: o nome do conjunto de dados do BigQuery em que o Storage Insights exporta seus dados.

Encontrar imagens que contenham um rótulo específico

Para pesquisar imagens avaliadas pelo modelo label-detector, você pode retornar cada rótulo correspondente como uma linha individual ou retornar imagens exclusivas que contenham o rótulo.

Retornar rótulos correspondentes (linhas de nivelamento)

A consulta a seguir nivela as matrizes contexts e labelAnnotations para retornar uma linha separada para cada rótulo correspondente encontrado em uma imagem:

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;

Retornar imagens exclusivas (evita linhas duplicadas)

Se uma imagem contiver vários rótulos correspondentes, o desaninhamento produzirá várias linhas para esse objeto. Para retornar exatamente uma linha por imagem, verifique a existência do rótulo em uma subconsulta 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;

Encontrar fotos de retrato e selfie com um assunto sorrindo (detecção facial)

É possível combinar vários atributos faciais, como expressões emocionais, ângulos de orientação da cabeça e dimensões da caixa delimitadora, para encontrar tipos específicos de fotos.

A consulta a seguir usa uma expressão de tabela comum (CTE) para calcular a cobertura da caixa delimitadora facial. Ela filtra retratos sorrindo e voltados para a frente em que o assunto ocupa pelo menos 60% da imagem:

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;

Essa consulta aplica os seguintes filtros:

  • joy_probability > 0.5: seleciona rostos avaliados como expressando felicidade ou sorrindo.
  • BETWEEN -10 AND 10: restringe os ângulos de roll, pan e tilt para que o rosto fique orientado diretamente para a câmera.
  • face_coverage_percentage >= 0.60: usa vértices de polígonos normalizados (0.0 a 1.0) para filtrar rostos que ocupam 60% ou mais do frame.

Encontrar imagens que tenham marcadores de segurança de conteúdo

O modelo content-safety avalia imagens para conteúdo adulto e violento. O modelo atribui a cada categoria uma classificação de probabilidade, como VERY_UNLIKELY, UNLIKELY, POSSIBLE, LIKELY, ou VERY_LIKELY.

A consulta a seguir retorna imagens exclusivas que o modelo marca com alta confiança como conteúdo adulto:

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;

Para filtrar conteúdo violento ou sensibilidades diferentes, substitua o adultContentLikelihood campo pelo violentContentLikelihood campo ou verifique a classificação 'LIKELY' rating.

Contar imagens que contenham um rótulo específico

Para contar o número total de imagens exclusivas que contêm um rótulo específico sem contagem duplicada de imagens que correspondem a vários rótulos, use COUNT(*) com uma subconsulta 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
  );

Extrair coordenadas de caixa delimitadora para objetos detectados

O modelo object-detector detecta objetos físicos em uma imagem e fornece polígonos delimitadores normalizados (boundingPoly) que indicam onde o objeto aparece no frame.

A consulta a seguir extrai objetos detectados chamados Drink e constrói colunas de coordenadas de caixa delimitadora de nível superior (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;

A subconsulta calcula as coordenadas normalizadas mínimas e máximas para cada polígono, e a expressão .* descompacta os campos de coordenadas x_min, y_min, x_max e y_max diretamente no conjunto de resultados.

Corresponder objetos em vários modelos

Como o Cloud Storage anexa enriquecimentos de cada modelo como contextos independentes no mesmo objeto, é possível unir vários resultados de modelos para encontrar conteúdo altamente específico.

A consulta a seguir desaninha contexts duas vezes para encontrar imagens que o modelo label-detector classifica como Ristretto e que contêm um objeto Drink localizado identificado pelo modelo object-detector:

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;

Filtrar documentos PDF por categoria de classificação

O modelo pdf-classification atribui categorias hierárquicas (como /Finance/Accounting & Auditing ou /Law & Government/Legal Services) a documentos PDF armazenados.

A consulta a seguir encontra objetos PDF categorizados na ramificação /Finance com pontuações de confiança maiores que 0,5:

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;

Para conferir a lista completa de categorias de taxonomia compatíveis, consulte Categorias de classificação de PDF categories.

Agregar documentos PDF por categoria de classificação

Para analisar a distribuição de documentos no arquivo, agregue e conte os objetos PDF por categoria:

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;

Entre em ação nos resultados da consulta

A consulta de metadados geralmente é a primeira etapa na curadoria de dados automatizada, na auditoria de conformidade ou na aplicação de políticas. Depois de identificar conjuntos específicos de objetos no BigQuery, é possível alimentar esses resultados em fluxos de trabalho downstream, da seguinte maneira:

  • Curar conjuntos de dados de machine learning: exporte os resultados da consulta para uma nova tabela do BigQuery ou arquivo CSV para criar conjuntos de treinamento e conjuntos de validação direcionados para modelos personalizados.
  • Colocar em quarentena ou remover objetos que violam a política: alimente os nomes de objetos e os locais de buckets identificados por consultas de segurança em operações em lote do Storage para movê-los para buckets de quarentena restritos ou excluí-los em massa.
  • Auditar a distribuição de conteúdo e otimizar custos: agregue classificações, dimensões e categorias de objetos para entender a distribuição de armazenamento na sua organização e criar regras de gerenciamento do ciclo de vida direcionadas.

A seguir