AI 関数を使用してインテリジェントな SQL クエリを実行する

ドキュメントのバージョンを選択してください。

このページでは、AlloyDB Omni AI クエリエンジンを使用して、AI 関数を使用してインテリジェントな SQL クエリを実行する方法について説明します。

AlloyDB AI 関数は、Gemini などの大規模言語モデル(LLM)を AlloyDB Omni データと直接統合して、インテリジェントなデータ オペレーションを実行します。この機能には、次の組み込み関数が含まれています。

  • フィルタリング(ai.if)
  • セマンティック ランキング(ai.rank)
  • テキスト生成(ai.generate)

これらの AI 関数は、AlloyDB AI クエリエンジンを使用して、単一行のレスポンスから大規模なデータベース オペレーションまで、さまざまな規模で人工知能モデルを使用してアプリケーションがデータを処理できるようにします。ai.if、ai.rank、ai.generate 演算子を使用して、自然言語と SQL クエリを組み合わせることができます。AlloyDB AI は ai スキーマを予約して作成します。

AI 関数には、入力データの処理方法とメモリ割り当てに基づいて、スカラー関数、配列ベースの関数、カーソル関数の 3 つのカテゴリがあります。適切な AI 関数を選択するかどうかは、データの規模とパフォーマンス要件によって異なります。次の表で、これらの関数とそのユースケースについて確認します。

カテゴリ

説明

推奨ユースケース

スカラー

基本的な 1 対 1 の処理向けに設計されています。単一の入力を受け取り、単一の出力を返します。

少数の(50 未満の)スカラー関数呼び出しを行うクエリに対して許容可能なパフォーマンスを提供する基本的な関数が必要な場合に使用します。

配列ベース

1 回の関数呼び出しで、データを行の配列として処理します。配列を入力として受け取り、配列を出力として返します。

対象となる行の配列全体がメモリ制限内に収まる小規模から中規模のデータセットに使用します。これにより、セットベースのオペレーションで高スループットが実現します。

Cursor

カーソルを入力として受け取り、カーソルを出力として返します。

多数の行(10,000 行など)の処理に使用します。

始める前に

  1. Vertex AI モデルへのユーザー アクセスを構成する。
  2. google_ml_integration の最新バージョンがインストールされていることを確認します。

    1. インストールされているバージョンを確認するには、次のコマンドを実行します。

      SELECT extversion FROM pg_extension WHERE extname = 'google_ml_integration';
      extversion 
      ------------
      1.5.2
      (1 row)
    2. 拡張機能がインストールされていない場合、またはインストールされているバージョンが 1.5.2 より前の場合は、拡張機能を更新します。

      CREATE EXTENSION IF NOT EXISTS google_ml_integration;
      ALTER EXTENSION google_ml_integration UPDATE;

      上記のコマンドを実行したときに問題が発生した場合、または上記のコマンドを実行しても拡張機能がバージョン 1.5.2 にアップデートされない場合は、Google Cloud サポートにお問い合わせください。

  3. AlloyDB AI クエリエンジンの機能を使用するには、google_ml_integration.enable_ai_query_engine フラグを on に設定します。

    SQL

    1. 現在のセッションで AI クエリエンジンを有効にします。

      SET google_ml_integration.enable_ai_query_engine = on;
    2. セッション間で特定のデータベースの機能を有効にします。

      ALTER DATABASE DATABASE_NAME SET google_ml_integration.enable_ai_query_engine = 'on';
    3. セッションとデータベース全体で特定のユーザーに対して AI クエリエンジンを有効にします。

      ALTER ROLE postgres SET google_ml_integration.enable_ai_query_engine = 'on';

リージョンでサポートされている Gemini モデルを使用する

gemini-2.5-flash-lite がサポートされていないリージョンに AlloyDB Omni クラスタがある場合は、model_id parameter を使用して、そのリージョンで利用可能な他の Gemini モデルのいずれかを使用できます。

または、Gemini モデル エンドポイントを登録し、AI 演算子でそのモデル ID を指定することもできます。詳細については、モデル エンドポイント管理を使用してリモート AI モデルを登録して呼び出すをご覧ください。

次の例は、別の Gemini エンドポイントを登録する方法を示しています。この例では、この 2 番目の Gemini エンドポイントは gemini-2.5-flash-lite のグローバル エンドポイントです。この登録済みモデルを AI 演算子で使用するには、追加の引数として model_id => 'gemini-2.5-flash-lite-global' を渡します。

CALL
  google_ml.create_model(
    model_id => 'gemini-2.5-flash-lite-global',
    model_type => 'llm',
    model_provider => 'google',
    model_qualified_name => 'gemini-2.5-flash-lite',
    model_request_url =>  'https://aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/global/publishers/google/models/gemini-2.5-flash-lite:generateContent',
    model_auth_type => 'alloydb_service_agent_iam'
);

Gemini 3.0 モデルを使用する

gemini-3.0-pro-preview などの一部の Gemini モデルは、グローバル エンドポイントでのみ使用できます。このようなモデルは、次のように登録する必要があります。

CALL
  google_ml.create_model(
    model_id => 'gemini-3-preview-model',
    model_request_url => 'https://aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/global/publishers/google/models/gemini-3-pro-preview:generateContent',
    model_qualified_name => 'gemini-3-pro-preview',
    model_provider => 'google',
    model_type => 'llm',
    model_auth_type => 'alloydb_service_agent_iam'
);

PROJECT_ID は、Vertex AI モデルが使用可能なプロジェクトの ID に置き換えます。AlloyDB Omni サービス アカウントには、そのプロジェクトの Vertex AI ユーザーロールが必要です。

モデルを登録したら、次のように AI 関数で使用できます。

SELECT ai.generate(prompt => 'What is AlloyDB?', model_id => 'gemini-3-preview-model');

クエリでフィルタを使用する

AlloyDB AI には、ai.if 演算子や ai.rank 演算子など、データベース クエリ内で自然言語処理と LLM を直接使用できる AI を活用した SQL 関数が用意されています。

スカラー関数を使用してフィルタリングを行う

自然言語で指定された条件が満たされているかどうかを評価するには、ai.if/google_ml.if 演算子を使用します。この関数はブール値 true または false を返します。出力が明確に検出されなかった場合は false を返します。

- Function signature
FUNCTION ai.if(prompt TEXT, model_id VARCHAR(100) DEFAULT NULL) RETURNS bool

次の例は、ai.if 演算子をフィルタとして使用して、人口が 10 万人を超える都市にあり、500 件を超える好意的なレビューがあるレストランを見つける方法を示しています。この例では restaurant_reviews を使用しています。このテーブルには、レビューや都市の位置情報などのデータが含まれています。ai.if 演算子を使用することによって、レビューの感情を把握したり、データベースから取得した場所とその場所の人口に関する Gemini の一般的な知識を組み合わせたりることができます。

SELECT r.name, r.location_city
FROM restaurant_reviews r
WHERE
  AI.IF(r.location_city || ' has a population OF more than 100,000 AND the following is a positive review; Review: ' || r.review)
GROUP BY r.name, r.location_city
HAVING COUNT(*) > 500;

次は、リージョンでサポートされている Gemini モデルを使用するで登録したモデルを使用した同じ例です。

SELECT r.name, r.location_city
FROM restaurant_reviews r
WHERE
  AI.IF(r.location_city || ' has a population of more than 100,000 AND the following is a positive review; Review: ' || r.review, model_id => 'gemini-2.5-flash-lite')
GROUP BY r.name, r.location_city
HAVING COUNT(*) > 500;

if 演算子を使用するクエリで結合を実行する

結合オペレーションを実行するには、結合で ai.if/google_ml.if 演算子を使用します。次のサンプルクエリは、レストランのメニューの各メニュー アイテムに言及しているレビューの数を検索します。

    SELECT item_name, COUNT(*)
    FROM menu_items JOIN user_reviews
      ON ai.if(
        prompt => 'Does the following user review talk about the menu item mentioned ? review: ' || user_reviews.review_text || ' menu item: ' || item_name)
    GROUP BY item_name;

配列ベースの関数を使用してフィルタリングを行う

次の例では、AI モデル(gemini-2.5-flash-lite)を使用してレビューの感情を分析し、結果をフィルタリングすることで、肯定的なレビューが 10 件以上あるレストランを特定します。ARRAY_AGG は、データの個々の行を構造化配列に変換するために使用されます。これにより、AI モデルは一度に 1 行ずつではなく、一括で処理できます。

WITH initial_arrays AS (WITH initial_arrays AS (
  SELECT
    ARRAY_AGG(r.id ORDER BY r.id) AS review_ids,
    -- Assuming ai.if takes an array of prompts and returns a boolean array
    ai.if(
      prompts => ARRAY_AGG('Is the review positive: ' || r.review ORDER BY r.id)
      model_id => 'gemini-2.5-flash-lite',
      batch_size => 20
    ) AS truth_values
  FROM restaurant_reviews r
),
reviews AS (
SELECT
  initial_arrays.review_ids[i] AS review_id,
  initial_arrays.truth_values[i] AS truth_value
FROM
  initial_arrays,
  generate_series(1, array_length(initial_arrays.review_ids, 1)) AS i
)
SELECT rest_review.city, rest_review.name
FROM restaurant_reviews rest_review JOIN reviews review ON rest_review.id=review.review_id
WHERE review.truth_value = 't'
GROUP BY rest_review.city, rest_review.name
HAVING COUNT(*) > 10;

カーソルを使用してフィルタリングを行う

次の例は、カーソルを介してストリーミングすることで、レストランのレビューの大きなセットをフィルタする方法を示しています。

CREATE TABLE filtered_results(input text, result bool);

DO $$
DECLARE
    prompt_cursor REFCURSOR;
    result_cursor REFCURSOR;
    rec RECORD;
BEGIN
    -- 1. Open a cursor for the input data
    OPEN prompt_cursor FOR
        SELECT r.location_city || ' has a population of > 100,000 and is a positive review; Review: ' || r.review
        FROM restaurant_reviews r;

    -- 2. Call the array-based function using the input cursor
    result_cursor := ai.if(
        'Is the given statement true? ',
        prompt_cursor,
        model_id => 'gemini-2.5-flash-lite'
    );

    -- 3. Fetch results from the output cursor and store them
    LOOP
        FETCH result_cursor INTO rec;
        EXIT WHEN NOT FOUND;
        INSERT INTO filtered_results VALUES(rec.input, rec.output);
    END LOOP;

    CLOSE result_cursor;
END $$;

テキスト生成、要約

AlloyDB AI は、スカラー ai.generate、配列ベースとカーソルベースの ai.generate などのテキスト生成演算子を提供します。

スカラー関数を使用してテキスト生成を行う

ai.generate 関数は、提供されたデータとユーザーのプロンプトを組み合わせてテキストを生成します。

-- Function Signature
FUNCTION ai.generate(prompt TEXT, model_id VARCHAR(100) DEFAULT NULL) RETURNS TEXT

たとえば、次のクエリを使用して、各ユーザー レビューの簡潔な要約を生成できます。

SELECT
  ai.generate(
    prompt => 'Summarize the review in 20 words or less. Review: ' || review) AS review_summary
FROM user_reviews;

配列ベースの関数を使用してテキスト生成を行う

次のクエリは、UNNEST と ai.generate を使用して複数のレビューを効率的に要約します。

SELECT
  UNNEST(
    ai.generate(
      prompts => ARRAY_AGG('Summarize the review in 20 words or less. Review: ' || review),
      model_id => 'gemini-2.5-flash-lite',
    )
  ) AS review_summary
FROM user_reviews;

カーソルを使用してテキスト生成を行う

メモリのボトルネックを回避しながら数百万行の要約や翻訳を生成するには、カーソルを使用したバッチ生成を使用します。

CREATE TABLE summary_results(summary text);

DO $$
DECLARE
    prompt_cursor REFCURSOR;
    summary_cursor REFCURSOR;
    rec RECORD;
BEGIN
    OPEN prompt_cursor FOR SELECT review_text FROM user_reviews ORDER BY id;

    summary_cursor := ai.generate(
        'Summarize the review in 20 words or less. Review:',
        prompt_cursor,
    );

    LOOP
        FETCH summary_cursor INTO rec;
        EXIT WHEN NOT FOUND;
        INSERT INTO summary_results VALUES(rec.output);
    END LOOP;

    CLOSE summary_cursor;
END $$;

クエリ結果をスコアリングする

カスタムの自然言語による指示を使用してクエリ結果を並べ替える必要がある場合は、ai.rank 演算子を使用します。

スカラー関数を使用してスコアリングを行う

次の関数を使用すると、ランキング基準を説明するプロンプトを指定し、各アイテムのスコアを返すことができます。

-- Function signature
FUNCTION ai.rank(prompt TEXT, model_id VARCHAR(100) DEFAULT NULL) RETURNS real

たとえば、次のクエリは、LLM のスコアを使用して、最も好意的なレストランのレビューの上位 20 件を取得します。

SELECT review AS top20
FROM user_reviews
ORDER BY ai.rank(
  'Score the following review according to these rules:
  (1) Score OF 8 to 10 IF the review says the food IS excellent.
  (2) 4 to 7 IF the review says the food is ok.
  (3) 1 to 3 IF the review says the food is not good. Here is the review:' || review) DESC
LIMIT 20;

配列ベースの関数を使用してスコアリングを行う

この ai.rank 関数を使用すると、カスタムの自然言語の指示に基づいてクエリ結果をスコアリングしてランク付けできます。

FUNCTION ai.rank(prompts TEXT[], model_id VARCHAR(100) DEFAULT NULL) RETURNS real[]

次のクエリは、UNNEST と ai.rank を使用して複数のレビューを効率的にスコアリングします。

SELECT
  UNNEST(
    ai.rank(
      ARRAY_AGG('Score the following review according to these rules:
  (1) Score OF 8 to 10 IF the review says the food IS excellent.
  (2) 4 to 7 IF the review says the food is ok.
  (3) 1 to 3 IF the review says the food is not good. Here is the review:' || review),
    )
  ) as review_scores
FROM user_reviews;

カーソルを使用してスコアリングを行う

この関数は、メモリ上限に達することなく大規模なデータセットをスコアリングするために使用されます。

FUNCTION ai.rank(context TEXT, input_cursor REFCURSOR, model_id VARCHAR(100) DEFAULT NULL) RETURNS REFCURSOR

次の例は、特定の自然言語基準に従って大量のテキストをスコアリングする方法を示しています。

CREATE TABLE scored_results(input text, score real);

DO $$
DECLARE
    prompt_cursor REFCURSOR;
    score_cursor REFCURSOR;
    rec RECORD;
BEGIN
    OPEN prompt_cursor FOR SELECT review FROM user_reviews ORDER BY id;

    score_cursor := ai.rank(
        'Score the following review: (1) 8-10 if excellent, (2) 4-7 if ok, (3) 1-3 if not good. Review:',
        prompt_cursor,
    );

    LOOP
        FETCH score_cursor INTO rec;
        EXIT WHEN NOT FOUND;
        INSERT INTO scored_results VALUES(rec.input, rec.output);
    END LOOP;

    CLOSE score_cursor;
END $$;

次のステップ