0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GeminiをSQLから呼ぶ:AlloyDBのAI関数で感情分析・要約をやってみた

0
Posted at

はじめに

KDDIアイレットの取り組みとして、6月22日〜7月3日の期間で開催中の「Google Cloud Next '26 / Google I/O やってみた系ブログリレー」、本日は2日目の投稿です。

今回は、GeminiをSQLから利用できるAlloyDBの新しいAI関数を実際に検証してみました!

前回の記事はこちらです。

文章も画像も同じ"ものさし"で!Gemini Embedding 2 のマルチモーダル検索を試してみた

概要

アプリ側でGemini APIを叩かなくても、SQLのSELECTだけで感情分析・要約ができる —— これが今回の主役です。

Google Cloud Next '26 で、AlloyDBに ai.analyze_sentiment / ai.summarize というAI関数が追加されました(現時点では Preview)。実際に日本語レビューで動かしてみた結果、わかったことは次の通りです。

  • 日本語レビューの感情分析は精度が高い
  • 要約は デフォルトだと英語で返ってくる が、プロンプトで日本語指定すれば解決する
  • 東京リージョンではモデル指定(model_id)が必要というつまずきがあった

先に結果だけ見たい方はこちら → 本題:SQLのSELECT一発でGeminiの感情分析と要約


目次


なぜ嬉しいのか:Gemini APIを叩かずSQLだけで感情分析できる

レビュー分析のような「テキストをAIにかけたい」処理は、これまで次のような流れが一般的でした。

  1. アプリからDBのデータを読む
  2. Gemini API(や他のLLM API)に投げる
  3. 結果をDBに書き戻す

この3ステップのために、AIを呼び出すアプリケーションコードやETLなどのデータ連携処理が必要でした。

ところがAlloyDBの新しいAI関数を使うと、このステップがまるごと消えて、SQLだけでAIを利用できるようになります。SELECT文を実行するだけで、感情分析と要約の結果がその場で返ってきます。DBとAIの境界が溶けていく感覚があって、これが今回一番おもしろかったところです。

既存の AlloyDB AI 関数群(ai.if, ai.rank, ai.generate, ai.forecast など)に、今回 Next '26 で新しく ai.analyze_sentiment と ai.summarize が加わった、という位置づけです。

検証環境

  • AlloyDB for PostgreSQL(PostgreSQL 17 ※AI関数の必須条件)
  • リージョン:asia-northeast1(東京)
  • インスタンス:プライマリ 2 vCPU(最小構成)
  • 接続:AlloyDB Studio(コンソールのSQLエディタ)

AlloyDBには30日間の無料トライアルクラスタ(8 vCPU・1TBストレージ)もあり、1プロジェクトにつき1回まで無料で試せます。

セットアップ編

1. クラスタ&インスタンスを作成

Cloud Shell から gcloud CLI で作成します。--database-version=POSTGRES_17 がAI関数の必須条件です。

# 変数
export PROJECT_ID="あなたのプロジェクトID"
export REGION="asia-northeast1"
export CLUSTER_ID="ai-demo-cluster"
export INSTANCE_ID="ai-demo-primary"
export DB_PASSWORD="英大小+数字を混ぜた16文字程度"
gcloud config set project "$PROJECT_ID"

# API有効化
gcloud services enable \
  alloydb.googleapis.com aiplatform.googleapis.com \
  compute.googleapis.com servicenetworking.googleapis.com

# ── ネットワーク準備(プライベートIP接続のため)──
# Service Networking のサービスエージェントを作成
gcloud beta services identity create \
  --service=servicenetworking.googleapis.com --project="$PROJECT_ID"

# ピアリング用のIP範囲を予約
gcloud compute addresses create google-managed-services-default \
  --global --purpose=VPC_PEERING --prefix-length=16 \
  --network=default --project="$PROJECT_ID"

# VPCピアリングを張る(roles/servicenetworking.networksAdmin が必要)
gcloud services vpc-peerings connect \
  --service=servicenetworking.googleapis.com \
  --ranges=google-managed-services-default \
  --network=default --project="$PROJECT_ID"

# ── クラスタ&インスタンス作成 ──
# クラスタ(PG17)
gcloud alloydb clusters create "$CLUSTER_ID" \
  --region="$REGION" --password="$DB_PASSWORD" \
  --database-version=POSTGRES_17

# プライマリインスタンス(2 vCPU)
gcloud alloydb instances create "$INSTANCE_ID" \
  --cluster="$CLUSTER_ID" --region="$REGION" \
  --instance-type=PRIMARY --cpu-count=2

2. AI関数用のIAM権限を付与

AI関数は裏でGemini(Vertex AI)を呼ぶので、AlloyDBのサービスエージェントにVertex AI利用権限が要ります。これが無いと関数実行時に Permission denied on the resource. になります。

# サービスエージェントを作成(出力されるアドレスを控える)
gcloud beta services identity create \
  --service=alloydb.googleapis.com --project="$PROJECT_ID"
# → service-XXXXXXXX@gcp-sa-alloydb.iam.gserviceaccount.com が出力される

# 上のアドレスに Vertex AI 利用権限を付与
gcloud projects add-iam-policy-binding "$PROJECT_ID" \
  --member="serviceAccount:控えたアドレス" \
  --role="roles/aiplatform.user"

3. AlloyDB Studio にログイン

コンソールの AlloyDB → クラスタ → 左メニュー「AlloyDB Studio」を開き、以下でログインします。

  • ユーザー:postgres
  • データベース:postgres
  • パスワード:クラスタ作成時に設定したもの

プライベートIPのクラスタにCloud Shellからpsqlで繋ぐより、Studioが手早くて確実です。以降のSQLはすべてStudioのエディタに貼って実行します。

4. プレビューAI関数を有効化

ai.analyze_sentiment / ai.summarize はPreview機能なので、フラグの有効化が要ります。まず拡張のバージョンを確認します。

SELECT extversion FROM pg_extension WHERE extname = 'google_ml_integration';

今回は 1.5.9 でした。プレビューAI関数には 1.5.7以上 が必要なので、そのまま進めます。もし古ければ、次のコマンドでプレビュー版へ上げてください(今回は不要でした)。

-- バージョンが 1.5.7 未満の場合のみ
CALL google_ml.upgrade_to_preview_version();

最後にプレビューAI関数フラグを有効化します。

SET google_ml_integration.enable_preview_ai_functions = 'on';

ハマりポイント:このフラグはセッション単位です。Studioでタブを開き直したり接続が変わると off に戻ります。「さっき動いたのに急に Preview AI functions are disabled エラー」が出たら、まずこれを疑ってください。SET文と本命SQLは同じエディタに並べて1回でまとめて実行するのが確実です。


5. テストデータを投入

CREATE TABLE IF NOT EXISTS customer_reviews (
    id INT PRIMARY KEY,
    review_content TEXT
);

INSERT INTO customer_reviews (id, review_content) VALUES
(1,  'この商品は期待以上でした。買って本当に良かったです。'),
(2,  '梱包が丁寧で、配送も早くて満足しています。'),
(3,  'デザインは気に入っていますが、値段が少し高いと感じました。'),
(4,  '使い方の説明書が分かりにくく、設定に時間がかかりました。'),
(5,  '正直、期待外れでした。すぐに壊れてしまい残念です。'),
(6,  'まあ普通です。可もなく不可もなくといった印象。'),
(7,  'サポートの対応がとても親切で好感が持てました。'),
(8,  '写真と実物の色が違っていて少しがっかりしました。'),
(9,  'コスパは良いと思います。リピートするか検討中です。'),
(10, '最高の買い物でした。友人にも勧めたいくらいです。');

ポジティブ・ネガティブ・ニュートラルを混在させた日本語レビュー10件です。

実践編(本題)

本題:SQLのSELECT一発でGeminiの感情分析と要約を実行する

SET google_ml_integration.enable_preview_ai_functions = 'on';

SELECT
    review_content,
    ai.analyze_sentiment(review_content, model_id => 'gemini-2.5-flash') AS sentiment,
    ai.summarize(review_content, model_id => 'gemini-2.5-flash')         AS summary
FROM customer_reviews
LIMIT 10;

今回の検証環境(東京リージョン)では model_id を指定しないとエラーになったため、ここでは明示的に指定して実行しています

alloydb-sentiment-summary-result.png

図1:感情分析と要約を1つのSELECTで実行した結果

スクリーンショットだと文字が小さく読みづらいので、結果を表にまとめます。

結果①:感情分析は日本語でも優秀

10件すべての結果がこちらです。

review_content sentiment
この商品は期待以上でした。買って本当に良かったです。 positive
梱包が丁寧で、配送も早くて満足しています。 positive
デザインは気に入っていますが、値段が少し高いと感じました。 neutral
使い方の説明書が分かりにくく、設定に時間がかかりました。 negative
正直、期待外れでした。すぐに壊れてしまい残念です。 negative
まあ普通です。可もなく不可もなくといった印象。 neutral
サポートの対応がとても親切で好感が持てました。 positive
写真と実物の色が違っていて少しがっかりしました。 negative
コスパは良いと思います。リピートするか検討中です。 positive
最高の買い物でした。友人にも勧めたいくらいです。 positive

表1:感情分析の結果

「可もなく不可もなく」を neutral に分類できているあたり、日本語のニュアンスもしっかり拾えています。10件すべて、ほぼ人間の感覚と一致する分類でした。想像していたより正確で、レビュー分析のような用途であれば十分活用できそうです。

結果②:要約は「英語で返ってくる」想定外の挙動

model_id を指定して実行したところ、要約(summary)は 日本語レビューを入れたのに英語で返ってきました。10件の結果がこちらです。

review_content summary(デフォルト)
この商品は期待以上でした。買って本当に良かったです。 "The product exceeded expectations and the purchase was highly satisfactory."
梱包が丁寧で、配送も早くて満足しています。 "The customer expressed satisfaction with the careful packaging and fast delivery."
デザインは気に入っていますが、値段が少し高いと感じました。 "The design is appealing, but the price is perceived as somewhat high."
使い方の説明書が分かりにくく、設定に時間がかかりました。 "The instruction manual was unclear, leading to a prolonged setup time."
正直、期待外れでした。すぐに壊れてしまい残念です。 "The product was disappointing, having broken quickly."
まあ普通です。可もなく不可もなくといった印象。 "The text conveys an impression of ordinariness, being neither good nor bad."
サポートの対応がとても親切で好感が持てました。 "The support's response was very kind and left a good impression."
写真と実物の色が違っていて少しがっかりしました。 写真と実物の色合いが異なり、やや落胆した。
コスパは良いと思います。リピートするか検討中です。 "The cost performance is considered good, and a repeat purchase is being contemplated."
最高の買い物でした。友人にも勧めたいくらいです。 "The purchase was excellent, warranting a strong recommendation to friends."

表2:要約結果(デフォルト)

見ての通り、9件は英語で返ってきたのに、8番だけなぜか日本語で返ってきました。つまり 出力言語が安定しない。これは実際に動かさないと気づけないポイントでした。

解決:プロンプトで出力言語を指定する

ai.summarize はプロンプトを渡せるので、日本語を明示すると揃います。

SET google_ml_integration.enable_preview_ai_functions = 'on';

SELECT
    review_content,
    ai.summarize(
      prompt => '次のレビューを日本語で1文に要約してください: ' || review_content,
      model_id => 'gemini-2.5-flash'
    ) AS summary
FROM customer_reviews
LIMIT 10;

alloydb-summary-japanese.png

図2:プロンプトで日本語を指定した要約結果

結果、全件きれいな日本語要約になりました。

review_content summary(日本語指定)
この商品は期待以上でした。買って本当に良かったです。 この商品は期待を上回り、購入に大変満足している。
梱包が丁寧で、配送も早くて満足しています。 丁寧な梱包と迅速な配送に満足している。
デザインは気に入っていますが、値段が少し高いと感じました。 デザインは評価するものの、価格は高めだと感じられている。
使い方の説明書が分かりにくく、設定に時間がかかりました。 説明書が不明瞭なため、設定に時間を要した。
正直、期待外れでした。すぐに壊れてしまい残念です。 すぐに壊れて期待外れだった。
まあ普通です。可もなく不可もなくといった印象。 良くも悪くもない、ごく普通の印象である。
サポートの対応がとても親切で好感が持てました。 サポートの対応が親切で好印象だった。
写真と実物の色が違っていて少しがっかりしました。 写真と実物の色合いが異なり、期待外れであった。
コスパは良いと思います。リピートするか検討中です。 コストパフォーマンスは良いと感じているものの、リピート購入については検討中である。
最高の買い物でした。友人にも勧めたいくらいです。 最高の買い物であり、友人にも勧めたいほど満足している。

表3:日本語指定の要約結果
プロンプトで出力言語を日本語に指定したところ、全件で自然な日本語の要約が得られました。

応用:ネガティブなレビューだけ抽出

WHERE 句に直接AI関数を書けるので、ネガティブなレビューだけ絞り込めます。

SET google_ml_integration.enable_preview_ai_functions = 'on';

SELECT id, review_content
FROM customer_reviews
WHERE ai.analyze_sentiment(review_content, model_id => 'gemini-2.5-flash') = 'negative';

alloydb-negative-filter.png

図3:ネガティブなレビューだけ抽出した結果

id review_content
4 使い方の説明書が分かりにくく、設定に時間がかかりました。
5 正直、期待外れでした。すぐに壊れてしまい残念です。
8 写真と実物の色が違っていて少しがっかりしました。

表4:ネガティブなレビューの抽出結果

「説明書が分かりにくい」「すぐ壊れた」「写真と色が違う」のネガティブな3件がちゃんと拾えました。クレーム検知のような用途がSQLだけで書けるのは、なかなか強力です。

モデル指定(model_id)に関する注意点

デフォルト(model_id を指定しない状態)で実行すると、今回の検証環境(東京リージョン)では以下のエラーが出ました。

postgresql error: Resource not found for the prediction request.

この場合、model_id => 'gemini-2.5-flash' のように利用可能なモデルを明示的に指定することで無事に動作しました。もし同様のエラーに遭遇した場合は、モデルの明示を試してみてください。

レイテンシ・コスト感

  • SQLだけで利用できますが、内部ではGeminiなどのLLMを呼び出すため、通常のSQLより実行時間は長くなります。今回の検証では数秒程度でしたが、実行条件によって変動します。
  • 無料トライアルクラスタを利用すれば、AlloyDBのインフラ料金をかけずに試せます。
  • AI関数自体に追加料金はありませんが、利用したGeminiなどのモデル推論料金は別途課金されます。

まとめ

ai.analyze_sentiment / ai.summarize を実機で試して、SQLのSELECTだけでLLMの感情分析・要約が動くことを確認できました。アプリ層もETLも要らず、DBの中で完結する体験は素直にインパクトがあります。日本語の感情分析の精度も実用十分で、レビュー分析やクレーム検知のような用途なら、これだけで形になりそうです。

一方で、デフォルトでは英語で返るケースがありましたが、プロンプトで日本語で要約するよう指示したところ、全件で自然な日本語の要約が得られました。現時点ではPreviewということもあり、本番利用では事前の検証は欠かせないと感じました。SQLの中にAIが溶け込んでいく方向性は、これから確実に広がっていくと感じます。

AlloyDB AIには時系列予測の ai.forecast など他の関数もあるので、機会があればそのあたりも試してみようと思います。

Preview機能ではあるものの、SQLだけでLLMを呼び出せる体験は非常に新鮮でした。正式リリース後は、レビュー分析や問い合わせ分類などの用途で活用が広がりそうです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?