Stream Firestore to BigQuery(旧Firestore BigQuery Export)はFirestoreの更新ログをBigQueryにストリームするFirebaseの拡張です。Firestore自身はその性質から集計や分析が非常に難しいため、上記の拡張を利用することでFirestore上のデータをBigQuery上のテーブルに流すことで集計が可能になります。
一方でFirestoreの変更のログがすべて吐き出されるため行数が多くなる・カラム型データストアであるBigQueryに対してFirestoreのデータはdata
カラムという1つのカラムに入るといったコスト面での課題があります。
その課題を解決する1つの策としてBigQueryのパーティション機能があります。簡単に言えば取り込み日時(取り込み日時以外も可能・数字も可能)によってテーブルを分割し、検索時に日付を絞ることで通常はテーブルの全行を検索するところパーティションで区切った範囲のみ検索対象になり、結果的にコストを抑えることができます。
Stream Firestore to BigQueryにも作成するテーブルをパーティション分割テーブルにする機能があります。今回はこの機能についての設定の注意点と備忘録です。
状況
Stream Firestore to BigQueryには下記の4つのパーティションに関する設定値があります。
- Time partitioning option type
- 設定の
TABLE_PARTITIONING
- テーブルを区切る単位(時間・日・月・年)
- 設定の
- Time partitioning column name
- 設定の
TIME_PARTITIONING_FIELD
- カラムの名前
- 設定の
- Time partitioning table schema
- 設定の
TIME_PARTITIONING_FIELD_TYPE
- カラムの型。
omit
を指定するのが良い
- 設定の
- Firestore document field name
- 設定の
TIME_PARTITIONING_FIRESTORE_FIELD
- Firestoreの特定のフィールドを指定して、それを基準にパーティションを分割する設定
- 設定の
これらの設定を記載しているのですが、パーティションが設定されない状態です。
結論
パーティションが適切に設定されるためには下記の2つのどちらかの状態でなければなりません。
TABLE_PARTITIONING
のみ設定されている- ちなみに
TIME_PARTITIONING_FIELD_TYPE
はomit
を指定すると内部的には「指定なし」という状況になります
- ちなみに
TABLE_PARTITIONING
・TIME_PARTITIONING_FIELD
・TIME_PARTITIONING_FIELD_TYPE
・TIME_PARTITIONING_FIRESTORE_FIELD
のすべてが設定されている
私の場合はTABLE_PARTITIONING
にDAY
・TIME_PARTITIONING_FIELD_TYPE
にTIMESTAMP
を設定していたため作成されませんでした。
また上記以外でも作成されない条件があるので記載します。物によってはエラーが出るのでinitBigQuerySync
から始まるCloud Functionのログを見てみると良いです。下記のようなケースがあります。
TABLE_PARTITIONING
が設定されていない- 既に同名のテーブルが有る
TABLE_PARTITIONING
を時間単位(HOUR)で設定しているが、TIME_PARTITIONING_FIELD_TYPE
の型がDATE
詳細
Firebaseの拡張はextension.yamlを見ると構成や設定値が分かります。今回はインストール時のBigQueryのテーブル作成が問題であると考え、lifecycleEvents
のonInstall
であるinitBigQuerySync
を探しました。それが下記です。
/** Init the BigQuery sync */
await eventTracker.initialize();
読んでいって、パーティションを作成していそうな関数を見つけます。
//Add partitioning
await partitioning.addPartitioningToSchema(schema.fields);
await partitioning.updateTableMetadata(options);
上記ですが2つ関数があります。BigQueryのパーティションを雰囲気で理解していたので気づかなかったのですが、実はBigQueryの2種類のパーティショニングをサポートしており、それぞれの関数が対応しています。
上は 時間単位列パーティショニングであり、ユーザーが指定したカラムを利用してパーティショニングを行うものです。下は取り込み時間パーティショニングであり、BigQueryに取り込まれた時間を利用してパーティショニングを行います。_PARTITIONTIME
という特別なカラムが作成されます。
addPartitioningToSchemaもupdateTableMetadataも複数の条件により設定値を確認しています。
私はこの中のhasValidCustomPartitionConfig
に引っかかってパーティションが作成されていませんでした。
private hasValidCustomPartitionConfig() {
/* Return false if partition type option has not been set*/
if (!this.isPartitioningEnabled()) return false;
const {
timePartitioningField,
timePartitioningFieldType,
timePartitioningFirestoreField,
} = this.config;
const hasNoCustomOptions =
!timePartitioningField &&
!timePartitioningFieldType &&
!timePartitioningFirestoreField;
/* No custom config has been set, use partition value option only */
if (hasNoCustomOptions) return true;
/* check if all valid combinations have been provided*/
const hasOnlyTimestamp =
timePartitioningField === "timestamp" &&
!timePartitioningFieldType &&
!timePartitioningFirestoreField;
return (
hasOnlyTimestamp ||
(!!timePartitioningField &&
!!timePartitioningFieldType &&
!!timePartitioningFirestoreField)
);
}
若干条件文が分かりづらいですが、hasNoCustomOptions
はTABLE_PARTITIONING
のみが設定されているケース。それ以外では3つのプロパティがすべて設定されているケースです。
が、hasOnlyTimestamp
という文言を見るとTIME_PARTITIONING_FIELD_TYPE
がTIMESTAMP
でも問題ないように見えますが、timePartitioningField
がtimestamp
の場合という感じです(timestamp
はこの拡張のデフォルトで作成するカラム)。
色々設定を変更して試していたところTIME_PARTITIONING_FIELD_TYPE
だけ設定した状態を引き継いでいたせいでこの様な状態になっていました。