SQL と Python を使用してマルチモーダル データを分析する

このチュートリアルでは、SQL クエリと Python ユーザー定義関数(UDF)を使用してマルチモーダル データを分析する方法について説明します。

このチュートリアルでは、一般公開されている Cymbal ペットショップ データセットの商品カタログを使用します。

目標

  • ObjectRef 値を使用して、BigQuery の標準テーブルに構造化データとともに画像データを保存します。
  • AI.GENERATE_TABLE 関数を使用して、標準テーブルの画像データに基づいてテキストを生成します。
  • Python UDF を使用して既存の画像を変換し、新しい画像を作成します。
  • Python UDF を使用して PDF をチャンク化し、詳細な分析を行います。
  • Gemini モデルと ML.GENERATE_TEXT 関数を使用して、チャンク化された PDF データを分析します。
  • ML.GENERATE_EMBEDDING 関数を使用して、標準テーブルの画像データに基づいてエンベディングを生成します。
  • ObjectRef 値の配列を使用して、順序付きマルチモーダル データを処理します。

料金

このドキュメントでは、課金対象である次の Trusted Cloud by S3NSコンポーネントを使用します。

  • 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.

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新規の Trusted Cloud ユーザーは無料トライアルをご利用いただける場合があります。

詳細については、次の料金ページをご覧ください。

始める前に

  1. In the Trusted Cloud console, on the project selector page, select or create a Trusted Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Trusted Cloud project.

  3. Enable the BigQuery, BigQuery Connection, Cloud Storage, and Vertex AI APIs.

    Enable the APIs

必要なロール

このチュートリアルを完了するために必要な権限を取得するには、管理者に次の IAM ロールを付与するよう依頼してください。

ロールの付与については、プロジェクト、フォルダ、組織に対するアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

設定

このセクションでは、このチュートリアルで使用するデータセット、接続、テーブル、モデルを作成します。

データセットを作成する

このチュートリアルで作成するオブジェクトを含む BigQuery データセットを作成します。

  1. Trusted Cloud コンソールで、[BigQuery] ページに移動します。

    BigQuery に移動

  2. [エクスプローラ] ペインでプロジェクトを選択します。

  3. [ アクション] オプションを開き、[データセットを作成] をクリックします。[データセットを作成] ペインが開きます。

  4. [データセット ID] に「cymbal_pets」と入力します。

  5. [データセットを作成] をクリックします。

バケットの作成

変換されたオブジェクトを保存する Cloud Storage バケットを作成します。

  1. [バケット] ページに移動します。

    [バケット] に移動

  2. [ 作成] をクリックします。

  3. [バケットの作成] ページの [始める] セクションで、バケット名の要件を満たすグローバルに一意の名前を入力します。

  4. [作成] をクリックします。

接続を作成する

クラウド リソース接続を作成し、接続のサービス アカウントを取得します。BigQuery は、この接続を使用して Cloud Storage 内のオブジェクトにアクセスします。

  1. [BigQuery] ページに移動します。

    BigQuery に移動

  2. [エクスプローラ] ペインで、 [データを追加] をクリックします。

    [データを追加] ダイアログが開きます。

  3. [フィルタ条件] ペインの [データソースのタイプ] セクションで、[ビジネス アプリケーション] を選択します。

    または、[データソースを検索] フィールドに「Vertex AI」と入力します。

  4. [特徴量データソース] セクションで、[Vertex AI] をクリックします。

  5. [Vertex AI モデル: BigQuery フェデレーション] ソリューション カードをクリックします。

  6. [接続タイプ] リストで、[Vertex AI リモートモデル、リモート関数、BigLake(Cloud リソース)] を選択します。

  7. [接続 ID] フィールドに「cymbal_conn」と入力します。

  8. [接続を作成] をクリックします。

  9. [接続へ移動] をクリックします。

  10. [接続情報] ペインで、次の手順で使用するサービス アカウント ID をコピーします。

接続のサービス アカウントに権限を付与する

他のサービスにアクセスするために、接続のサービス アカウントに適切なロールを付与します。これらのロールは、始める前にで作成または選択したプロジェクトで付与する必要があります。別のプロジェクトでロールを付与すると、bqcx-1234567890-xxxx@gcp-sa-bigquery-condel.s3ns-system.iam.gserviceaccount.com does not have the permission to access resource エラーが発生します。

Cloud Storage バケットに対する権限を付与する

作成したバケット内のオブジェクトを使用するためのアクセス権をサービス アカウントに付与します。

  1. [バケット] ページに移動します。

    [バケット] に移動

  2. 作成したバケットの名前をクリックします。

  3. [権限] をクリックします。

  4. [アクセスを許可] をクリックします。[アクセス権を付与] ダイアログが開きます。

  5. [新しいプリンシパル] フィールドに、前の手順でコピーしたサービス アカウント ID を入力します。

  6. [ロールを選択] フィールドで、[Cloud Storage] を選択し、[Storage オブジェクト ユーザー] を選択します。

  7. [保存] をクリックします。

Vertex AI モデルを使用する権限を付与する

Vertex AI モデルを使用するアクセス権をサービス アカウントに付与します。

  1. [IAM と管理] ページに移動します。

    [IAM と管理] に移動

  2. [アクセスを許可] をクリックします。[アクセス権を付与] ダイアログが開きます。

  3. [新しいプリンシパル] フィールドに、前の手順でコピーしたサービス アカウント ID を入力します。

  4. [ロールを選択] フィールドで、[Vertex AI] を選択し、[Vertex AI ユーザー] を選択します。

  5. [保存] をクリックします。

サンプルデータのテーブルを作成する

Cymbal ペット商品情報を格納するテーブルを作成します。

products テーブルを作成する

Cymbal ペット商品情報を含む標準テーブルを作成します。

  1. Trusted Cloud コンソールで、[BigQuery] ページに移動します。

    BigQuery に移動

  2. クエリエディタで、次のクエリを実行して products テーブルを作成します。

    LOAD DATA OVERWRITE cymbal_pets.products
    FROM
      FILES(
        format = 'avro',
        uris = [
          'gs://cloud-samples-data/bigquery/tutorials/cymbal-pets/tables/products/products_*.avro']);

product_images テーブルを作成する

Cymbal ペット商品の画像を含むオブジェクト テーブルを作成します。

  • [BigQuery] ページのクエリエディタで、次のクエリを実行して 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);

product_manuals テーブルを作成する

Cymbal ペット製品のマニュアルを含むオブジェクト テーブルを作成します。

  • [BigQuery] ページのクエリエディタで、次のクエリを実行して 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']);

テキスト生成モデルを作成する

Vertex AI Gemini モデルを表す BigQuery ML リモートモデルを作成します。

  • [BigQuery] ページのクエリエディタで、次のクエリを実行してリモートモデルを作成します。

    CREATE OR REPLACE MODEL `cymbal_pets.gemini`
      REMOTE WITH CONNECTION `us.cymbal_conn`
      OPTIONS (ENDPOINT = 'gemini-2.0-flash');

エンベディング生成モデルを作成する

Vertex AI マルチモーダル エンベディング モデルを表す BigQuery ML リモートモデルを作成します。

  • [BigQuery] ページのクエリエディタで、次のクエリを実行してリモートモデルを作成します。

    CREATE OR REPLACE MODEL `cymbal_pets.embedding_model`
      REMOTE WITH CONNECTION `us.cymbal_conn`
      OPTIONS (ENDPOINT = 'multimodalembedding@001');

マルチモーダル データを含む products_mm テーブルを作成する

product_images オブジェクト テーブルの商品画像が入力された image 列を含む products_mm テーブルを作成します。作成される image 列は、ObjectRef 形式を使用する STRUCT 列です。

  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して products_mm テーブルを作成し、image 列にデータを入力します。

    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;
  2. [BigQuery] ページのクエリエディタで、次のクエリを実行して image 列データを表示します。

    SELECT product_name, image
    FROM cymbal_pets.products_mm`

    結果は次のようになります。

    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    | 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}}     |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    | ...                            | ...                                  | ...           |                               | ...                                            |
    +--------------------------------+--------------------------------------+-----------------------------------------------+------------------------------------------------+
    

Gemini モデルを使用して商品情報を生成する

Gemini モデルを使用して、ペットショップの商品に関する次のデータを生成します。

  • products_mm テーブルに image_description 列を追加します。
  • products_mm テーブルの animal_typesearch_keywordssubcategory 列にデータを入力します。
  • 各商品ブランドの説明と、そのブランドの商品数を返すクエリを実行します。ブランドの説明は、そのブランドのすべての商品の商品情報(商品画像を含む)を分析して生成されます。
  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して 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));
  2. [BigQuery] ページのクエリ エディタで、次のクエリを実行して、animal_typesearch_keywordssubcategory 列を生成するデータで更新します。

    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;
  3. [BigQuery] ページのクエリエディタで、次のクエリを実行して生成されたデータを表示します。

    SELECT
      product_name,
      image_description,
      animal_type,
      search_keywords,
      subcategory,
    FROM cymbal_pets.products_mm;

    結果は次のようになります。

    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    | 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          |                  |
    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    | ...                            | ...                                 | ...         |  ...                   | ...              |
    +--------------------------------+-------------------------------------+-------------+------------------------+------------------+
    
  4. [BigQuery] ページのクエリエディタで、次のクエリを実行して、各商品ブランドの説明と、そのブランドの商品数を生成します。

    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;

    結果は次のようになります。

    +--------------+-------------------------------------+-----+
    | 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.. |     |
    +--------------+-------------------------------------+-----+
    |  ...         | ...                                 |...  |
    +--------------+-------------------------------------+-----+
    

Python UDF を作成して商品画像を変換する

Python UDF を作成して、商品画像をグレースケールに変換します。

Python UDF はオープンソース ライブラリを使用し、また並列実行を使用して複数の画像を同時に変換します。

  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して to_grayscale UDF を作成します。

    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
    """;

商品画像を変換する

グレースケール画像の宛先パスと認証情報を格納する ObjectRef 列を持つ products_grayscale テーブルを作成します。宛先パスは元のイメージパスから派生します。

テーブルを作成したら、to_grayscale 関数を実行してグレースケール画像を作成し、Cloud Storage バケットに書き込みます。次に、グレースケール画像のアクセス URL とメタデータを含む ObjectRefRuntime 値を返します。

  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して 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;

    BUCKET は、作成したバケットの名前に置き換えます。

  2. [BigQuery] ページのクエリエディタで、次のクエリを実行してグレースケール画像を作成し、Cloud Storage バケットに書き込みます。次に、グレースケール画像のアクセス URL とメタデータを含む ObjectRefRuntime 値を返します。

    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;

    結果は次のようになります。

    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | 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"}}                 |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    |  ...                                                                                                                                                                  |
    +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    

Python UDF を作成して PDF データをチャンク化する

Python UDF を作成して、Cymbal ペット製品のマニュアルを含む PDF オブジェクトを複数のパートに分割します。

PDF は非常に大きい場合が多く、生成 AI モデルへの単一の呼び出しに収まらない可能性があります。PDF をチャンク化することで、PDF データをモデル対応の形式で保存し、分析を容易にできます。

  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して chunk_pdf UDF を作成します。

    -- 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
    """;

PDF データを分析する

chunk_pdf 関数を実行して product_manuals テーブルの PDF データをチャンクに分割し、行ごとに 1 つの PDF チャンクを含む product_manual_chunk_strings テーブルを作成します。product_manual_chunk_strings データに Gemini モデルを使用して、製品マニュアルに記載されている法的情報を要約します。

  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して 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;
  2. [BigQuery] ページのクエリエディタで、次のクエリを実行して Gemini モデルを使用して PDF データを分析します。

    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));

    結果は次のようになります。

    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | 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:**                                                                                                         |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    | ...                                                                                                                                       |
    +-------------------------------------------------------------------------------------------------------------------------------------------+
    

画像データからエンベディングを生成し、エンベディングを使用してベクトル検索で類似画像を返します。

本番環境のシナリオでは、ベクトル検索を実行する前にベクトル インデックスを作成することをおすすめします。ベクトル インデックスを使用すると、ベクトル検索をより迅速に実行できますが、再現率が低下するため、より近似的な結果が返されます。

  1. [BigQuery] ページのクエリエディタで、次のクエリを実行して 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 ()
    );
  2. [BigQuery] ページのクエリエディタで、次のクエリを実行してベクトル検索を実行し、指定された入力画像に類似した商品画像を返します。

    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)
      ))
    );

    結果は次のようになります。

    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | 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--------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    | ...             | ...             | ...            | ...                                          | ...                | ...                           | ...                                            | ...            |
    +-----------------+-----------------+----------------+----------------------------------------------+--------------------+-------------------------------+------------------------------------------------+----------------+
    

ObjectRef 値の配列を使用して順序付きマルチモーダル データを処理する

このセクションでは、次のタスクを行う方法を説明します。

  1. product_manuals テーブルを再作成して、Crittercuisine 5000 製品マニュアルの PDF ファイルと、そのマニュアルの各ページの PDF ファイルの両方が含まれるようにします。
  2. マニュアルをチャンクにマッピングするテーブルを作成します。マニュアル全体を表す ObjectRef 値は、STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>> 列に保存されます。マニュアル ページを表す ObjectRef 値は、ARRAY<STRUCT<uri STRING, version STRING, authorizer STRING, details JSON>> 列に格納されます。
  3. ObjectRef 値の配列をまとめて分析し、生成された単一の値を返します。
  4. ObjectRef 値の配列を個別に分析し、配列値ごとに生成された値を返します。

分析タスクの一環として、ObjectRef 値の配列を ObjectRefRuntime 値の順序付きリストに変換し、そのリストを Gemini モデルに渡して、プロンプトの一部として ObjectRefRuntime 値を指定します。ObjectRefRuntime 値は、モデルが Cloud Storage 内のオブジェクト情報にアクセスするために使用する署名付き URL を提供します。

ObjectRef 値の配列を使用して順序付きマルチモーダル データを処理する手順は次のとおりです。

  1. [BigQuery] ページに移動します。

    BigQuery に移動

  2. クエリエディタで、次のクエリを実行して 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']);
  3. クエリエディタで次のクエリを実行して、PDF データを 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;
  4. クエリエディタで次のクエリを実行して、map_manual_to_chunks テーブルの PDF データを表示します。

    SELECT *
    FROM cymbal_pets.map_manual_to_chunks;

    結果は次のようになります。

    +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    | 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}}             |
    |                                     |                                |                                   |                                                      +-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    |                                     |                                |                                   |                                                      | ...                                       | ...                             |  ...                               | ...                                                   |
    +-------------------------------------+--------------------------------+-----------------------------------+------------------------------------------------------+-------------------------------------------+---------------------------------+------------------------------------+-------------------------------------------------------+
    
  5. クエリエディタで次のクエリを実行して、ObjectRef 値の配列の分析に基づいて Gemini モデルから単一のレスポンスを生成します。

    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));

    結果は次のようになります。

    +-------------------------------------------+
    | 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. |
    +-------------------------------------------+
    
  6. クエリエディタで次のクエリを実行して、ObjectRef 値の配列の分析に基づいて Gemini モデルから複数のレスポンスを生成します。

    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));

    結果は次のようになります。

    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    | 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.                        |
    +-----------------------------------------------+-------------------------------------------+----------------------------------------------------+
    

クリーンアップ

  1. In the Trusted Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.