はじめに
こんにちは、石原です。
生成 AI と大規模言語モデル(LLM)の普及により、SQL だけでテーブル内データを直接プロンプトに渡し、その場で要約や翻訳を返す 方法が主要データウェアハウスに実装され始めています。従来は Python などで外部 API を呼び出し、結果を再ロードする必要がありましたが、現在ではクエリと生成をワンステップで統合可能になりました。
代表例が BigQuery の ML.GENERATE_TEXT
と、Snowflake の Cortex LLM 関数(COMPLETE
など)。どちらも「SQL ネイティブに LLM を呼び出し、レスポンスを行・列として受け取る」という共通コンセプトを持っていますが記述方法には違いがあります。
本記事では BigQuery と Snowflake の LLM 関数を実際に比較し、それぞれ実装されている処理や呼び出し方法について比較してみます。
比較対象の概要
それぞれの関数についてまとめてみました。
観点 | BigQuery ML | Snowflake Cortex |
---|---|---|
実装されている関数 | ML.GENERATE_TEXT ML.GENERATE_EMBEDDING AI.GENERATE_TABLE | COMPLETE CLASSIFY_TEXT EXTRACT_ANSWER PARSE_DOCUMENT SENTIMENT SUMMARIZE TRANSLATE EMBED_TEXT _768 EMBED_TEXT _1024 |
バックエンド LLM | gemini-1.5-pro-002, gemini-1.5-flash-002, claude-3-sonnet, mistral-large, llama-3.3-70B など | claude-3-7-sonnet, llama4-maverick, mistral-large2, jamba-1.5-large, snowflake-arctic など |
BigQuery MLのポイント
パラメータはSTRUCTで入力
STRUCT(.15 AS TEMPERATURE)
のように埋め込みます。
MODEL 句を介して呼び出す
Remote Model を CREATE MODEL
で登録 → ML.GENERATE_TEXT
に渡すフローが必須です。
呼び出し例
SELECT *
FROM
ML.GENERATE_TEXT(
MODEL `mydataset.gemini_flash`,
(SELECT 'What is the purpose of dreams?' AS prompt),
STRUCT( .15 AS TEMPERATURE)
);
Snowflake Cortex のポイント
シンプルな関数の呼び出し
COMPLETE()
, EMBED()
などをそのまま SELECT 句で呼ぶことができます。また、モデルは関数の引数としてシンプルに指定可能です。
パラメータは関数のオプション引数として入力
pythonなどでよく使われるjson形式での入力ができます。
呼び出し例
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'mistral-7b',
[
{
'role': 'user',
'content': 'What are large language models?'
}
],
{
'temperature': 0.7,
'max_tokens': 10
}
);
それぞれを実行してみる
BigQueryML
下記のコードを実行してみます。
SELECT *
FROM
ML.GENERATE_TEXT(
MODEL `mydataset.gemini_flash`,
(SELECT 'What are large language models??' AS prompt),
STRUCT( .15 AS TEMPERATURE)
);

出力結果が長いですね。もう少し出力結果を絞りこむには下記で対応できます。
SELECT
ml_generate_text_result['candidates'][0]['content'] AS generated_text,
* EXCEPT (ml_generate_text_result)
FROM
ML.GENERATE_TEXT(
MODEL `mydataset.gemini_flash`,
(SELECT 'What are large language models?' AS prompt),
STRUCT( .15 AS TEMPERATURE)
);

ただし、この方法でもJSON形式での出力なのでよりシンプルに文字列として取得したい場合はflatten_json_output=True
にするのが良いかと思います。
SELECT
ml_generate_text_result[‘candidates’][0][‘content’] AS generated_text,
- EXCEPT (ml_generate_text_result)
FROM
ML.GENERATE_TEXT(
MODELmydataset.gemini_flash
,
(SELECT ‘What is the purpose of dreams?’ AS prompt),
STRUCT( .15 AS TEMPERATURE)
);

これならml_generate_text_llm_resultが出力結果としてそのまま利用できます。
画像や動画などの非構造データの入力も可能です。その場合、オブジェクトテーブルを使用する構文を使用する必要があります。
Snowflake Cortex
下記のコードを実行してみます。
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'mistral-7b',
[
{
'role': 'user',
'content': 'What are large language models?'
}
],
{
'temperature': 0.7,
'max_tokens': 10
}
) as genetated_text;

こちらも、出力結果を絞りこむには下記で対応できます。
SELECT SNOWFLAKE.CORTEX.COMPLETE(
'mistral-7b',
[
{
'role': 'user',
'content': 'What are large language models?'
}
],
{
'temperature': 0.7,
'max_tokens': 10
}
)['choices'][0]['messages'] as genetated_text;

Snowflake Cortexでの画像の入力方法についてはこちらの記事もあわせてご確認下さい。
テーブルのそれぞれの値に対して適用する方法
上記で紹介した方法は単発のプロンプトに対しての回答のみです。
それぞれテーブルの特定のカラムについて処理を行う場合は下記のように記述することが出来ます。
BigQueryML
SELECT
*
FROM
ML.GENERATE_TEXT(
MODEL `exture-common-sandbox-lab.ml_model.gemini_flash`,
(
SELECT
id,
name,
CONCAT(
'Provide a category name appropriate for the following product in one word only. If it cannot be determined, return as not determinable.',
name,
'\nCategory:') AS prompt
FROM product
),
STRUCT(TRUE AS flatten_json_output));
Snowflake Cortex
SELECT
id,
name,
SNOWFLAKE.CORTEX.COMPLETE(
'mistral-large',
CONCAT('Provide a category name appropriate for the following product in one word only. If it cannot be determined, return as not determinable.', name)
)
FROM product;
これらのクエリではCONCAT句で、productテーブルのname要素からカテゴリーを作成するような処理を実行しています。こちらで作成した結果からテーブルの要素全てに処理を適応することが出来ます。
その他のLLM関数について紹介
今回紹介した汎用関数以外にもタスク固有の関数や出力が特殊なものがありますのでいくつか紹介します。
BigQueryML
エンベディング関数を除く関数については現段階ではプレビューになっています。
エンベディングモデルを使用してエンベディングを実施します。
エンベディングモデルによっては、オブジェクトテーブルやObject Ref型として定義されている画像などのエンベディングも実行可能です。
下記のように文字列からoutput_schemaに従ったテーブルを作成可能です。
SELECT
address,
age,
is_married,
name,
phone_number,
weight_in_pounds
FROM
AI.GENERATE_TABLE( MODEL `mydataset.gemini_model`,
(
SELECT
'John Smith is a 20-year old single man living at 1234 NW 45th St, Kirkland WA, 98033. He has two phone numbers 123-123-1234, and 234-234-2345. He is 200.5 pounds.'
AS prompt
),
STRUCT("address STRING, age INT64, is_married BOOL, name STRING, phone_number ARRAY<STRING>, weight_in_pounds FLOAT64"
AS output_schema, 8192 AS max_output_tokens));
組み込みの TimesFM モデルを使用して時系列予測を事前学習なしで実施します。
horizon
:予測ポイント数
confidence_level:信頼区間の設定
SELECT *
FROM
AI.FORECAST(
(
SELECT TIMESTAMP_TRUNC(start_date, HOUR) as trip_hour, COUNT(*) as num_trips
FROM `bigquery-public-data.san_francisco_bikeshare.bikeshare_trips`
WHERE subscriber_type = 'Subscriber' AND start_date >= TIMESTAMP('2018-01-01')
GROUP BY TIMESTAMP_TRUNC(start_date, HOUR)
),
horizon => 720,
confidence_level => 0.95,
timestamp_col => 'trip_hour',
data_col => 'num_trips');
Geminiモデルに対してプロンプトを投げる関数です。ML.GENERATE_TEXTとほぼ同じ用途で用いることができます。(出力型の指定もoutput_schema
により可能)
エンドポイント経由でアクセスするため、リモートモデルの作成が不要です。
AI.GENERATE_BOOL
AI.GENERATE_DOUBLE
AI.GENERATE_INT
上記はそれぞれ関数名にある通りの型だけを返します。
Snowflake Cortex
タスク固有の関数が作成されており、用途に合致する場合、プロンプトエンジニアリングによる調整がなくとも高い精度で実行が可能になっています。
テキストを指定したカテゴリの内のいずれかに分類します。
ソースの情報をもとに質問に対して回答を行います。
ステージに保存されているドキュメントを解析します。
OCRモードとLAYOUTモードが存在し、OCRモードではテキストを抽出、LAYOUTモードではマークダウン形式で表などをそのままの形で抽出します。
感情分析を実行できます。ENTITY_SENTIMENT関数は全体的な感情分析と詳細な感情分析の双方を提供します。一方で、SENTIMENT関数はネガティブ・ポジティブの感情スコアを返し、より高速で低コストに実行可能です。
製品分析のためのレビューや肯定的・中立的・否定的・混合など微妙な感情の識別を必要とするケースではENTITY_SENTIMENT関数が適しており、大量の顧客フィードバックへのラベル付けなどのケースではSENTIMENT関数が適しています。
文章の要約を行います。現状英語のみ対応で、日本語文章を入れた場合にも英語へ変換されてしまいます。
文章を別の言語に翻訳します。精度としては英語をソースかターゲットにしている場合が最良の結果となります。
上記SUMMARIZE関数の結果から翻訳することで実質的に日本語文書の要約も可能です。

EMBED_TEXT _768
EMBED_TEXT _1024
テキストからエンベディングを生成します。それぞれの関数末尾の数値だけの次元のベクトルを作成します。
まとめ
- 呼び出し方の思想が異なる
- BigQuery ML は リモートモデルを作成 → 関数で利用 という 2 ステップ。
- プレビューで公開されているAI.GENERATE関数ではよりシンプルに呼び出しが可能
- Snowflake Cortex は シンプルな関数で即実行できる。
- BigQuery ML は リモートモデルを作成 → 関数で利用 という 2 ステップ。
- 仕様について
- BigQuery ML は出力が特定の列に格納されるので実装時にドキュメントの確認は必要。デフォルトでsafety_settingsが有効になっている。Google検索によるGroundingに対応。
- Snowflake Cortex は 入力形式がシンプルで使いやすい。ロール・履歴の設定が可能(OpenAIの形式やLangChainなどの形式で入力可能)。Cortex Guardを使用したフィルタリングがオプションで対応可能。
- モデル選択の柔軟性
- BigQuery ML:Gemini、Claude、Mistral、Llama 3 系など Vertex AIのモデルガーデン上で提供される複数のモデルを使用できる
- Snowflake Cortex:Claude 3 Sonnet、Llama 4 Maverick、Mistral Large2、Jamba 1.5 Large、Snowflake Arctic など複数のモデルを使用できる
- どちらを選ぶか
- 既にGCP上で分析基盤を運用しており、Looker StudioやBQ とでの処理と連携したい。Google検索によるGroundingを使用したい → BigQuery ML。
- 複数のモデルでの結果を元に簡単にA/Bテストしたい、または Snowflake 内でアプリ(Streamlit、Native App)まで完結させたい、定義済みの関数を利用したい → Snowflake Cortex。
結論としては、呼び出しやすさという点ではSnowflakeの方が簡単であると思いましたが、Google特有のGroudingオプションの有無など踏まえるとどちらかが優位という違いはないというように感じました。使用されているDWHによってそれぞれの関数を使用するのが良いかと思います。
参考
- Google BigQueryドキュメント
- Generative AI functions