1. はじめに
概要
BigQuery リモート関数を使用すると、SQL と JavaScript 以外の言語で関数を実装できます。また、BigQuery のユーザー定義関数で許可されていないライブラリやサービスを使用して関数を実装することもできます。BigQuery リモート関数は、Cloud Run 関数と Cloud Run を直接統合します。SQL クエリ内で BigQuery リモート関数を呼び出すには、1 つ以上の列を入力として受け取り、単一の値を出力として返します。
Cloud Run 関数は軽量なコンピューティング ソリューションで、デベロッパーはサーバーやランタイム環境を管理せずに、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 関数に送信します。この関数は、画像に関する VQA から回答を返します。
イラスト
開発の観点から、この Codelab で行う手順は次のとおりです。
- Cloud Run 関数で HTTP エンドポイントを作成する
- CLOUD_RESOURCE タイプの接続を作成する
- Cloud Storage バケットの BigQuery オブジェクト テーブルを作成する
- リモート関数を作成する
- 他のユーザー定義関数と同様に、クエリ内でリモート関数を使用します。
学習内容
- Python で HTTP Cloud Run 関数を作成する方法
- SQL クエリ内で BigQuery リモート関数を作成して使用する方法
- BigQuery オブジェクト テーブルを作成する方法
- Vertex AI SDK for Python を使用して Visual Question Answering(VQA)を使用する方法
2. 設定と要件
前提条件
- Cloud コンソールにログインしていること。
- 以前に HTTP Cloud Run 関数をデプロイしている。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 関数を作成する
BigQuery リモート関数を作成するには、まず Cloud Run 関数を使用して HTTP エンドポイントを作成する必要があります。エンドポイントは、単一の HTTP POST リクエストで行のバッチを処理し、バッチの結果を HTTP レスポンスとして返す必要があります。
この Cloud Run 関数は、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 関数をデプロイする
これで、python311 ランタイム用の Cloud Run 関数をデプロイできます。
Cloud Run 関数を Cloud Run に直接デプロイするには、次のコマンドを実行します。
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 Resource 接続を作成する
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 関数サービスの未認証の呼び出しを許可することはおすすめしません。
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 関数を呼び出せるようになりました。
まず、質問と 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 呼び出し元ロールの権限が BigQuery 接続サービス アカウントに伝播されるまで 1 ~ 2 分ほど待ってから、再試行してください。
11. 完了
これでこの Codelab は完了です。
BigQuery Remote Functions と Visual Question Answering(VQA)のドキュメントを確認することをおすすめします。
学習した内容
- Cloud Run 関数で認証を設定し、認証が正しく構成されていることを確認する方法
- gcloud ID のトークンを指定して、ローカル開発環境から認証済み関数を呼び出す
- サービス アカウントを作成し、関数を呼び出す適切なロールを付与する方法
- 関数の呼び出しに適切なロールを持つローカル開発環境のサービスに権限を委任する方法
12. クリーンアップ
誤って課金されないようにするには(たとえば、この Cloud Run 関数が 無料 tier の Cloud Run 関数の呼び出しの月間割り当てを超える回数誤って呼び出された場合など)、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
を実行します。