1. はじめに
概要
BigQuery リモート関数を使用すると、SQL と JavaScript 以外の言語や、BigQuery ユーザー定義関数で許可されていないライブラリやサービスを使用して関数を実装できます。BigQuery リモート関数は、 Cloud Run functions と Cloud Run を直接統合します。1 つ以上の列を入力として受け取り、単一の値を出力として返すことで、SQL クエリ内で BigQuery リモート関数を呼び出すことができます。
Cloud Run functions は、デベロッパーがサーバーやランタイム環境を管理することなく、HTTPS を使用してトリガーできる単一目的のスタンドアロン関数を作成したり、CloudEvents に応答したりできる軽量なコンピューティング ソリューションです。Cloud Run functions は、Node.js、Python、Go、Java、.NET、Ruby、PHP をサポートしています。
この Codelab では、Vertex AI の Visual Question & Answering(VQA) を使用して、Cloud Storage に保存されている画像に関する質問に回答する BigQuery リモート関数の作成方法について説明します。SQL クエリは、BigQuery のテーブルから画像の URI を取得します。次に、BigQuery リモート関数を使用して、画像 URI を Cloud Run functions の関数に送信します。この関数は、画像に関する VQA からの回答を返します。
イラスト

開発の観点から見ると、この Codelab で完了する手順は次のとおりです。
- Cloud Run functions で HTTP エンドポイントを作成する
- CLOUD_RESOURCE タイプの接続を作成する
- Cloud Storage バケットの BigQuery オブジェクト テーブルを作成する
- リモート関数を作成する
- 他のユーザー定義関数と同様に、クエリ内でリモート関数を使用する
学習内容
- Python で HTTP Cloud Run functions の関数を作成する方法
- SQL クエリ内で BigQuery リモート関数を作成して使用する方法
- BigQuery オブジェクト テーブルを作成する方法
- Vertex AI SDK for Python を使用して Visual Question Answering(VQA) を使用する方法
2. 設定と要件
前提条件
- Cloud コンソールにログインしていること。
- HTTP Cloud Run functions の関数をデプロイ済みであること。 Python クイックスタートをご覧ください。
- Cloud Storage にバケットを作成済みであること。 Cloud Storage クイックスタートをご覧ください。
- BigQuery 内でデータセット、テーブル、リモート関数を作成するための適切なロールがあること。 BigQuery でのデータの読み込みとクエリのクイックスタートをご覧ください。
Cloud Shell をアクティブにする
- Cloud Console で、[Cloud Shell をアクティブにする ]
をクリックします。

Cloud Shell を初めて起動した場合は、その内容を説明する画面が表示されます。その場合は、[続行] をクリックしてください。

すぐにプロビジョニングが実行され、Cloud Shell に接続されます。

この仮想マシンには、必要な開発ツールがすべてロードされています。永続的な 5 GB のホーム ディレクトリが用意されており、Google Cloud で実行されるため、ネットワーク パフォーマンスと認証が大幅に向上します。 この Codelab で行う作業のほとんどはブラウザから実行できます。
Cloud Shell に接続すると、認証が完了し、プロジェクトがプロジェクト ID に設定されていることがわかります。
- Cloud Shell で次のコマンドを実行して、認証されたことを確認します。
gcloud auth list
コマンド出力
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- Cloud Shell で次のコマンドを実行して、gcloud コマンドがプロジェクトを認識していることを確認します。
gcloud config list project
コマンド出力
[core] project = <PROJECT_ID>
上記のようになっていない場合は、次のコマンドで設定できます。
gcloud config set project <PROJECT_ID>
コマンド出力
Updated property [core/project].
3. ローカル環境変数を設定する
このコードでは、この Codelab で使用する gcloud コマンドの可読性を高めるために、いくつかの環境変数を作成します。
PROJECT_ID=$(gcloud config get-value project) # Cloud Function variables FUNCTION_NAME="imagen-vqa" FUNCTION_REGION="us-central1" # Cloud Function variables BUCKET_NAME=$PROJECT_ID-imagen-vqa # BigQuery variables DATASET_ID="remote_function_codelab" TABLE_NAME="images" BQ_REGION="US" CONNECTION_ID="imagen_vqa_connection"
4. Cloud Run functions の関数を作成する
BigQuery リモート関数を作成するには、まず Cloud Run functions の関数を使用して HTTP エンドポイントを作成する必要があります。エンドポイントは、単一の HTTP POST リクエストで行のバッチを処理し、バッチの結果を HTTP レスポンスとして返すことができる必要があります。
この Cloud Run functions の関数は、SQL クエリから画像ストレージ URI と質問プロンプトを入力として受け取り、Visual Question Answering(VQA)からの回答を返します。
この Codelab では、 Vertex AI SDK for Python を使用する python311 ランタイムの例を使用します。
関数のソースコードを作成する
まず、ディレクトリを作成して、そのディレクトリに移動します。
mkdir imagen-vqa && cd $_
次に、requirements.txt ファイルを作成します。
google-cloud-aiplatform[preview] google-cloud-storage functions-framework==3.*
次に、main.py ソースファイルを作成します。
from vertexai.preview.vision_models import ImageQnAModel
from vertexai.preview.vision_models import Image
from flask import jsonify
from google.cloud import storage
from urllib.parse import urlparse
import functions_framework
# This is the entry point for the cloud function
@functions_framework.http
def imagen_vqa(request):
try:
# See if you can parse the incoming JSON
return_value = []
request_json = request.get_json()
# This grabs the input into the function as called from the SQL function
calls = request_json['calls']
for call in calls:
# We call the VQA function here in another function defined below
ai_result = vqa(call)
# The result to BigQuery is in the order it was prepared in
return_value.append(ai_result[0])
# Prepare the response back to BigQuery
return_json = jsonify( { "replies": return_value } )
return return_json
except Exception as e:
return jsonify( { "errorMessage": str(e) } ), 400
# Helper function to split apart the GCS URI
def decode_gcs_url(url):
# Read the URI and parse it
p = urlparse(url)
bucket = p.netloc
file_path = p.path[0:].split('/', 1)
# Return the relevant objects (bucket, path to object)
return bucket, file_path[1]
# We can't use the image load from local file since it expects a local path
# We use a GCS URL and get the bytes of the image
def read_file(object_path):
# Parse the path
bucket, file_path = decode_gcs_url(object_path)
storage_client = storage.Client()
bucket = storage_client.bucket(bucket)
blob = bucket.blob(file_path)
# Return the object as bytes
return blob.download_as_bytes()
# This is the function that calls the VQA function
def vqa (parameters):
# This is the model we want to use
image_qna_model = ImageQnAModel.from_pretrained("imagetext@001")
# The location is the first parameter
image_loc = parameters[0]
# Get the bytes
image_bytes = read_file(image_loc)
# Load the bytes into the Image handler
input_image = Image(image_bytes)
# Ask the VQA the question
results = image_qna_model.ask_question(
image=input_image,
# The prompt was the second parameter
question=parameters[1],
number_of_results=1
)
return results
Cloud Run functions の関数をデプロイする
これで、python311 ランタイム用の Cloud Run functions の関数をデプロイできます。
Cloud Run functions に Cloud Run functions の関数を直接デプロイするには、次のコマンドを実行します。
gcloud beta run deploy $FUNCTION_NAME \
--source . \
--function imagen_vqa \
--region $FUNCTION_REGION \
--no-allow-unauthenticated
Cloud Functions(第 2 世代)としてデプロイする場合は、次のコマンドを使用します。
gcloud functions deploy $FUNCTION_NAME \ --gen2 \ --region=$FUNCTION_REGION \ --runtime=python311 \ --trigger-http \ --source=. \ --no-allow-unauthenticated
後で使用するために、関数 URL を環境変数として保存できます。
ENDPOINT_URL="$(gcloud beta run services describe $FUNCTION_NAME --region $FUNCTION_REGION --format='value(status.url)')"
5. Cloud Storage バケットを作成する
まず、画像を保存するための Cloud Storage バケットを作成します。
gcloud storage buckets create gs://$BUCKET_NAME
次に、VQA で使用する画像をアップロードします。この Codelab では、サンプル画像をVQA のドキュメントから使用します。
Cloud Storage 用の Cloud コンソールを使用して、画像をバケットに直接アップロードできます。または、次のコマンドを実行して、サンプル画像を現在の Cloud Shell ディレクトリにダウンロードすることもできます。
wget -O image.jpg -o /dev/null https://unsplash.com/photos/QqN25A3iF9w/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjk1NzYxMjY2fA&force=true
その後、Cloud Storage バケットにアップロードします。
gcloud storage cp image.jpg gs://$BUCKET_NAME
6. BigQuery Cloud リソース接続を作成する
BigQuery は CLOUD_RESOURCE 接続を使用して、Cloud Functions の関数とやり取りします。次のコマンドを実行して、この接続を作成します。
bq mk --connection --location=$BQ_REGION --project_id=$PROJECT_ID \ --connection_type=CLOUD_RESOURCE $CONNECTION_ID
次に、新しい BigQuery 接続の詳細を表示します。
bq show --connection $PROJECT_ID.$BQ_REGION.$CONNECTION_ID
BigQuery 接続サービス アカウントの名前を、次のように変数に保存します。
CONNECTION_SA="<YOUR-SERVICE-ACCOUNT-ID>@gcp-sa-bigquery-condel.iam.gserviceaccount.com"
Cloud Storage バケットにアクセスするためのアクセス権をサービス アカウントに付与します。
gsutil iam ch serviceAccount:$CONNECTION_SA:objectAdmin gs://$BUCKET_NAME
7. BigQuery オブジェクト テーブルを作成する
BigQuery オブジェクト テーブルは、Cloud Storage 内にある非構造化データ オブジェクトの読み取り専用テーブルです。
オブジェクト テーブルによって、Cloud Storage 内の非構造化データを分析できます。リモート関数で分析を行い、これらのオペレーションの結果を BigQuery の残りの構造化データと結合できます。
まず、データセットを作成します。
bq --location=$BQ_REGION mk \
--dataset \
$DATASET_ID
次のコマンドは、Cloud Storage イメージ バケットに基づいてオブジェクト テーブルを作成します。結果のテーブルには、そのバケット内のすべての画像の URI が含まれます。
bq mk --table \ --external_table_definition=gs://$BUCKET_NAME/*@$BQ_REGION.$CONNECTION_ID \ --object_metadata=SIMPLE \ $PROJECT_ID:$DATASET_ID.$TABLE_NAME
8. BigQuery リモート関数を作成する
最後の手順は、BigQuery リモート関数を構成することです。
まず、BigQuery 接続サービス アカウントに Cloud Run 関数を呼び出す権限を付与します。Cloud Run functions の関数サービスで認証されていない呼び出しを許可することはおすすめしません。
gcloud run services add-iam-policy-binding $FUNCTION_NAME \ --member=serviceAccount:$CONNECTION_SA \ --role="roles/run.invoker" \ --region $FUNCTION_REGION
次に、SQL クエリを変数に保存します。
SQL_CREATE_FUNCTION="CREATE FUNCTION \`$PROJECT_ID.$DATASET_ID\`.vqa(uri STRING, image_prompt STRING) RETURNS STRING REMOTE WITH CONNECTION \`$PROJECT_ID.$BQ_REGION.$CONNECTION_ID\` OPTIONS ( endpoint = '$ENDPOINT_URL' )"
クエリを実行します。
bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION
クエリを実行してリモート関数を作成すると、Created <your-project-id>.remote_function_codelab.vqa が表示されます。
9. SQL クエリで BigQuery リモート関数を呼び出す
これで、リモート関数を作成するための開発手順が完了しました。SQL クエリ内から Cloud Run functions の関数を呼び出すことができます。
まず、質問と SQL クエリを変数に保存します。この Codelab では、Visual Question Answering のドキュメントの例を使用します。このクエリでは、ストレージ バケットに追加された最新の画像を使用します。
export SQL_QUERY="DECLARE question STRING DEFAULT 'What objects are in the image?'; SELECT uri, image_prompt ,\`$DATASET_ID\`.vqa(uri, image_prompt) as result FROM ( SELECT *, dense_rank() over (order by updated) as rnk , question as image_prompt FROM \`$PROJECT_ID.$DATASET_ID.images\`) as innertable WHERE rnk = 1; "
次に、SQL クエリを実行して、Vertex AI Visual Question Answering(VQA)サービスからのレスポンスを表示します。
bq query --nouse_legacy_sql $SQL_QUERY
結果は、次の出力例のようになります。
+---------------------------------+--------------------------------+----------+ | uri | image_prompt | result | +---------------------------------+--------------------------------+----------+ | gs://<YOUR_BUCKET>/image.jpg | What objects are in the image? | marbles | +---------------------------------+--------------------------------+----------+
10. トラブルシューティング
BigQuery テーブルの作成時にエラー BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME が発生した場合は、コマンドの $BUCKET_NAME の後に /* パスが含まれていることを確認してください。
SQL クエリの実行時にエラー Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint> が発生した場合は、Cloud Functions Invoker ロール権限の付与が BigQuery 接続サービス アカウントに伝播するまで 1 ~ 2 分ほど待ってから再試行してください。
11. 完了
以上で、この Codelab は完了です。
BigQuery リモート関数と Visual Question Answering(VQA)のドキュメントを確認することをおすすめします。
学習した内容
- Cloud Run functions の関数で認証を構成し、認証が正しく構成されていることを確認する方法
- gcloud ID のトークンを指定して、ローカル開発環境から認証済み関数を呼び出す方法
- サービス アカウントを作成し、関数を呼び出すための適切なロールを付与する方法
- 関数を呼び出すための適切なロールを持つローカル開発環境からサービスを権限借用する方法
12. クリーンアップ
意図しない課金を避けるため(たとえば、この Cloud Run functions の関数が、無料枠の月間 Cloud Run functions の関数呼び出し割り当てよりも多く呼び出された場合)、Cloud Functions の関数を削除するか、ステップ 2 で作成したプロジェクトを削除します。
Cloud Run 関数を削除するには、Cloud Run Cloud コンソール(https://console.cloud.google.com/functions/)に移動し、imagen-vqa 関数(別の名前を使用した場合は $FUNCTION_NAME)を削除します。
プロジェクト全体を削除する場合は、https://console.cloud.google.com/cloud-resource-manager に移動し、ステップ 2 で作成したプロジェクトを選択して、[削除] を選択します。プロジェクトを削除する場合は、Cloud SDK でプロジェクトを変更する必要があります。gcloud projects list を実行すると、使用可能なすべてのプロジェクトのリストが表示されます。