やりたいこと
タイトルの通り。
動機
とあるAPIから取得できるデータ(ex. 実行ログとか)をBigQueryで分析できるようにしたい。
いままでは専用のジョブを作ったりしてたけど、そもそもBQで直接取れるのでは?と思ったのと、軽く検索した感じ同じようなことやってる人が見つからなかったのでやってみた。
BigQuery Remote Functionsとは
BigQuery リモート関数を使用すると、SQL と JavaScript 以外の言語や、BigQuery ユーザー定義関数で許可されていないライブラリやサービスを使用して関数を実装できます。
ドキュメントのサンプルでは「引数の数値を足し算したものを返す」関数の例がある。
もっと色々できるはずだと思ったので、思いついたのが今回のもの。
必要なもの
- BigQuery
- Cloud Functions(Cloud Run Functions)
- Cloud Runでもよい
- なんらかのJSONを返すAPI
- 今回はGitHubのAPIを使ってみた
実装
Cloud Functions
ソースコード
適当に書いた。サンキューChatGPT。
import requests
import functions_framework
from flask import jsonify, request
@functions_framework.http
def get_github_repos(request):
# POSTリクエストのJSONボディから`username`を取得
request_json = request.get_json(silent=True)
calls = request_json["calls"]
replies = []
print("==debug==")
print(calls)
print("==debug==")
for call in calls:
# GitHub APIのURL
url = f"https://api.github.com/users/{call[0]}/repos"
print(f"call {url}")
response = requests.get(url)
# GitHub APIからのレスポンスを処理
if response.status_code == 200:
repos = response.json()
replies.append(repos)
else:
return jsonify({"error": "Failed to fetch repositories"}), response.status_code
return jsonify({"replies": replies})
- 引数に指定したユーザーのpublic repositoryを取得する。
-
request
に入るパラメータは、BigQuery Remote Functions側で指定されたものがあるので、それを想定する。
Functionsの設定
ポイントだけ。
- リージョン:
us-central1
- BigQueryのデータセットをマルチリージョンにしちゃったので、USから適当に選んだ。
- データセットを単一リージョンにしてTokyoとかを選べば、FunctionもTokyoでいけると思う。
- 権限:
bqcx-xxxp@gcp-sa-bigquery-condel.iam.gserviceaccount.com
に起動元ロール(Cloud Functions 起動元)をつける- このサービスアカウントは、後でBigQuery Remote Functionsを作成したときに自動生成されるもの。
BigQuery
Remote Functions
https://cloud.google.com/bigquery/docs/remote-functions?hl=ja#create_a_remote_function
上記を参考に設定
関数を作るDDLは以下のような感じ。
CREATE FUNCTION `PROJECT_ID`.DATASET_ID.get_api(x STRING) RETURNS JSON
REMOTE WITH CONNECTION `PROJECT_ID.us.api-functions`
OPTIONS (
endpoint = 'https://us-central1-PROJECT_ID.cloudfunctions.net/get-api-1'
)
実行
とれた。
おわりに
- とりあえず適当に書いたけど思った通りのことができた。使いみちあるかなあ。
- 本気で使うなら、APIバカスカ実行しないようにキャッシュなりを実装しないといけない。
- Functions側のIP固定もしたいだろうからVPCサービスコネクタあたりが必要そう。
- ゴリッと取ってきた値を1行に入れてるから、本当は要素ごとに行は分けたい。
- Remote Functionsはもっといろんな使い道があると思うんだがなかなか使いこなせてない。