| 入力 | 出力 | エイリアス |
|---|---|---|
| ✔ | ✔ |
説明
Protobuf 形式は、Protocol Buffers のフォーマットです。
このフォーマットでは外部のフォーマットスキーマが必要で、クエリ間でキャッシュされます。
ClickHouse は以下をサポートしています。
proto2とproto3の両方の構文Repeated/optional/requiredフィールド
テーブルのカラムと Protocol Buffers' のメッセージ型のフィールドとの対応関係を判断するために、ClickHouse はそれらの名前を比較します。
この比較では大文字と小文字は区別されず、文字 _ (アンダースコア) と . (ドット) は同一と見なされます。
カラムと Protocol Buffers' のメッセージのフィールドの型が異なる場合は、必要な変換が適用されます。
ネストされたメッセージもサポートされています。たとえば、次のメッセージ型のフィールド z の場合です。
message MessageType {
message XType {
message YType {
int32 z;
};
repeated YType y;
};
XType x;
};ClickHouse は、x.y.z (または x_y_z、X.y_Z など) という名前のカラムを見つけようとします。
ネストされたメッセージは、ネストされたデータ構造 への入力や、そこからの出力に適しています。
転送データ上に存在しないマッピングされたフィールドの場合:
- 通常の非 Nullableマッピング済みカラムでは、パース中にテーブルの
DEFAULT式ではなく、protobuf スキーマのフィールドデフォルト (proto2の[default = …]、それ以外では型のデフォルト) が使用されます。 - マッピングされた
Nullable(...)カラムでは、フィールドが存在しない場合にNULLとなります (protobuf のフィールド/型のデフォルトは使用されません)。 google.protobuf.*Valueラッパーに対してinput_format_protobuf_flatten_google_wrappersが有効な場合:Nullable(...)カラム上の存在しないラッパーは、外側のフィールドが欠落しているものとして扱われ、NULLになります。- 存在するが空のラッパー (
str {}) では、ネストされたスカラーのデフォルト (''/0) が維持されます。 - 存在しないラッパーにマッピングされた非 Nullable カラムには、
NULLではなくネストされたスカラーのデフォルトが設定されます。
input_format_defaults_for_omitted_fields が有効な場合 (デフォルトでは有効)、テーブル DEFAULT (およびデフォルト式) は、メッセージ型内に一致するフィールドがないテーブルカラムに適用されます。その設定が 0 の場合、マッピングされていないカラムにはテーブルの DEFAULT 式ではなく、パース中に挿入されるデータ型のデフォルトが維持されます。
proto2 スキーマのフィールドデフォルトの例 (メッセージに存在しないマッピング済みフィールドに使用):
syntax = "proto2";
message MessageType {
optional int32 result_per_page = 3 [default = 10];
}メッセージに oneof が含まれ、input_format_protobuf_oneof_presence が設定されている場合、ClickHouse は oneof 内でどのフィールドが見つかったかを示すカラムに値を設定します。
syntax = "proto3";
message StringOrString {
oneof string_oneof {
string string1 = 1;
string string2 = 42;
}
}CREATE TABLE string_or_string ( string1 String, string2 String, string_oneof Enum('no'=0, 'hello' = 1, 'world' = 42)) Engine=MergeTree ORDER BY tuple();
INSERT INTO string_or_string from INFILE '$CURDIR/data_protobuf/String1' SETTINGS format_schema='$SCHEMADIR/string_or_string.proto:StringOrString' FORMAT ProtobufSingle;
SELECT * FROM string_or_string ┌─────────┬─────────┬──────────────┐
│ string1 │ string2 │ string_oneof │
├─────────┼─────────┼──────────────┤
1. │ │ string2 │ world │
├─────────┼─────────┼──────────────┤
2. │ string1 │ │ hello │
└─────────┴─────────┴──────────────┘存在の有無を示すカラム名は、oneof の名前と同じである必要があります。 ネストされたメッセージもサポートされています (basic-examples を参照) 。空のメッセージもサポートされています。 使用可能な型は Int8、UInt8、Int16、UInt16、Int32、UInt32、Int64、UInt64、Enum、Enum8、Enum16 です。 Enum (Enum8 または Enum16 を含む) には、不在を示す 0 と、ターゲットテーブル内に一致するカラムを持つ各 oneof ケースのタグを含める必要があります。文字列表現は問いません。 一致するテーブルカラムを持たない oneof メッセージメンバーについては、Enum タグが欠けていても許可されます。そのようなブランチが入力に存在する場合、ClickHouse は oneof の存在を省略されたものとして扱い、存在カラムに 0 を書き込みます。
設定 input_format_protobuf_oneof_presence はデフォルトで無効になっています
ClickHouse は protobuf メッセージを 長さ区切り フォーマットで入出力します。
つまり、各メッセージの前に、その長さを 可変長整数 (varint) として書き込む必要があります。
使用例
データの読み書き
この例では、ファイル protobuf_message.bin からデータを読み込んで ClickHouse のテーブルに格納します。続いて、Protobuf 形式を使用して、そのデータを protobuf_message_from_clickhouse.bin という名前のファイルに書き出します。
schemafile.proto ファイルの内容が次のとおりであるとします。
syntax = "proto3";
message MessageType {
string name = 1;
string surname = 2;
uint32 birthDate = 3;
repeated string phoneNumbers = 4;
};バイナリファイルの生成
Protobuf 形式でデータをシリアライズ/デシリアライズする方法をすでに理解している場合は、この手順をスキップできます。
ここでは Python を使ってデータを protobuf_message.bin にシリアライズし、それを ClickHouse に読み込みます。
別の言語を使いたい場合は、"主要な言語で長さ区切りの Protobuf メッセージを読み書きする方法"も参照してください。
次のコマンドを実行して、schemafile.proto と
同じディレクトリに schemafile_pb2.py という名前の Python ファイルを生成します。このファイルには、
UserData Protobuf メッセージを表す Python クラスが含まれます。
protoc --python_out=. schemafile.proto次に、schemafile_pb2.py と同じ
ディレクトリに generate_protobuf_data.py という名前の新しい Python ファイルを作成し、次のコードを貼り付けます。
import schemafile_pb2 # 'protoc' によって生成されたモジュール
from google.protobuf import text_format
from google.protobuf.internal.encoder import _VarintBytes # 内部 varint エンコーダをインポート
def create_user_data_message(name, surname, birthDate, phoneNumbers):
"""
UserData Protobuf メッセージを作成して値を設定します。
"""
message = schemafile_pb2.MessageType()
message.name = name
message.surname = surname
message.birthDate = birthDate
message.phoneNumbers.extend(phoneNumbers)
return message
# この例で使用するユーザーデータ
data_to_serialize = [
{"name": "Aisha", "surname": "Khan", "birthDate": 19920815, "phoneNumbers": ["(555) 247-8903", "(555) 612-3457"]},
{"name": "Javier", "surname": "Rodriguez", "birthDate": 20001015, "phoneNumbers": ["(555) 891-2046", "(555) 738-5129"]},
{"name": "Mei", "surname": "Ling", "birthDate": 19980616, "phoneNumbers": ["(555) 956-1834", "(555) 403-7682"]},
]
output_filename = "protobuf_messages.bin"
# バイナリファイルをバイナリ書き込みモード ('wb') で開く
with open(output_filename, "wb") as f:
for item in data_to_serialize:
# 現在のユーザー用の Protobuf メッセージインスタンスを作成
message = create_user_data_message(
item["name"],
item["surname"],
item["birthDate"],
item["phoneNumbers"]
)
# メッセージをシリアライズ
serialized_data = message.SerializeToString()
# シリアライズされたデータの長さを取得
message_length = len(serialized_data)
# Protobuf ライブラリの内部 _VarintBytes を使って長さをエンコード
length_prefix = _VarintBytes(message_length)
# 長さプレフィックスを書き込む
f.write(length_prefix)
# シリアライズされたメッセージデータを書き込む
f.write(serialized_data)
print(f"Protobuf messages (length-delimited) written to {output_filename}")
# --- 任意: 検証(読み戻して出力) ---
# 読み戻しには、varint 用の内部 Protobuf デコーダも使用します。
from google.protobuf.internal.decoder import _DecodeVarint32
print("\n--- Verifying by reading back ---")
with open(output_filename, "rb") as f:
buf = f.read() # varint のデコードを簡単にするため、ファイル全体をバッファに読み込む
n = 0
while n < len(buf):
# varint の長さプレフィックスをデコード
msg_len, new_pos = _DecodeVarint32(buf, n)
n = new_pos
# メッセージデータを抽出
message_data = buf[n:n+msg_len]
n += msg_len
# メッセージを解析
decoded_message = schemafile_pb2.MessageType()
decoded_message.ParseFromString(message_data)
print(text_format.MessageToString(decoded_message, as_utf8=True))次に、コマンドラインからスクリプトを実行します。たとえば uv を使って、
Python 仮想環境で実行することをおすすめします。
uv venv proto-venv
source proto-venv/bin/activate次の Python ライブラリをインストールする必要があります。
uv pip install --upgrade protobufスクリプトを実行してバイナリファイルを生成します。
python generate_protobuf_data.pyスキーマに一致する ClickHouse テーブルを作成します。
CREATE DATABASE IF NOT EXISTS test;
CREATE TABLE IF NOT EXISTS test.protobuf_messages (
name String,
surname String,
birthDate UInt32,
phoneNumbers Array(String)
)
ENGINE = MergeTree()
ORDER BY tuple()コマンドラインからテーブルにデータを挿入します:
cat protobuf_messages.bin | clickhouse-client --query "INSERT INTO test.protobuf_messages SETTINGS format_schema='schemafile:MessageType' FORMAT Protobuf"Protobuf 形式を使用して、データをバイナリファイルに書き戻すこともできます。
SELECT * FROM test.protobuf_messages INTO OUTFILE 'protobuf_message_from_clickhouse.bin' FORMAT Protobuf SETTINGS format_schema = 'schemafile:MessageType'Protobufスキーマがあれば、ClickHouse からファイル protobuf_message_from_clickhouse.bin に書き出されたデータをデシリアライズできるようになりました。
ClickHouse Cloud を使用したデータの読み書き
ClickHouse Cloud では、Protobuf のスキーマファイルをアップロードできません。ただし、format_protobuf_schema
設定を使用して、クエリ内でスキーマを指定できます。この例では、ローカル
マシンからシリアライズされたデータを読み込み、それを ClickHouse Cloud のテーブルに挿入する方法を示します。
前の例と同様に、ClickHouse Cloud で Protobuf スキーマに従ってテーブルを作成します。
CREATE DATABASE IF NOT EXISTS test;
CREATE TABLE IF NOT EXISTS test.protobuf_messages (
name String,
surname String,
birthDate UInt32,
phoneNumbers Array(String)
)
ENGINE = MergeTree()
ORDER BY tuple()設定 format_schema_source は、設定 format_schema の指定元を定義します
設定可能な値:
- 'file' (デフォルト) : Cloud ではサポートされていません
- 'string':
format_schemaはスキーマの内容そのものです。 - 'query':
format_schemaはスキーマを取得するためのクエリです。
format_schema_source='string'
スキーマを文字列として指定してデータをClickHouse Cloudに挿入するには、次を実行します。
cat protobuf_messages.bin | clickhouse client --host <hostname> --secure --password <password> --query "INSERT INTO testing.protobuf_messages SETTINGS format_schema_source='syntax = "proto3";message MessageType { string name = 1; string surname = 2; uint32 birthDate = 3; repeated string phoneNumbers = 4;};', format_schema='schemafile:MessageType' FORMAT Protobuf"テーブルに挿入されたデータを選択します:
clickhouse client --host <hostname> --secure --password <password> --query "SELECT * FROM testing.protobuf_messages"Aisha Khan 19920815 ['(555) 247-8903','(555) 612-3457']
Javier Rodriguez 20001015 ['(555) 891-2046','(555) 738-5129']
Mei Ling 19980616 ['(555) 956-1834','(555) 403-7682']format_schema_source='query'
Protobuf スキーマはテーブルに保存することもできます。
データの挿入先となるテーブルを ClickHouse Cloud に作成します:
CREATE TABLE testing.protobuf_schema (
schema String
)
ENGINE = MergeTree()
ORDER BY tuple();INSERT INTO testing.protobuf_schema VALUES ('syntax = "proto3";message MessageType { string name = 1; string surname = 2; uint32 birthDate = 3; repeated string phoneNumbers = 4;};');実行するクエリでスキーマを指定して、データをClickHouse Cloudに挿入します:
cat protobuf_messages.bin | clickhouse client --host <hostname> --secure --password <password> --query "INSERT INTO testing.protobuf_messages SETTINGS format_schema_source='SELECT schema FROM testing.protobuf_schema', format_schema='schemafile:MessageType' FORMAT Protobuf"テーブルに挿入したデータを選択します:
clickhouse client --host <hostname> --secure --password <password> --query "SELECT * FROM testing.protobuf_messages"Aisha Khan 19920815 ['(555) 247-8903','(555) 612-3457']
Javier Rodriguez 20001015 ['(555) 891-2046','(555) 738-5129']
Mei Ling 19980616 ['(555) 956-1834','(555) 403-7682']自動生成されたスキーマを使用する
データ用の外部 Protobuf スキーマがなくても、自動生成されたスキーマを使って Protobuf 形式でデータを出力/入力できます。
この場合は、format_protobuf_use_autogenerated_schema 設定を使用します。
例:
SELECT * FROM test.hits format Protobuf SETTINGS format_protobuf_use_autogenerated_schema=1この場合、ClickHouse は関数
structureToProtobufSchema を使用して、テーブル構造に基づいて Protobuf スキーマを自動生成します。続いて、このスキーマを使ってデータを Protobuf 形式にシリアライズします。
自動生成されたスキーマを使用して Protobuf ファイルを読み込むこともできます。この場合、そのファイルも同じスキーマを使って作成されている必要があります。
$ cat hits.bin | clickhouse-client --query "INSERT INTO test.hits SETTINGS format_protobuf_use_autogenerated_schema=1 FORMAT Protobuf"設定 format_protobuf_use_autogenerated_schema はデフォルトで有効で、format_schema が設定されていない場合に適用されます。
また、設定 output_format_schema を使用すると、入力/出力時に自動生成されたスキーマをファイルに保存することもできます。たとえば:
SELECT * FROM test.hits format Protobuf SETTINGS format_protobuf_use_autogenerated_schema=1, output_format_schema='path/to/schema/schema.proto'この場合、自動生成された Protobuf スキーマは path/to/schema/schema.capnp というファイルに保存されます。
Protobuf キャッシュを削除
format_schema_path で読み込まれた Protobuf スキーマを再読み込みするには、SYSTEM DROP ... FORMAT CACHE ステートメントを使用します。
SYSTEM DROP FORMAT SCHEMA CACHE FOR Protobuf