ラズパイで取得したセンサー値をGoogleSpreadSheetsでグラフ化する【BigQuery蓄積編】(3/4)

[ラズパイで取得したセンサー値をGoogleSpreadSheetsでグラフ化する](https://qiita.com/tnagao3000/private/2059938038a685b2ec8f)のBigQuery蓄積編です。

前回まででラズパイのセンサー値は定期的にPub/Subにパブリッシュされるようになっています。
今回はそれをCloudFunctionsでサブスクライブしてBigQueryにインサートします。

図にすると次の通りです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/577fe5cf-6eb3-6dd6-92fc-5c5d0a138acb.png)

今回は次の順に設定を行います。

- [BigQueryにテーブルを作る](#bigquery%E3%81%AB%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E4%BD%9C%E3%82%8B)
    - データセットを作成する
    - テーブルを作成する
- [CloudFunctionsに関数を作る](#cloudfunctions%E3%81%AB%E9%96%A2%E6%95%B0%E3%82%92%E4%BD%9C%E3%82%8B)
    - 関数を書く
    - 関数を登録する
    - 関数の処理結果を確認する

## BigQueryにテーブルを作る
BigQueryにはデータセットというテーブルをまとめる単位があり、
テーブルはその中に作る必要があります。

よって今回はデータセットとテーブルを１つずつ作成します。
これらの正確なところは以下の公式で確認してください。

- [データセットの作成](https://cloud.google.com/bigquery/docs/datasets?hl=ja#create-dataset)
- [テーブルの作成](https://cloud.google.com/bigquery/docs/tables?hl=ja#create-table)


また記事内では設定に以下の名前を付けました。

|サービス|項目|名前|
|:--|:--|:--|
|BigQuery|データセット|sensor_dataset|
|BigQuery|テーブル|sensor_table|
|CloudFunctions|関数|raspi-comfort-sensor-function|

### データセットを作成する

ウェブUIでBigQueryを選択すると次の画面が出てくるので
Create new datasetを選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/acfa0636-2e19-9342-a587-9a8dcd862f3a.png)


すると小窓が出てくるのでデータセット名とロケーションを指定します。
有効期限の指定はなんでもいいです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/ee6799fb-681a-8589-e2c7-d7c3f48540f9.png)

以上でデータセットが出来ました。

### テーブルを作成する

空のテーブルを１つ作成します。
データセットのプルダウンからCreate new tableを選択します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/c01831c8-af9b-0069-b089-dcb893f8fc6e.png)

次の画面でテーブル名、カラム名、カラムの型を指定します。
※ カラム名とカラムの型はサブスクライブするjsonと合致している必要があります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/7ca1254b-ba1a-e95f-1bda-6072b21d80ca.png)


以上でテーブルが出来ました。

## CloudFunctionsに関数を作る

CloudFunctionsは [サーバーレスなNode.jsランタイム環境](https://cloud.google.com/functions/docs/concepts/overview?hl=ja) です。

今回はサブスクライブ(push配信)がトリガーとなってCloudFunctionsの
関数が起動し、データをBigQueryにインサートするようにします。

#### メモ (その１)

公式の [push配信とpull配信](https://cloud.google.com/pubsub/docs/subscriber#push_pull) によるとPub/Subデータが多い場合
（１秒間に１個超）は、pull配信を選択するよう記載されています。

CloudFunctionsはpush配信になるので、もしそのような要件なら
代わりに [CloudDataflow](https://cloud.google.com/dataflow/docs/templates/provided-templates?hl=ja#cloud-pubsub--bigquery-) を選択せよということだと思います。

#### メモ (その２)

今回は無視していますが [at-least-once配信](https://cloud.google.com/pubsub/docs/subscriber#at-least-once-) によると関数は
**べき等** である必要があります。
<br>
### 関数を書く

下記のリファレンスなどを参考にセンサー値を
BigQueryにインサートする関数を作ります。

- [Google Cloud Pub/Sub Triggers ](https://cloud.google.com/functions/docs/calling/pubsub)
- [Node.js client for Google Cloud BigQuery](https://github.com/googleapis/nodejs-bigquery)

出来たソースは次の２つです。
subscribe()がデータ受信時に呼ばれます。

```json:package.json
{
  "name": "raspi-comfort-sensor-pubsub2bigquery",
  "version": "0.0.1",
  "repository": "googleapis/nodejs-bigquery",
  "dependencies": {
    "@google-cloud/bigquery": "1.0.0"
  }
}
```

```javascript:index.js
/**
 * Triggered from a message on a Cloud Pub/Sub topic.
 *
 * @param {!Object} event The Cloud Functions event.
 * @param {!Function} The callback function.
 */
exports.subscribe = function subscribe(event, callback) {

  //----------------------------
  // payloadを取得
  //----------------------------
  const payload = Buffer.from(event.data.data, 'base64').toString()

  //----------------------------
  // insert
  //----------------------------
  const BigQuery = require('@google-cloud/bigquery');
  const bigquery = BigQuery({ projectId: 'raspi-comfort-sensor' });

  bigquery
    .dataset('sensor_dataset')
    .table('sensor_table')
    .insert(JSON.parse(payload))

  .then(function(result) {

    console.log('BQ INSERTED : ' + payload);
    callback();
  })
  .catch((err) => {
    console.error('BQ ERROR : ', err);
    callback(1);
  });
};
```

### 関数を登録する

ウェブUIのインラインエディタを使って登録します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/d5ab3b5a-e839-3817-9fc7-3eaed1af327f.png)

以上で登録完了です。

### 関数の処理結果を確認する

関数が想定通り動いているかどうか確認ためには、CloudFunctionsのログを
見るか、またはBigQueryのテーブルの中身を参照する必要があります。

例えばテーブルの中身は次のようなクエリをウェブUIで投げて参照します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/26808/16072d0c-6955-cad5-a31a-4976387994db.png)

以上でセンサー値の蓄積まで確認できました。

次は [グラフ化編](https://qiita.com/tnagao3000/private/cf3a6d6ea366e81678f7) です。