BigQuery × Geminiで愛犬の「心の声」を覗いてみた — 非構造化データのAI解析入門

BigQuery × Geminiで愛犬の「心の声」を覗いてみた — 非構造化データのAI解析入門

これまでBigQueryといえば、売上データやログなどの「構造化データ」を扱う場所でした。しかしBigQueryの AI.GENERATE関数は、「非構造化データ」も取り扱うことができます。「前の前の記事」「前の記事」では「非構造化データ」として人間が書いた想定の、「レビュー」という不定形なテキストを取り上げました。

以下が紹介した内容です。

 

 

AI.GENERATE関数は、テキストだけでなく、「画像」や「音声」も取り扱うことができます。この記事では、代表的な非構造化データである「画像」をAI.GENERATE関数で扱う方法を紹介します。

画像は、GCS(Google Cloud Storage:Googleが提供するネット上のファイル保管倉庫)上に格納したものを、生成AIエンジンはVertex AI上の Gemini-2.5-Flashを利用します。

もし、結果だけ知りたいよとか、まずは結果を見たいよ。という方は、以下の「目次」から「3.3 クエリの実行結果」をご覧ください。
 

 

1. お題:愛犬の独り言を生成する

Geminiに渡すのは、我が家の愛犬(ゴールデンレトリバー・4歳メス)の写真3枚です。犬は人間の言葉を話さないので、何を考えているのか分からない時があります。そこで、何を考えているのかをGeminiに「愛犬の心の声」として生成してもらいます。

さて、うまくいくでしょうか?まず、準備から始めましょう。

2. 準備

準備として、以下が必要になります。

  1. 画像の、Google Cloud Storageへのアップロード
  2. BigQuery側での「接続」の作成と生成されるサービスアカウントに対する権限付与
  3. 画像のメタデータを格納する「オブジェクトテーブル」の作成

 

2.1 GCSへの画像のアップロード

まずは、Google Cloud Storage(GCS)にバケットを作成し、犬の画像をアップロードします。バケットとは、直訳すると「バケツ」のことです。分析対象の素材である画像を、作成したバケツ(正式名:バケット)にアップロードする必要があります。

以下は、ちょっと縦に長い画像で、見づらくてすみませんが、Google Cloudのコンソールの左カラムから、「Cloud Storage > バケット」と進みます。

 

次に、バケットに名前を付けて、保存します。以下の通り、私は、dog-photo-20260324という名前にしました。このバケット名はコピーしておきます。

 

次に、画像をアップロードします。特に難しい操作はありません。以下は3枚の愛犬の画像をGCSにアップロードしたところです。

  

2.2 「接続」の作成と権限付与

次に、BigQueryから、画像を置いたGCSへアクセスするために、「接続」を作成します。「接続」とは、BigQueryから見た「外部サービス」であるGCSとやりとりするための「使者」だと思ってください。

実は、「前の前の記事」でAI.GENERATE関数の基本的な挙動とクエリの記述方法を紹介したときには、「接続」は不要でした。しかし、画像を扱うとなると話は別です。なぜなら、画像はGCSという鍵のかかった別倉庫に保管されているからです。

さらに、その「使者」が適切な権限を持っていないと、BigQueryから画像にアクセスできません。そこで、「接続」を作成すると自動で生成される使者(サービスアカウント)に、権限(役割)を付与します。

まずは、接続の追加、そして、その次に役割の付与について、手順を確認します。

 

2.2.1 BigQuery管理画面から「接続」を追加

BigQueryの、今回の検証をしたいプロジェクト配下にある「接続」(赤枠)をクリックし、「接続を作成」(オレンジ枠)ををクリックします。

 

すると、接続の作成画面になりますので、適当な接続ID(以下では、gemini-dog-connとしています)を入力し、接続先として「Vertex AI リモートモデル、リモート関数、BigLake、Spanner(Cloud リソース)を指定します。

リージョンは、以下の通り、USのマルチリージョンを選択しています。接続IDについてもコピーしておきます。

 

2.2.2 サービスアカウントへの役割付与

発行されたサービスアカウントに、GCSの画像にアクセスするための権限を付与します。以下が「接続」の作成後に確認できる「接続情報」画面です。サービスアカウントIDが見えています。次の作業として、このサービスアカウントに「役割」を付与します。その時必要になるので、このサービスアカウントIDも付与しておいてください。

 

左カラムの「IAMと管理 > IAM」に入り、以下の通り、先程コピーしたサービスアカウントIDに対して、GCSの閲覧権限である、「Storage オブジェクト閲覧者(Storage Object Viewer)」を付与します。

 

2.3 GCS画像の「オブジェクトテーブル」化

次に、画像をメタデータとして管理するための「オブジェクトテーブル」を作成します。後述する「愛犬の心の声」を生成してもらうクエリ(SQL文)では、GCS上の個別の画像のURLではなく、ここで作成する「オブジェクトテーブル」を参照することになるので、この手順は端折れません。

オブジェクトテーブルを作成するには、以下のクエリをコンソールのクエリエディタから実行します。このクエリを見ると、接続IDやバケットの記述があります。予め作ってあった「接続」を利用して、予め格納してあったGCS上の画像を参照している。というのが分かりますね。

CREATE OR REPLACE EXTERNAL TABLE `ai_demo_us.dog_images` -- 作成するオブジェクトテーブル
WITH CONNECTION `us.gemini-dog-conn` -- 作成した接続ID
OPTIONS (
  object_metadata = 'SIMPLE',
  uris = ['gs://dog-photo-20260324/*.JPG'] -- 作成済みのバケット名のフルパス
);

 

ちなみに、作成したオブジェクトテーブルは以下(一部)のような列を持っています。GCSに格納してある画像について、ファイル名や、ファイルタイプ、サイズやなど、まさにメタデータの集積。といえるでしょう。

 

3. 本編:Geminiによる「心の声」生成

では、本ブログ記事のメインのテーマである、Geminiによる心の声を生成するクエリと、その結果を紹介します。

3.1 クエリの紹介

準備が整いましたので、本編である、「犬の画像から心の声をGeminiに生成してもらう」ことにしましょう。クエリは以下です。少し長いクエリに見えますが、大部分がプロンプトですので、SQLの命令自体は、「オブジェクトテーブル」と、Geminiからの戻り値(のSTRUCTをARRAY化して、UNNESTしたフラットテーブル)をクロスジョインしたFROM句に対して、SELECT句で2カラムだけを表示している、至ってシンプルな内容です。

 

ただ、1点、AI.GENERATE関数の第一引数は、「プロンプト」と「データ」で構成されていますが、「データ」として画像をGeminiに渡すのに必要な以下の関数が使われています。

OBJ.GET_ACCESS_URL(t.ref, ‘r”)

この関数については、もう少し説明しましょう。

SELECT
  t.uri AS dog_image_uri,
  ml_gen.inner_voice
FROM
  `ai_demo_us.dog_images` AS t,
  UNNEST([
    AI.GENERATE(
      (
        '''あなたは写真に写っているゴールデンレトリバー(4歳・メス)本人です。
        人間年齢に換算すると30歳という、落ち着きと茶目っ気が共存する年齢であることを意識してください。
        
        【任務】
        画像から読み取れるあなたの「現在の気持ち」を独白してください。
        
        【条件】
        - 撮影者(人間)に呼びかけない「完全なひとりごと」にすること。
        - 50文字程度で、30代らしい少し冷めたユーモアや余裕を感じさせる表現。
        - 状況の解説ではなく、内面の「ワクワク」「退屈」「悟り」などの感情にフォーカス。
        - 犬としての本能(食欲や散歩への執着)は忘れないでください。
        - 最後に必ずハッシュタグを1つ付けてください。''' ,
        OBJ.GET_ACCESS_URL(t.ref, 'r')
      ),
      endpoint => 'gemini-2.5-pro',
      output_schema => 'inner_voice STRING'
    )
  ]) AS ml_gen
ORDER BY  t.uri ASC;

 

3.2 OBJ.GET_ACCESS_URL関数の解説

この関数は、GCSにある画像に一時的にアクセスできるURL(署名付きURL)を生成するための関数です。Geminiが画像を「見る」ためには、その画像に対するURLが必要なので、この関数を通じて画像にアクセス可能なURLを取得しています。
 

引数についても解説します。

OBJ.GET_ACCESS_URL(t.ref, ‘r”)

 

第一引数である、t.refは、tという別名を付けた、オブジェクトテーブル(ここでは、dog_images)の、refカラムを示しています。ただし、refカラムはシンプルな1列のカラムではなく、構造体(STRUCT)ですので、以下の4カラムを一挙に指定し、Geminiに引き渡しています。

  • ref.uri
  • ref.version
  • ref.authorizer
  • ref.details

どんな値が格納されているのかを確認してみましょう。見に行く画像のGCS上の住所(ref.uri)や、どの接続IDを使って見に行けばいいのか(ref.authorizer)などが指定されていますね。

 

第二引数の、’r’は、「読み取り専用」を示しています。

 

3.3 クエリの実行結果


クエリの実行結果は、以下の通りです。心の声(innter_voiceカラム)の内容には好き嫌いがあるかもしれませんが ^^;、Geminiが画像を「見て」心の声を生成してくれた。ということは分かりますね。

 

画像と合わせて「心の声」を確認しないと、Geminiの仕事ぶりを評価できないと思うので、Google Sheetsで画像と心の声を同時に表示できるようにしたのが、以下です。(クエリの実行結果をテーブルにして保存した上で、BigQueryの結果をConnected Sheetsで読み込み、画像関数(=IMG())を使って並べてみました。

 

4. まとめ

如何だったでしょうか?
GCSにバケットを作ったり、そのバケットに画像をアップロードしたり、接続を作ったり、接続に紐づくサービスアカウントに役割を付与したり、オブジェクトテーブルを作ったり、といった事前準備は確かに面倒くさい作業でした。
しかし、BigQueryからGeminiに画像を投げて処理をしてもらうという根幹部分は思ったほど難しくない。という感想ではないでしょうか。

この記事で皆さんに体験して頂きたかったのは、「BigQueryによる画像に対する生成AIの処理」と聞くと身構えてしまうものですが、準備さえ完了してしまえば、実際には「SQLを数行書くだけ」で実行できてしまうということです。

私たちが日頃使っているブラウザ板のGeminiは「対話」が得意ですが、BigQuery版は「一括処理」が得意です。紹介したお題は画像3枚を対象としましたが、1,000枚の画像に対して一斉にキャプションを付けるといった作業も、クエリ一発で完了します。

今回は、デモなので、「愛犬画像とその心の声」という柔らかいお題にしましたが、デジタルマーケティングへの応用としては、次のようなシーンが考えられるかもしれません。

  • クリエイティブ分析: 大量のバナー広告画像から「色使い」や「写っている物」を抽出し、クリック率との相関を分析する。
  • SNS監視: 自社ブランドが写っている投稿画像を自動で判別し、ポジ・ネガ判定や状況をタグ付けする。

「画像」という未開のデータを「SQL X 生成AI」で処理し、ビジネスに役立てることができる。この記事でそんな理解をして頂けたら嬉しいです。

 

5.この記事に関連した学習リソース

この記事をここまで読んでいただいた方は、もれなく、BigQuery(SQL)って、素敵なことができるな!!と思っていただいたんじゃないかと思います。

SQLについて、学習用の良い動画講座を紹介します。たくさんのレビューを頂き、5点満点中4.6点と、お陰様で評判も良いようです。よろしければどうぞ。(画像をクリックするとUdemy.comにジャンプします。)

 

書籍で学習したい場合には、以下の拙著を推奨します。こちらをどうぞ。(アマゾンのアフィリエイトリンクです。画像をクリックするとアマゾンにジャンプします)

 

自分のSQLライティング能力を確認したい、同僚や上司や転職先にアピールしたい。という場合には、ぜひ、こちらのサービスをご利用ください。私が開発した、SQLリテラシーを診断するテストです。