Analiza datos multimodales con SQL y Python
En este instructivo, se muestra cómo analizar datos multimodales con consultas en SQL y funciones definidas por el usuario (UDF) de Python.
En este instructivo, se usa el catálogo de productos del conjunto de datos públicos de la tienda de mascotas Cymbal.
Objetivos
- Usa valores de
ObjectRef
para almacenar datos de imágenes junto con datos estructurados en una tabla estándar de BigQuery. - Genera texto basado en datos de imágenes de una tabla estándar con la función
AI.GENERATE_TABLE
. - Transforma imágenes existentes para crear imágenes nuevas con una UDF de Python.
- Fragmentar PDFs para un análisis posterior con una UDF de Python
- Usa un modelo de Gemini y la función
ML.GENERATE_TEXT
para analizar los datos del PDF divididos en fragmentos. - Genera embeddings basados en datos de imágenes de una tabla estándar con la función
ML.GENERATE_EMBEDDING
. - Procesa datos multimodales ordenados con arrays de valores
ObjectRef
.
Costos
En este documento, usarás los siguientes componentes facturables de Google Cloud:
- BigQuery: you incur costs for the data that you process in BigQuery.
- BigQuery Python UDFs: you incur costs for using Python UDFs.
- Cloud Storage: you incur costs for the objects stored in Cloud Storage.
- Vertex AI: you incur costs for calls to Vertex AI models.
Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.
Para obtener más información, consulta las siguientes páginas de precios:
- Precios de BigQuery
- Precios de las UDF de Python de BigQuery
- Precios de Cloud Storage
- Precios de Vertex AI
Antes de comenzar
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
Enable the BigQuery, BigQuery Connection, Cloud Storage, and Vertex AI APIs.
Roles obligatorios
Si quieres obtener los permisos que necesitas para completar este instructivo, pídele a tu administrador que te otorgue los siguientes roles de IAM:
-
Crea una conexión:
Administrador de conexión de BigQuery (
roles/bigquery.connectionAdmin
) -
Otorga permisos a la cuenta de servicio de la conexión:
Administrador de IAM del proyecto (
roles/resourcemanager.projectIamAdmin
) -
Crea un bucket de Cloud Storage:
Administrador de almacenamiento (
roles/storage.admin
) -
Crea conjuntos de datos, modelos, UDF y tablas, y ejecuta trabajos de BigQuery:
Administrador de BigQuery (
roles/bigquery.admin
) -
Crea URLs que te permitan leer y modificar objetos de Cloud Storage:
Administrador de ObjectRef de BigQuery (
roles/bigquery.objectRefAdmin
)
Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.
También puedes obtener los permisos necesarios mediante roles personalizados o cualquier otro rol predefinido.
Configurar
En esta sección, crearás el conjunto de datos, la conexión, las tablas y los modelos que se usan en este instructivo.
Crea un conjunto de datos
Crea un conjunto de datos de BigQuery que contenga los objetos que crearás en este instructivo:
En la consola de Google Cloud , ve a la página BigQuery.
En el panel Explorador, selecciona tu proyecto.
Expande la opción Acciones
y haz clic en Crear conjunto de datos. Se abrirá el panel Crear conjunto de datos.En ID de conjunto de datos, ingresa
cymbal_pets
.Haz clic en Crear conjunto de datos.
Crea un bucket
Crea un bucket de Cloud Storage para almacenar objetos transformados:
Ve a la página Buckets.
Haz clic en
Crear.En la página Crear un bucket, en la sección Comenzar, ingresa un nombre único a nivel global que cumpla con los requisitos de nombres de buckets.
Haz clic en Crear.
Crear una conexión
Crea una conexión de recurso de Cloud y obtén la cuenta de servicio de la conexión. BigQuery usa la conexión para acceder a los objetos en Cloud Storage:
Ve a la página de BigQuery.
En el panel Explorador, haz clic en
Agregar datos.Se abrirá el diálogo Agregar datos.
En el panel Filtrar por, en la sección Tipo de fuente de datos, selecciona Aplicaciones empresariales.
También puedes ingresar
Vertex AI
en el campo Buscar fuentes de datos.En la sección Fuentes de datos destacadas, haz clic en Vertex AI.
Haz clic en la tarjeta de solución Vertex AI Models: BigQuery Federation.
En la lista Tipo de conexión, selecciona Modelos remotos de Vertex AI, funciones remotas y BigLake (Cloud Resource).
En el campo ID de conexión, escribe
cymbal_conn
.Haz clic en Crear conexión.
Haz clic en Ir a la conexión.
En el panel Información de conexión, copia el ID de la cuenta de servicio para usarlo en un paso siguiente.
Otorga permisos a la cuenta de servicio de las conexiones
Otorga a la cuenta de servicio de la conexión los roles adecuados para acceder a otros servicios. Debes otorgar estos roles en el mismo proyecto que creaste o seleccionaste en la sección Antes de comenzar. Si otorgas los roles en un proyecto diferente, se produce el error bqcx-1234567890-xxxx@gcp-sa-bigquery-condel.iam.gserviceaccount.com
does not have the permission to access resource
.
Otorga permisos en el bucket de Cloud Storage
Otorga a la cuenta de servicio acceso para usar objetos en el bucket que creaste:
Ve a la página Buckets.
Haz clic en el nombre del bucket que creaste.
Haz clic en Permisos.
Haz clic en
Grant access. Se abrirá el diálogo Otorgar acceso.En el campo Principales nuevas (New principals), ingresa el ID de la cuenta de servicio que copiaste antes.
En el campo Selecciona un rol, elige Cloud Storage y, luego, selecciona Usuario de objetos de Storage.
Haz clic en Guardar.
Otorga permisos para usar modelos de Vertex AI
Otorga a la cuenta de servicio acceso para usar los modelos de Vertex AI:
Ir a la página IAM y administración
Haz clic en
Grant access. Se abrirá el diálogo Otorgar acceso.En el campo Principales nuevas (New principals), ingresa el ID de la cuenta de servicio que copiaste antes.
En el campo Selecciona un rol, selecciona Vertex AI y, luego, Usuario de Vertex AI.
Haz clic en Guardar.
Crea las tablas de datos de ejemplo
Crea tablas para almacenar la información de los productos de mascotas de Cymbal.
Crea la tabla products
Crea una tabla estándar que contenga la información de los productos de mascotas de Cymbal:
En la consola de Google Cloud , ve a la página BigQuery.
En el editor de consultas, ejecuta la siguiente consulta para crear la tabla
products
:LOAD DATA OVERWRITE cymbal_pets.products FROM FILES( format = 'avro', uris = [ 'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/tables/products/products_*.avro']);
Crea la tabla product_images
Crea una tabla de objetos que contenga las imágenes de los productos de mascotas de Cymbal:
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla
product_images
:CREATE OR REPLACE EXTERNAL TABLE cymbal_pets.product_images WITH CONNECTION `us.cymbal_conn` OPTIONS ( object_metadata = 'SIMPLE', uris = ['gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/images/*.png'], max_staleness = INTERVAL 30 MINUTE, metadata_cache_mode = AUTOMATIC);
Crea la tabla product_manuals
Crea una tabla de objetos que contenga los manuales de productos de mascotas de Cymbal:
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla
product_manuals
:CREATE OR REPLACE EXTERNAL TABLE cymbal_pets.product_manuals WITH CONNECTION `us.cymbal_conn` OPTIONS ( object_metadata = 'SIMPLE', uris = ['gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/documents/*.pdf']);
Crea un modelo de generación de texto
Crea un modelo remoto de BigQuery ML que represente un modelo de Gemini de Vertex AI:
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear el modelo remoto:
CREATE OR REPLACE MODEL `cymbal_pets.gemini` REMOTE WITH CONNECTION `us.cymbal_conn` OPTIONS (ENDPOINT = 'gemini-2.0-flash');
Crea un modelo de generación de embeddings
Crea un modelo remoto de BigQuery ML que represente un modelo de incorporación multimodal de Vertex AI:
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear el modelo remoto:
CREATE OR REPLACE MODEL `cymbal_pets.embedding_model` REMOTE WITH CONNECTION `us.cymbal_conn` OPTIONS (ENDPOINT = 'multimodalembedding@001');
Crea una tabla products_mm
con datos multimodales
Crea una tabla products_mm
que contenga una columna image
propagada con imágenes de productos de la tabla de objetos product_images
. La columna image
que se crea es una columna de STRUCT
que usa el formato ObjectRef
.
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla
products_mm
y completar la columnaimage
:CREATE OR REPLACE TABLE cymbal_pets.products_mm AS SELECT products.* EXCEPT (uri), ot.ref AS image FROM cymbal_pets.products INNER JOIN cymbal_pets.product_images ot ON ot.uri = products.uri;
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para ver los datos de la columna
image
:SELECT product_name, image FROM cymbal_pets.products_mm`
Los resultados son similares a los siguientes:
+--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+ | product_name | image.uri | image.version | image.authorizer | image.details | +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+ | AquaClear Aquarium Background | gs://cloud-samples-data/bigquery/ | 1234567891011 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"image/png", | | | tutorials/cymbal-pets/images/ | | | "md5_hash":"494f63b9b137975ff3e7a11b060edb1d", | | | aquaclear-aquarium-background.png | | | "size":1282805,"updated":1742492680017000}} | +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+ | AquaClear Aquarium | gs://cloud-samples-data/bigquery/ | 2345678910112 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"image/png", | | Gravel Vacuum | tutorials/cymbal-pets/images/ | | | "md5_hash":"b7bfc2e2641a77a402a1937bcf0003fd", | | | aquaclear-aquarium-gravel-vacuum.png | | | "size":820254,"updated":1742492682411000}} | +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+ | ... | ... | ... | | ... | +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
Genera información del producto con un modelo de Gemini
Usa un modelo de Gemini para generar los siguientes datos de los productos de la tienda de mascotas:
- Agrega una columna
image_description
a la tablaproducts_mm
. - Completa las columnas
animal_type
,search_keywords
ysubcategory
de la tablaproducts_mm
. - Ejecuta una consulta que devuelva una descripción de cada marca de producto y un recuento de la cantidad de productos de esa marca. La descripción de la marca se genera analizando la información de todos los productos de esa marca, incluidas las imágenes de los productos.
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear y completar la columna
image_description
:CREATE OR REPLACE TABLE cymbal_pets.products_mm AS SELECT product_id, product_name, brand, category, subcategory, animal_type, search_keywords, price, description, inventory_level, supplier_id, average_rating, image, image_description FROM AI.GENERATE_TABLE( MODEL `cymbal_pets.gemini`, ( SELECT ('Can you describe the following image?', OBJ.GET_ACCESS_URL(image, 'r')) AS prompt, * FROM cymbal_pets.products_mm ), STRUCT('image_description STRING' AS output_schema));
En el editor de consultas de la página de BigQuery, ejecuta la siguiente consulta para actualizar las columnas
animal_type
,search_keywords
ysubcategory
con los datos generados:UPDATE cymbal_pets.products_mm p SET p.animal_type = s.animal_type, p.search_keywords = s.search_keywords, p.subcategory = s.subcategory FROM ( SELECT animal_type, search_keywords, subcategory, uri FROM AI.GENERATE_TABLE( MODEL `cymbal_pets.gemini`, ( SELECT ( 'For the image of a pet product, concisely generate the following metadata.' '1) animal_type and 2) 5 SEO search keywords, and 3) product subcategory', OBJ.GET_ACCESS_URL(image, 'r'), description) AS prompt, image.uri AS uri, FROM cymbal_pets.products_mm ), STRUCT( 'animal_type STRING, search_keywords ARRAY<STRING>, subcategory STRING' AS output_schema, 100 AS max_output_tokens)) ) s WHERE p.image.uri = s.uri;
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para ver los datos generados:
SELECT product_name, image_description, animal_type, search_keywords, subcategory, FROM cymbal_pets.products_mm;
Los resultados son similares a los siguientes:
+--------------------------------+-------------------------------------+-------------+------------------------+------------------+ | product_name | image.description | animal_type | search_keywords | subcategory | +--------------------------------+-------------------------------------+-------------+------------------------+------------------+ | AquaClear Aquarium Background | The image shows a colorful coral | fish | aquarium background | aquarium decor | | | reef backdrop. The background is a | | fish tank backdrop | | | | blue ocean with a bright light... | | coral reef decor | | | | | | underwater scenery | | | | | | aquarium decoration | | +--------------------------------+-------------------------------------+-------------+------------------------+------------------+ | AquaClear Aquarium | The image shows a long, clear | fish | aquarium gravel vacuum | aquarium | | Gravel Vacuum | plastic tube with a green hose | | aquarium cleaning | cleaning | | | attached to one end. The tube... | | aquarium maintenance | | | | | | fish tank cleaning | | | | | | gravel siphon | | +--------------------------------+-------------------------------------+-------------+------------------------+------------------+ | ... | ... | ... | ... | ... | +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
En el editor de consultas de la página de BigQuery, ejecuta la siguiente consulta para generar una descripción de cada marca de producto y un recuento de la cantidad de productos de esa marca:
SELECT brand, brand_description, cnt FROM AI.GENERATE_TABLE( MODEL `cymbal_pets.gemini`, ( SELECT brand, COUNT(*) AS cnt, ( 'Use the images and text to give one concise brand description for a website brand page.' 'Return the description only.', ARRAY_AGG(OBJ.GET_ACCESS_URL(image, 'r')), ARRAY_AGG(description), ARRAY_AGG(category), ARRAY_AGG(subcategory)) AS prompt FROM cymbal_pets.products_mm GROUP BY brand ), STRUCT('brand_description STRING' AS output_schema)) ORDER BY cnt DESC;
Los resultados son similares a los siguientes:
+--------------+-------------------------------------+-----+ | brand | brand.description | cnt | +--------------+-------------------------------------+-----+ | AquaClear | AquaClear is a brand of aquarium | 33 | | | and pond care products that offer | | | | a wide range of solutions for... | | +--------------+-------------------------------------+-----+ | Ocean | Ocean Bites is a brand of cat food | 28 | | Bites | that offers a variety of recipes | | | | and formulas to meet the specific.. | | +--------------+-------------------------------------+-----+ | ... | ... |... | +--------------+-------------------------------------+-----+
Crea una UDF de Python para transformar imágenes de productos
Crea una UDF de Python para convertir imágenes de productos a escala de grises.
La UDF de Python usa bibliotecas de código abierto y también ejecución paralela para transformar varias imágenes de forma simultánea.
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la UDF
to_grayscale
:CREATE OR REPLACE FUNCTION cymbal_pets.to_grayscale(src_json STRING, dst_json STRING) RETURNS STRING LANGUAGE python WITH CONNECTION `us.cymbal_conn` OPTIONS (entry_point='to_grayscale', runtime_version='python-3.11', packages=['numpy', 'opencv-python']) AS """ import cv2 as cv import numpy as np from urllib.request import urlopen, Request import json # Transform the image to grayscale. def to_grayscale(src_ref, dst_ref): src_json = json.loads(src_ref) srcUrl = src_json["access_urls"]["read_url"] dst_json = json.loads(dst_ref) dstUrl = dst_json["access_urls"]["write_url"] req = urlopen(srcUrl) arr = np.asarray(bytearray(req.read()), dtype=np.uint8) img = cv.imdecode(arr, -1) # 'Load it as it is' # Convert the image to grayscale gray_image = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # Send POST request to the URL _, img_encoded = cv.imencode('.png', gray_image) req = Request(url=dstUrl, data=img_encoded.tobytes(), method='PUT', headers = { "Content-Type": "image/png", }) with urlopen(req) as f: pass return dst_ref """;
Transforma imágenes de productos
Crea la tabla products_grayscale
con una columna ObjectRef
que contenga las rutas de destino y los autorizadores para las imágenes en escala de grises. La ruta de destino se deriva de la ruta de la imagen original.
Después de crear la tabla, ejecuta la función to_grayscale
para crear las imágenes en escala de grises, escribirlas en un bucket de Cloud Storage y, luego, devolver valores de ObjectRefRuntime
que contengan URLs de acceso y metadatos para las imágenes en escala de grises.
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla
products_grayscale
:CREATE OR REPLACE TABLE cymbal_pets.products_grayscale AS SELECT product_id, product_name, image, OBJ.MAKE_REF( CONCAT('gs://BUCKET/cymbal-pets-images/grayscale/', REGEXP_EXTRACT(image.uri, r'([^/]+)$')), 'us.cymbal_conn') AS gray_image FROM cymbal_pets.products_mm;
Reemplaza
BUCKET
por el nombre del bucket que creaste.En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear las imágenes en escala de grises, escribirlas en un bucket de Cloud Storage y, luego, devolver valores de
ObjectRefRuntime
que contengan URLs de acceso y metadatos para las imágenes en escala de grises:SELECT cymbal_pets.to_grayscale( TO_JSON_STRING(OBJ.GET_ACCESS_URL(image, 'r')), TO_JSON_STRING(OBJ.GET_ACCESS_URL(gray_image, 'rw'))) FROM cymbal_pets.products_grayscale;
Los resultados son similares a los siguientes:
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | f0 | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | {"access_urls":{"expiry_time":"2025-04-26T03:00:48Z", | | "read_url":"https://storage.googleapis.com/mybucket/cymbal-pets-images%2Fgrayscale%2Focean-bites-salmon-%26-tuna-cat-food.png?additional_read URL_information", | | "write_url":"https://storage.googleapis.com/myproject/cymbal-pets-images%2Fgrayscale%2Focean-bites-salmon-%26-tuna-cat-food.png?additional_write URL_information"}, | | "objectref":{"authorizer":"myproject.region.myconnection","uri":"gs://myproject/cymbal-pets-images/grayscale/ocean-bites-salmon-&-tuna-cat-food.png"}} | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | {"access_urls":{"expiry_time":"2025-04-26T03:00:48Z", | | "read_url":"https://storage.googleapis.com/mybucket/cymbal-pets-images%2Fgrayscale%2Ffluffy-buns-guinea-pig-tunnel.png?additional _read URL_information", | | "write_url":"https://storage.googleapis.com/myproject/cymbal-pets-images%2Fgrayscale%2Focean-bites-salmon-%26-tuna-cat-food.png?additional_write_URL_information"}, | | "objectref":{"authorizer":"myproject.region.myconnection","uri":"gs://myproject/cymbal-pets-images%2Fgrayscale%2Ffluffy-buns-guinea-pig-tunnel.png"}} | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | ... | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
Crea una UDF de Python para dividir los datos de PDF en fragmentos
Crea una UDF de Python para dividir en fragmentos los objetos PDF que contienen los manuales de productos de mascotas de Cymbal en varias partes.
Los PDFs suelen ser muy grandes y es posible que no quepan en una sola llamada a un modelo de IA generativa. Si divides los PDFs en fragmentos, puedes almacenar los datos en un formato listo para el modelo y facilitar el análisis.
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la UDF
chunk_pdf
:-- This function chunks the product manual PDF into multiple parts. -- The function accepts an ObjectRefRuntime value for the PDF file and the chunk size. -- It then parses the PDF, chunks the contents, and returns an array of chunked text. CREATE OR REPLACE FUNCTION cymbal_pets.chunk_pdf(src_json STRING, chunk_size INT64, overlap_size INT64) RETURNS ARRAY<STRING> LANGUAGE python WITH CONNECTION `us.cymbal_conn` OPTIONS (entry_point='chunk_pdf', runtime_version='python-3.11', packages=['pypdf']) AS """ import io import json from pypdf import PdfReader # type: ignore from urllib.request import urlopen, Request def chunk_pdf(src_ref: str, chunk_size: int, overlap_size: int) -> str: src_json = json.loads(src_ref) srcUrl = src_json["access_urls"]["read_url"] req = urlopen(srcUrl) pdf_file = io.BytesIO(bytearray(req.read())) reader = PdfReader(pdf_file, strict=False) # extract and chunk text simultaneously all_text_chunks = [] curr_chunk = "" for page in reader.pages: page_text = page.extract_text() if page_text: curr_chunk += page_text # split the accumulated text into chunks of a specific size with overlaop # this loop implements a sliding window approach to create chunks while len(curr_chunk) >= chunk_size: split_idx = curr_chunk.rfind(" ", 0, chunk_size) if split_idx == -1: split_idx = chunk_size actual_chunk = curr_chunk[:split_idx] all_text_chunks.append(actual_chunk) overlap = curr_chunk[split_idx + 1 : split_idx + 1 + overlap_size] curr_chunk = overlap + curr_chunk[split_idx + 1 + overlap_size :] if curr_chunk: all_text_chunks.append(curr_chunk) return all_text_chunks """;
Analiza datos de PDF
Ejecuta la función chunk_pdf
para dividir los datos del PDF en la tabla product_manuals
y, luego, crea una tabla product_manual_chunk_strings
que contenga un fragmento de PDF por fila. Usar un modelo de Gemini en los datos de product_manual_chunk_strings
para resumir la información legal que se encuentra en los manuales del producto
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla
product_manual_chunk_strings
:CREATE OR REPLACE TABLE cymbal_pets.product_manual_chunk_strings AS SELECT chunked FROM cymbal_pets.product_manuals, UNNEST (cymbal_pets.chunk_pdf( TO_JSON_STRING( OBJ.GET_ACCESS_URL(OBJ.MAKE_REF(uri, 'us.cymbal_conn'), 'r')), 1000, 100 )) as chunked;
En el editor de consultas de la página de BigQuery, ejecuta la siguiente consulta para analizar los datos del PDF con un modelo de Gemini:
SELECT ml_generate_text_llm_result FROM ML.GENERATE_TEXT( MODEL `cymbal_pets.gemini`, ( SELECT ( 'Can you summarize the product manual as bullet points? Highlight the legal clauses', chunked) AS prompt, FROM cymbal_pets.product_manual_chunk_strings ), STRUCT( TRUE AS FLATTEN_JSON_OUTPUT));
Los resultados son similares a los siguientes:
+-------------------------------------------------------------------------------------------------------------------------------------------+ | ml_generate_text_llm_result | +-------------------------------------------------------------------------------------------------------------------------------------------+ | ## CritterCuisine Pro 5000 Automatic Pet Feeder Manual Summary: | | | | **Safety:** | | | | * **Stability:** Place feeder on a level, stable surface to prevent tipping. | | * **Power Supply:** Only use the included AC adapter. Using an incompatible adapter can damage the unit and void the warranty. | | * **Cord Safety:** Keep the power cord out of reach of pets to prevent chewing or entanglement. | | * **Children:** Supervise children around the feeder. This is not a toy. | | * **Pet Health:** Consult your veterinarian before using an automatic feeder if your pet has special dietary needs, health conditions, or | +-------------------------------------------------------------------------------------------------------------------------------------------+ | ## Product Manual Summary: | | | | **6.3 Manual Feeding:** | | | | * Press MANUAL button to dispense a single portion (Meal 1 size). **(Meal Enabled)** | | | | **6.4 Recording a Voice Message:** | | | | * Press and hold VOICE button. | | * Speak clearly into the microphone (up to 10 seconds). | | * Release VOICE button to finish recording. | | * Briefly press VOICE button to play back the recording. | | * To disable the voice message, record a blank message (hold VOICE button for 10 seconds without speaking). **(Meal Enabled)** | | | | **6.5 Low Food Level Indicator:** | +-------------------------------------------------------------------------------------------------------------------------------------------+ | ... | +-------------------------------------------------------------------------------------------------------------------------------------------+
Genera embeddings y realiza una búsqueda vectorial
Generar embeddings a partir de datos de imágenes y, luego, usar los embeddings para devolver imágenes similares con la búsqueda de vectores
En un entorno de producción, te recomendamos que crees un índice de vectores antes de ejecutar una búsqueda de vectores. Un índice vectorial te permite realizar la búsqueda vectorial más rápido, con la compensación de reducir la recuperación y, de esa forma, mostrar resultados más aproximados.
En el editor de consultas de la página BigQuery, ejecuta la siguiente consulta para crear la tabla
products_embeddings
:CREATE OR REPLACE TABLE cymbal_pets.products_embedding AS SELECT product_id, ml_generate_embedding_result as embedding, content as image FROM ML.GENERATE_EMBEDDING( MODEL `cymbal_pets.embedding_model`, ( SELECT OBJ.GET_ACCESS_URL(image, 'r') as content, image, product_id FROM cymbal_pets.products_mm ), STRUCT () );
En el editor de consultas de la página de BigQuery, ejecuta la siguiente consulta para realizar una búsqueda de vectores y devolver imágenes de productos similares a la imagen de entrada proporcionada:
SELECT * FROM VECTOR_SEARCH( TABLE cymbal_pets.products_embedding, 'embedding', (SELECT ml_generate_embedding_result as embedding FROM ML.GENERATE_EMBEDDING( MODEL `cymbal_pets.embedding_model`, (SELECT OBJ.FETCH_METADATA(OBJ.MAKE_REF('gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/images/cozy-naps-cat-scratching-post-with-condo.png', 'us.cymbal_conn')) as content) )) );
Los resultados son similares a los siguientes:
+-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+ | query.embedding | base.product_id | base.embedding | base.image.uri | base.image.version | base.image.authorizer | base.image.details | distance | +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+ | -0.0112330541 | 181 | -0.0112330541 | gs://cloud-samples-data/bigquery/ | 12345678910 | myproject.region.myconnection | {"gcs_metadata":{"content_type": | 0.0 | | 0.0142525584 | | 0.0142525584 | tutorials/cymbal-pets/images/ | | | "image/png","md5_hash":"21234567hst16555w60j", | | | 0.0135886827 | | 0.0135886827 | cozy-naps-cat-scratching-post-with-condo.png | | | "size":828318,"updated":1742492688982000}} | | | 0.0149955815 | | 0.0149955815 | | | | | | | ... | | ... | | | | | | | | | | | | | | | | | | | | | | | | +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+ | -0.0112330541 | 187 | -0.0190353896 | gs://cloud-samples-data/bigquery/ | 23456789101 | myproject.region.myconnection | {"gcs_metadata":{"content_type": | 0.4216330832.. | | 0.0142525584 | | 0.0116206668 | tutorials/cymbal-pets/images/ | | | "image/png","md5_hash":"7328728fhakd9937djo4", | | | 0.0135886827 | | 0.0136198215 | cozy-naps-cat-scratching-post-with-bed.png | | | "size":860113,"updated":1742492688774000}} | | | 0.0149955815 | | 0.0173457414 | | | | | | | ... | | ... | | | | | | | | | | | | | | | | | | | | | | | | +---------C--------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+ | ... | ... | ... | ... | ... | ... | ... | ... | +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
Procesa datos multimodales ordenados con arrays de valores de ObjectRef
En esta sección, se muestra cómo completar las siguientes tareas:
- Vuelve a crear la tabla
product_manuals
para que contenga un archivo PDF del manual del productoCrittercuisine 5000
y archivos PDF de cada página de ese manual. - Crea una tabla que asigne el manual a sus fragmentos. El valor
ObjectRef
que representa el manual completo se almacena en una columnaSTRUCT<uri STRING, version STRING, authorizer STRING, details JSON>>
. Los valores deObjectRef
que representan las páginas manuales se almacenan en una columnaARRAY<STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>>
. - Analiza un array de valores
ObjectRef
en conjunto para devolver un solo valor generado. - Analiza un array de valores de
ObjectRef
por separado y devuelve un valor generado para cada valor del array.
Como parte de las tareas de análisis, conviertes el array de valores ObjectRef
en una lista ordenada de valores ObjectRefRuntime
y, luego, pasas esa lista a un modelo de Gemini, especificando los valores ObjectRefRuntime
como parte de la instrucción. Los valores de ObjectRefRuntime
proporcionan URLs firmadas que el modelo usa para acceder a la información del objeto en Cloud Storage.
Sigue estos pasos para procesar datos multimodales ordenados con arrays de valores de ObjectRef
:
Ve a la página de BigQuery.
En el editor de consultas, ejecuta la siguiente consulta para volver a crear la tabla
product_manuals
:CREATE OR REPLACE EXTERNAL TABLE `cymbal_pets.product_manuals` WITH CONNECTION `us.cymbal_conn` OPTIONS ( object_metadata = 'SIMPLE', uris = [ 'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/documents/*.pdf', 'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/document_chunks/*.pdf']);
En el editor de consultas, ejecuta la siguiente consulta para escribir datos de PDF en la tabla
map_manual_to_chunks
:-- Extract the file and chunks into a single table. -- Store the chunks in the chunks column as array of ObjectRefs (ordered by page number) CREATE OR REPLACE TABLE cymbal_pets.map_manual_to_chunks AS SELECT ARRAY_AGG(m1.ref)[0] manual, ARRAY_AGG(m2.ref ORDER BY m2.ref.uri) chunks FROM cymbal_pets.product_manuals m1 JOIN cymbal_pets.product_manuals m2 ON REGEXP_EXTRACT(m1.uri, r'.*/([^.]*).[^/]+') = REGEXP_EXTRACT(m2.uri, r'.*/([^.]*)_page[0-9]+.[^/]+') GROUP BY m1.uri;
En el editor de consultas, ejecuta la siguiente consulta para ver los datos del PDF en la tabla
map_manual_to_chunks
:SELECT * FROM cymbal_pets.map_manual_to_chunks;
Los resultados son similares a los siguientes:
+-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+ | manual.uri | manual.version | manual.authorizer | manual.details | chunks.uri | chunks.version | chunks.authorizer | chunks.details | +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+ | gs://cloud-samples-data/bigquery/ | 1742492785900455 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"application/pef", | gs://cloud-samples-data/bigquery/ | 1745875761227129 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"application/pdf", | | tutorials/cymbal-pets/documents/ | | | "md5_hash":"c9032b037693d15a33210d638c763d0e", | tutorials/cymbal-pets/documents/ | | | "md5_hash":"5a1116cce4978ec1b094d8e8b49a1d7c", | | crittercuisine_5000_user_manual.pdf | | | "size":566105,"updated":1742492785941000}} | crittercuisine_5000_user_manual_page1.pdf | | | "size":504583,"updated":1745875761266000}} | | | | | +-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+ | | | | | crittercuisine_5000_user_manual_page1.pdf | 1745875760613874 | myproject.region.myconnection | {"gcs_metadata":{"content_type":"application/pdf", | | | | | | tutorials/cymbal-pets/documents/ | | | "md5_hash":"94d03ec65d28b173bc87eac7e587b325", | | | | | | crittercuisine_5000_user_manual_page2.pdf | | | "size":94622,"updated":1745875760649000}} | | | | | +-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+ | | | | | ... | ... | ... | ... | +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
En el editor de consultas, ejecuta la siguiente consulta para generar una sola respuesta de un modelo de Gemini basada en el análisis de un array de valores de
ObjectRef
:WITH manuals AS ( SELECT OBJ.GET_ACCESS_URL(manual, 'r') AS manual, ARRAY( SELECT OBJ.GET_ACCESS_URL(chunk, 'r') AS chunk FROM UNNEST(m1.chunks) AS chunk WITH OFFSET AS idx ORDER BY idx ) AS chunks FROM cymbal_pets.map_manual_to_chunks AS m1 ) SELECT ml_generate_text_llm_result AS Response FROM ML.GENERATE_TEXT( MODEL `cymbal_pets.gemini`, ( SELECT ( 'Can you provide a page by page summary for the first 3 pages of the attached manual? Only write one line for each page. The pages are provided in serial order', manuals.chunks) AS prompt, FROM manuals ), STRUCT(TRUE AS FLATTEN_JSON_OUTPUT));
Los resultados son similares a los siguientes:
+-------------------------------------------+ | Response | +-------------------------------------------+ | Page 1: This manual is for the | | CritterCuisine Pro 5000 automatic | | pet feeder. | | Page 2: The manual covers safety | | precautions, what's included, | | and product overview. | | Page 3: The manual covers assembly, | | initial setup, and programming the clock. | +-------------------------------------------+
En el editor de consultas, ejecuta la siguiente consulta para generar varias respuestas a partir de un modelo de Gemini en función del análisis de un array de valores de
ObjectRef
:WITH input_chunked_objrefs AS ( SELECT row_id, offset, chunk_ref FROM ( SELECT ROW_NUMBER() OVER () AS row_id, * FROM `cymbal_pets.map_manual_to_chunks` ) AS indexed_table LEFT JOIN UNNEST(indexed_table.chunks) AS chunk_ref WITH OFFSET ), get_access_urls AS ( SELECT row_id, offset, chunk_ref, OBJ.GET_ACCESS_URL(chunk_ref, 'r') AS ObjectRefRuntime FROM input_chunked_objrefs ), valid_get_access_urls AS ( SELECT * FROM get_access_urls WHERE ObjectRefRuntime['runtime_errors'] IS NULL ), ordered_output_objrefruntime_array AS ( SELECT ARRAY_AGG(ObjectRefRuntime ORDER BY offset) AS ObjectRefRuntimeArray FROM valid_get_access_urls GROUP BY row_id ) SELECT page1_summary, page2_summary, page3_summary FROM AI.GENERATE_TABLE( MODEL `cymbal_pets.gemini`, ( SELECT ( 'Can you provide a page by page summary for the first 3 pages of the attached manual? Only write one line for each page. The pages are provided in serial order', ObjectRefRuntimeArray) AS prompt, FROM ordered_output_objrefruntime_array ), STRUCT( 'page1_summary STRING, page2_summary STRING, page3_summary STRING' AS output_schema));
Los resultados son similares a los siguientes:
+-----------------------------------------------+-------------------------------------------+----------------------------------------------------+ | page1_summary | page2_summary | page3_summary | +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+ | This manual provides an overview of the | This section explains how to program | This page covers connecting the feeder to Wi-Fi | | CritterCuisine Pro 5000 automatic pet feeder, | the feeder's clock, set feeding | using the CritterCuisine Connect app, remote | | including its features, safety precautions, | schedules, copy and delete meal settings, | feeding, managing feeding schedules, viewing | | assembly instructions, and initial setup. | manually feed your pet, record | feeding logs, receiving low food alerts, | | | a voice message, and understand | updating firmware, creating multiple pet profiles, | | | the low food level indicator. | sharing access with other users, and cleaning | | | | and maintaining the feeder. | +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
Limpia
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.