7月19日、Brice Fotzoが「SQL Is All You Need: RAG without a Vector Database in a Dozen Lines of BigQuery」と題した記事を公開した。ベクトルDBもオーケストレーターも不要で、BigQueryのSQL関数だけでRAGパイプラインを構築する方法を解説している。
「RAGスタックの90%は不要」
LangChain、Pinecone、embedding API、複数のコンテナ——一般的なRAG(Retrieval-Augmented Generation)チュートリアルが前提とするアーキテクチャには、少なくとも5つのシステムと3つのAPIキーが登場する。しかもデータはウェアハウスの外に出る。BigQueryで丁寧に設定した行レベルセキュリティも、監査ログも、外部ベクトルストアにchunkを書き出した瞬間に意味をなさなくなる。
Brice Fotzoはこの前提を正面から否定し、BigQueryのAI関数だけで完結するRAGパイプラインを「十数行のSQL」で実現する方法を示している。
使用するデータは bigquery-public-data.bbc_news.fulltext。誰でも今すぐ手元で動かせる。
BigQueryに何が変わったか
BigQuery AI.* 関数群がGAに達し、RAGに必要な3つの操作がSQLの演算子として使えるようになった。各関数の公式ドキュメントは BigQuery AIリファレンス を参照されたい。
- **
AI.GENERATE_EMBEDDING**:テーブルから埋め込みをバッチ生成 - **
VECTOR_SEARCH**:セマンティック検索のネイティブ関数(IVFやTreeAHインデックスに対応。TreeAHはGoogleのScaNNアルゴリズムベース) - **
AI.GENERATE**:行単位の生成関数。output_schemaで型付き出力を指定でき、SELECTやWHERE、JOIN条件の中にも書ける
認証はコード中のAPIキーではなく、BigQueryの「接続(Connection)」という管理サービスアカウントで一元管理される。デフォルト接続を使えば、初回実行時にBigQueryが自動でプロビジョニングしてくれる。
なお、「Geminiに縛られるのでは」という懸念はよくある誤解で、Anthropic Claude、Meta Llama、Mistral AI、そしてHugging Faceのオープンソースモデルも利用できる。
Path 2:自動更新コーパス(Preview)
先にこちらを紹介する。Path 1(バッチ版)の本番運用上の根本的な問題は「データは静止しない」ことだ。新着記事が来るたびに差分検出・再埋め込み・リトライを自前で実装する必要がある。
これを解決するのが autonomous embedding generation(自律的埋め込み生成)だ。埋め込みをテーブルの生成列(Generated Column) として宣言すると、データの挿入・更新に連動してBigQueryがバックグラウンドで自動的にベクトルを生成・更新する。
CREATE TABLE `rag_demo_us.news_live` (
title STRING,
body STRING,
body_embedding STRUCT<result ARRAY<FLOAT64>, status STRING>
GENERATED ALWAYS AS (
AI.EMBED(
body,
connection_id => 'us.my_connection',
endpoint => 'gemini-embedding-001')
) STORED OPTIONS (asynchronous = TRUE)
);
asynchronous = TRUE により、INSERTは埋め込み生成の完了を待たずに返る。バックグラウンドジョブはジョブ履歴で gc_ プレフィックスで確認できる。
検索も AI.SEARCH 関数でシンプルになる。クエリを手動で埋め込む必要すらない。
SELECT base.title, base.body, distance
FROM AI.SEARCH(
TABLE `rag_demo_us.news_live`, 'body',
'major browser security stories',
top_k => 5
);
ただし この機能は現在Preview段階(プレGA条項が適用され、変更の可能性あり)。また、1テーブルあたり自動生成埋め込み列は1つのみ、頻繁なDMLよりバッチ挿入が推奨、テーブルのコピー・クローン・スナップショットは設定を引き継がない、といった制約も把握しておく必要がある。
Path 1:バッチ版パイプライン(GA)
モデルとコーパスの準備
まず埋め込みモデルを登録する(コンテナもエンドポイント管理も不要)。
CREATE OR REPLACE MODEL `rag_demo_us.emb_model`
REMOTE WITH CONNECTION DEFAULT
OPTIONS (ENDPOINT = 'gemini-embedding-001');
次に、BBCニュースのtech記事を一括で埋め込む。
CREATE OR REPLACE TABLE `rag_demo_us.news_emb` AS
SELECT *
FROM AI.GENERATE_EMBEDDING(
MODEL `rag_demo_us.emb_model`,
(
SELECT title, body AS content
FROM `bigquery-public-data.bbc_news.fulltext`
WHERE category = 'tech'
),
STRUCT('RETRIEVAL_DOCUMENT' AS task_type)
);
ここで2点注意がある。入力クエリは**content という列名を持つ必要がある**(エイリアスで対応)。また、task_type の使い分けが重要で、コーパス側は RETRIEVAL_DOCUMENT、ユーザーの質問側は RETRIEVAL_QUERY を指定する非対称埋め込みが検索精度を上げる。
落とし穴:サイレントな部分失敗。 バッチ全体は成功しても、個々の行がクォータ上限などで失敗していることがある。status 列が空でない行を必ず確認すること(成功行は status = '')。
検索と生成を1クエリで
SELECT
AI.GENERATE(
(
'Answer using only this context:\n',
STRING_AGG(base.content, '\n---\n'),
'\nQuestion: what were the major browser security stories?'
),
endpoint => 'gemini-2.5-flash',
output_schema => 'answer STRING, confidence FLOAT64, sources ARRAY<STRING>'
).*
FROM VECTOR_SEARCH(
TABLE `rag_demo_us.news_emb`, 'embedding',
(
SELECT embedding
FROM AI.GENERATE_EMBEDDING(
MODEL `rag_demo_us.emb_model`,
(SELECT 'major browser security stories' AS content),
STRUCT('RETRIEVAL_QUERY' AS task_type)
)
),
top_k => 5
);
output_schema が肝で、返ってくるのはJSONの文字列ではなく型付きの列(answer、confidence、sources)だ。パースコードは不要になる。
「無料でついてくる」ものの価値
記事が強調するのは機能よりもこちらかもしれない。
VECTOR_SEARCHに行レベル・列レベルセキュリティが適用される。 ユーザーが見られない行はRAGのコンテキストとしても取得されない。これを外部ベクトルDBとの同期で正しく実装するのがいかに困難かは、経験者なら分かるはずだ。- 認証はIAMのみ。 パイプラインコードにAPIキーを埋め込まない。
- 監査ログとコスト管理が既存のBigQueryの仕組みに乗る。
このアプローチが向かないケース
記事はメリットだけでなく、Pythonが依然として正しい選択肢であるケースも率直に挙げている。具体的には、サブ秒のレイテンシが求められるリアルタイム検索、BigQueryの外に存在するデータソース(アプリDBやファイルストレージなど)を直接扱う場合、LangGraphやLlamaIndexといったエージェントフレームワークの高度なオーケストレーション機能を必要とする場合などが該当する。データがすでにBigQueryに集約されており、セキュリティ・ガバナンス要件が厳しいバッチ系ユースケースで最も威力を発揮するアーキテクチャだ。ツールを正当化するために限界を隠さない点は、技術記事として誠実だ。
詳細はSQL Is All You Need: RAG without a Vector Database in a Dozen Lines of BigQueryを参照していただきたい。