Analiza los enriquecimientos de objetos en BigQuery

Consultar los enriquecimientos de objetos con SQL en BigQuery te permite buscar, filtrar y analizar metadatos en millones de objetos almacenados sin inspeccionar cada objeto de forma individual.

Cuando configuras conjuntos de datos de Storage Insights, Cloud Storage exporta automáticamente tu inventario de objetos y metadatos, incluidos los enriquecimientos de objetos generados por modelos de IA, directamente a BigQuery. En esta página, se explica cómo Cloud Storage estructura los enriquecimientos de objetos en BigQuery. También se proporcionan recetas de SQL para encontrar etiquetas, detectar rostros, identificar contenido explícito, extraer cuadros delimitadores y categorizar documentos PDF.

Obtén los roles necesarios

Para obtener los permisos que necesitas para consultar los enriquecimientos de objetos en BigQuery, pídele a tu administrador que te otorgue los siguientes roles de IAM en tu proyecto:

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

Estos roles predefinidos contienen los permisos necesarios para consultar los enriquecimientos de objetos en BigQuery. Para ver los permisos exactos que son necesarios, expande la sección Permisos requeridos:

Permisos necesarios

Se requieren los siguientes permisos para consultar los enriquecimientos de objetos en BigQuery:

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

También puedes obtener estos permisos con roles personalizados o otros roles predefinidos.

Cómo se integran los enriquecimientos de objetos con Storage Insights

Cuando configuras un conjunto de datos de Storage Insights para tu proyecto, Cloud Storage exporta periódicamente tu inventario de bucket y los contextos de objetos a un conjunto de datos de BigQuery.

En BigQuery, tus datos aparecen en la object_contexts_catalog_view vista. Esta vista proporciona un catálogo unificado de tus objetos almacenados. Cada fila contiene atributos de objeto (project, bucket, name, generation) y un array de registros contexts repetido:

  • contexts.key: Es el identificador de contexto único. Los enriquecimientos de aprendizaje automático generados por Cloud Storage siempre comienzan con el google:annotation: prefijo (por ejemplo, google:annotation:label-detector-v1 o google:annotation:face-detector-v1).
  • contexts.value: Es el estado de ejecución del modelo para el enriquecimiento (como SUCCESS o FAILURE).
  • contexts.extendedData: Es una columna JSON que contiene la carga útil de enriquecimiento del modelo, como etiquetas detectadas, puntos de referencia faciales, vértices de polígonos y rutas de acceso de categorías.

Para obtener la estructura completa de la tabla y las descripciones de las columnas, consulta el esquema del catálogo de contextos de objetos.

Comprende los patrones de consulta: UNNEST versus EXISTS

Un objeto puede tener varios contextos, y cada modelo puede generar varias detecciones (como varias etiquetas o rostros detectados). Cuando consultas la vista object_contexts_catalog_view, por lo general, usas uno de los siguientes patrones de SQL:

  • Fila por detección (UNNEST): Usa el operador UNNEST en el array de registros contexts repetido y el array JSON interno del modelo (con la función JSON_QUERY_ARRAY). La anidación aplana los enriquecimientos repetidos para que cada función detectada produzca su propia fila. Usa este enfoque cuando necesites inspeccionar etiquetas individuales, extraer coordenadas de cuadro delimitador o calcular estadísticas en las detecciones.
  • Fila por objeto (EXISTS): Usa una subconsulta EXISTS correlacionada para probar si un objeto contiene una etiqueta, un resultado del modelo o un umbral específicos. Este enfoque evalúa los contextos repetidos sin anidarlos en la consulta externa. Muestra exactamente una fila por objeto, independientemente de cuántas detecciones coincidan.

Ejemplos de consultas

En los siguientes ejemplos de SQL, se muestra cómo consultar y filtrar los enriquecimientos de objetos para los flujos de trabajo comunes de análisis y curación de datos.

En cada consulta, reemplaza lo siguiente:

  • PROJECT_ID: Es el ID de tu Google Cloud proyecto.
  • DATASET_ID: Es el nombre del conjunto de datos de BigQuery en el que Storage Insights exporta tus datos.

Encuentra imágenes que contengan una etiqueta específica

Para buscar imágenes evaluadas por el modelo label-detector, puedes mostrar cada etiqueta coincidente como una fila individual o mostrar imágenes únicas que contengan la etiqueta.

Muestra etiquetas coincidentes (aplana filas)

La siguiente consulta aplana los arrays contexts y labelAnnotations para mostrar una fila separada para cada etiqueta coincidente que se encuentre en una imagen:

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;

Muestra imágenes únicas (evita filas duplicadas)

Si una imagen contiene varias etiquetas coincidentes, la anidación produce varias filas para ese objeto. Para mostrar exactamente una fila por imagen, verifica la existencia de la etiqueta en una 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;

Encuentra fotos de retratos y selfies con un sujeto sonriente (detección de rostros)

Puedes combinar varios atributos faciales, como expresiones emocionales, ángulos de orientación de la cabeza y dimensiones de cuadro delimitador, para encontrar tipos específicos de fotos.

En la siguiente consulta, se usa una expresión de tabla común (CTE) para calcular la cobertura del cuadro delimitador de rostros. Se filtra para retratos sonrientes y frontales en los que el sujeto ocupa al menos el 60% de la imagen:

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;

Esta consulta aplica los siguientes filtros:

  • joy_probability > 0.5: Selecciona los rostros evaluados como expresiones de felicidad o sonrisas.
  • BETWEEN -10 AND 10: Restringe los ángulos roll, pan y tilt para que el rostro esté orientado directamente hacia la cámara.
  • face_coverage_percentage >= 0.60: Usa vértices de polígonos normalizados (0.0 a 1.0) para filtrar los rostros que ocupan el 60% o más del marco.

Encuentra imágenes que tengan marcas de seguridad de contenido

El modelo content-safety evalúa las imágenes en busca de contenido para adultos y violento. El modelo asigna a cada categoría una clasificación de probabilidad, como VERY_UNLIKELY, UNLIKELY, POSSIBLE, LIKELY, o VERY_LIKELY.

La siguiente consulta muestra imágenes únicas que el modelo marca con alta confianza como contenido para adultos:

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 contenido violento o diferentes sensibilidades, reemplaza el adultContentLikelihood campo por el violentContentLikelihood campo, o verifica la clasificación 'LIKELY' rating.

Cuenta las imágenes que contienen una etiqueta específica

Para contar la cantidad total de imágenes únicas que contienen una etiqueta específica sin registro duplicado de imágenes que coinciden con varias etiquetas, usa COUNT(*) con una 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
  );

Extrae las coordenadas del cuadro delimitador para los objetos detectados

El modelo object-detector detecta objetos físicos en una imagen y proporciona polígonos delimitadores normalizados (boundingPoly) que indican dónde aparece el objeto en el marco.

La siguiente consulta extrae los objetos detectados llamados Drink y construye columnas de coordenadas de cuadro delimitador de nivel 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;

La subconsulta calcula las coordenadas normalizadas mínimas y máximas para cada polígono, y la expresión .* descomprime los campos de coordenadas x_min, y_min, x_max y y_max directamente en el conjunto de resultados.

Haz coincidir objetos en varios modelos

Como Cloud Storage adjunta enriquecimientos de cada modelo como contextos independientes en el mismo objeto, puedes unir varios resultados del modelo para encontrar contenido muy específico.

La siguiente consulta anida contexts dos veces para encontrar imágenes que el modelo label-detector clasifica como Ristretto y que contienen un objeto Drink localizado identificado por el 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;

Filtra documentos PDF por categoría de clasificación

El modelo pdf-classification asigna categorías jerárquicas (como /Finance/Accounting & Auditing o /Law & Government/Legal Services) a los documentos PDF almacenados.

La siguiente consulta encuentra objetos PDF categorizados en la rama /Finance con puntuaciones de confianza superiores a 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 obtener la lista completa de las categorías de taxonomía admitidas, consulta Categorías de clasificación de PDF.

Agrega documentos PDF por categoría de clasificación

Para analizar la distribución de documentos en tu archivo, agrega y cuenta tus objetos PDF por categoría:

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;

Toma medidas en función de los resultados de la consulta

Consultar tus metadatos suele ser el primer paso en la curación de datos automatizada, la auditoría de cumplimiento o la aplicación de políticas. Después de identificar conjuntos específicos de objetos en BigQuery, puedes incorporar esos resultados en flujos de trabajo posteriores, de la siguiente manera:

  • Cura conjuntos de datos de aprendizaje automático: Exporta los resultados de tu consulta a una tabla de BigQuery o un archivo CSV nuevos para crear conjuntos de entrenamiento y validación segmentados para modelos personalizados.
  • Pon en cuarentena o quita objetos que infrinjan las políticas: Incorpora los nombres de los objetos y las ubicaciones de bucket identificados por las consultas de seguridad en las operaciones por lote en objetos almacenados para moverlos a buckets de cuarentena restringidos o borrarlos de forma masiva.
  • Audita la distribución de contenido y optimiza los costos: Agrega clasificaciones, dimensiones y categorías de objetos para comprender la distribución del almacenamiento en tu organización y crear reglas de administración del ciclo de vida segmentadas.

¿Qué sigue?