BigQueryのローカル検証用にbigquery-emulatorを触ってみた。ついでにPythonから接続してみる

# はじめに

みなさん、BigQueryが絡む処理のローカル開発やテストどうしてますか？BigQueryは公式のエミュレーターが提供されていないのでけっこう困ること多いんじゃないでしょうか？

私はとりあえず、ローカルではなく専用の環境を用意してそこに接続する形にしていましたが、業務委託の方などに入っていただくことが増えると権限周りで少々悩ましいことも多いです。

ただ数ヶ月前に、goccyさんという方が開発されたGo製のOSS`bigquery-emulator`が公開され、こうした問題に解消の兆しが見えてきました。(開発者の方にはリスペクトしかありません！)

https://github.com/goccy/bigquery-emulator

少し前までは提供されていない機能も多かったのですが、開発が進み環境が整ってきているようなので、今回はこの`bigquery-emulator`を触ってみようと思います。

# 実行準備

今回は提供されているdockerイメージを利用して作業をしていくので、リポジトリのクローンは不要です。

※ docker, docker-composeを利用できるようにしておいてください

#### 環境

- OS: macOS Big Sur(11.1)

# やってみる
#### CLIからのクエリ実行
まずは起動 -> CLIからのクエリ実行を確認します。

ディレクトリ構成は以下の通りです。
```
.
├── docker-compose.yaml
└── testdata
    └── data.yaml

```

ここだけであればcomposeは必須でないですが、後でpythonコンテナから接続したいのでcomposeを利用しています。

中身は以下の通り
```docker-compose.yaml
version: '3.7'
services:

    bq:
        image: ghcr.io/goccy/bigquery-emulator:latest
        ports:
            - "9050:9050"
        volumes:
            - ./testdata:/testdata
        command: "bigquery-emulator --project=test --data-from-yaml=../testdata/data.yaml"

```

`./testdata/data.yaml`には起動時に挿入するデータを指定しておきます。(これはリポジトリのものをそのまま拝借)
```data.yaml
projects:
- id: test
  datasets:
    - id: dataset1
      tables:
        - id: table_a
          columns:
            - name: id
              type: INTEGER
            - name: name
              type: STRING
          data:
            - id: 1
              name: alice
            - id: 2
              name: bob
```

コンテナを立ち上げれば9050番ポートでbigquery-emulatorが起動し、`test`という名前のプロジェクト名で`data.yaml`に記述したデータについてクエリをかけられるようになるので確認してみましょう！

以下、ターミナルから実行します。
```shell
# 起動
$ docker-compose up -d

# クエリ
$ bq --api http://0.0.0.0:9050 query --project_id=test "SELECT id, name FROM dataset1.table_a WHERE id = 1"

+----+-------+
| id | name  |
+----+-------+
|  1 | alice |
+----+-------+
```

無事にクエリ結果が得られました。


#### pythonクライアントからのクエリ実行

ここまででもローカルで実行できることに感動ものなのですが、せっかくなのでpythonからも接続してみます。

pythonコンテナ用にDockerfileを追加し、docker-compose.yamlを修正します。
Dockerfileでは、BigQueryのクライアントをインストールしておきます。

```shell
$ touch Dockerfile
```

```Dockerfile
FROM python:3.8

RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install google-cloud-bigquery

COPY app app
WORKDIR /app
```

```docker-compose.yaml
version: '3.7'
services:

    # 追記
    app:
        restart: always
        build: .
        tty: true
        volumes:
            - ./app:/app

.
.
.
```

pythonで実行するコードは`app/main.py`に以下の通り追加します。
```shell
$ mkdir app
$ touch app/main.py
```

```main.py
from google.cloud import bigquery
from google.auth.credentials import AnonymousCredentials


project_id = "test"
client = bigquery.Client(
    project=project_id,
    credentials=AnonymousCredentials(),
    client_options={
        "api_endpoint": "http://host.docker.internal:9050",
    }
)

table_name = f"{project_id}.dataset1.table_a"

query = f'''
SELECT id, name FROM `{table_name}`
'''
result = client.query(query)
for row in result:
    print(row)

```

`AnonymousCredentials`はエミュレーターなどのためにダミーで渡すことのできるcredentialsクラスで、こうしておくことで認証情報を渡さずに認証部分を突破できます。

また今回はコンテナ間で接続するので、エンドポイントが`http://host.docker.internal:9050`になる点にも注意してください。

それではコンテナをbuildしてから実行してみます。

```shell
$ docker-compose build --no-cache
$ docker-compose up -d

# 実行
$ docker-compose exec app python main.py
```

以下の通りクエリ結果が得られました。
```shell
Row((1, 'alice'), {'id': 0, 'name': 1})
Row((2, 'bob'), {'id': 0, 'name': 1})
```


# 最後に

今回はbigquery-emulatorを少し触ってみました。
すでにおおよそ整備されているので非常に簡単に扱えそうですね！感謝！

これを機にローカル開発環境やテスト環境を本格的に整備して行こうかなーなど考えてます。

というわけで今回はこれにて！