はじめに
GCSにあるログファイルや非構造化テキストデータを、とりあえずBigQueryの外部テーブル(External Table)として参照したいケースがあります。
CSVやJSONではなく、「テキストファイルの1行を、そのまま1つのSTRING型カラムとして扱いたい」 という要件です。
BigQueryには純粋な「テキストファイル」というフォーマット指定がないため、Terraformで実装する際には少し工夫が必要です。また、区切り文字(delimiter)の選定でハマりやすいポイントがあったため、その解決策を含めて共有します。
結論:完成したTerraformコード
先に完成形のコードを提示します。
ポイントは csv_options 内の field_delimiter に Unit Separator (\u001F) を指定している点です。
resource "google_bigquery_table" "external_text_table" {
dataset_id = "your_dataset_id"
table_id = "raw_text_table"
external_data_configuration {
autodetect = false
source_uris = ["gs://your-bucket-name/path/to/logs/*.txt"]
# テキストファイルでも形式は "CSV" を指定する
source_format = "CSV"
csv_options {
# 引用符の処理を無効化(データ内の " が悪さをしないようにする)
quote = ""
# 【重要】データ内に絶対に含まれない制御文字を区切り文字にする
# \u001F (Unit Separator) はASCII制御文字であり、確実に1バイトとして扱われる
field_delimiter = "\u001F"
skip_leading_rows = 0
}
}
# 1行を格納する単一カラムを定義
schema = <<EOF
[
{
"name": "data",
"type": "STRING",
"mode": "NULLABLE",
"description": "Raw text line"
}
]
EOF
}
解説:設定のポイント
1. source_format = "CSV"
BigQueryには「行単位のテキスト」というネイティブなフォーマット設定はありません。そのため、形式上は CSV として定義し、CSVパーサーの設定を調整することで擬似的にテキスト読み込みを実現します。
2. field_delimiter の罠と正解
ここが最大のハマりポイントです。
行を分割させないためには、「テキスト内に絶対に出現しない文字」 を区切り文字に設定する必要があります。
失敗例:\u00FF などの特殊文字
「使われていない文字」として \u00FF (ÿ) などを指定したくなりますが、TerraformからAPIを叩く際、UTF-8エンコードによって 2バイト (0xC3 0xBF) に変換されて送信されてしまうことがあります。
BigQueryの field_delimiter は ISO-8859-1 エンコーディングのシングルバイト文字 である必要があるため、以下のエラーが発生します。
Error: googleapi: Error 400: Field delimiter must be a single byte.
成功例:\u001F (Unit Separator)
そこで、ASCIIコードに含まれる制御文字を使用します。
\u001F (Unit Separator: ユニット区切り文字) は、ASCIIの範囲内(0x1F)であるため、UTF-8環境下でも確実に 1バイト であることが保証されます。
通常のテキストデータにこの制御文字が含まれることはまずないため、安全に「行全体を1カラム」として読み込むことができます。
3. quote = ""
デフォルトでは二重引用符(")が引用文字として機能します。
ログやテキスト内に " が含まれていると、そこから次の " までが1つの値としてパースされてしまい、改行が無視されるなどの意図しない挙動になります。
quote = ""(空文字)を指定することで、引用符の処理を完全に無効化します。
まとめ
- BigQueryで生のテキストファイルを読み込むときは
CSV形式を利用する - 区切り文字には、データに含まれない文字を選ぶ必要がある
-
field_delimiterはシングルバイト制限があるため、\u00FFではなく\u001F(Unit Separator) を使うのが安全かつ確実