概要
ClickHouse は Apache Arrow Flight プロトコルをサポートしています。これは、gRPC 上で Arrow IPC フォーマットを使用し、効率的な列指向データ転送を実現する高性能な RPC フレームワークです。 この実装には Arrow Flight SQL のサポートも含まれており、Flight SQL プロトコルに対応した BI ツールやアプリケーションから ClickHouse に直接クエリできます。 主な機能:- SQL クエリを実行し、結果を Apache Arrow フォーマットで取得できます。
- Arrow フォーマットを使用してテーブルにデータを挿入できます。
- Flight SQL コマンドを使ってメタデータ (カタログ、スキーマ、テーブル、主キー) をクエリできます。
- Flight SQL を介してサーバー側のプリペアドステートメントを作成、バインド、実行、クローズできます。
- Flight SQL アクションを介してセッションと設定を管理できます。
- TLS 暗号化とユーザー名/パスワード認証。
PollFlightInfoによる段階的な結果取得。CancelFlightInfoによるクエリのキャンセル。
Arrow Flight Server を有効にする
Arrow Flight Server を有効にするには、ClickHouse サーバー設定にarrowflight_port 設定を追加します。
TLS 設定
Arrow Flight インターフェイスで TLS を有効にするには、以下の設定を行います。grpc:// ではなく grpc+tls:// 認証スキームを使用して接続する必要があります。
認証
Arrow Flight インターフェイスでは、2 つの認証方法がサポートされています。基本認証
クライアントは、標準の HTTPAuthorization: Basic ヘッダーを介して、ユーザー名とパスワードで認証します。認証に成功すると、サーバーはレスポンスヘッダーで Bearer トークンを返します。
ベアラートークン認証
後続のリクエストでは、基本認証で返されたベアラートークンをAuthorization: Bearer <token> ヘッダーで使用できます。トークンは使用するたびに自動的に更新され、有効期限は default_session_timeout サーバー設定 (既定値: 60 秒) に従います。
Python の例
セッション管理
Arrow Flight インターフェイスは、カスタム gRPC メタデータヘッダーを介して ClickHouse のセッションをサポートします。Arrow Flight は HTTP/2 上で gRPC を使用するため、メタデータヘッダー名では大文字と小文字が区別され、ここに示すとおり、正確に小文字で指定する必要があります (例:
x-clickhouse-session-id。X-ClickHouse-Session-Id ではありません) 。これは、HTTP/2 のフィールド名には小文字のみを含めることを義務付ける RFC 9113, Section 8.2 で規定されています。これは、ヘッダー名で大文字と小文字が区別されない HTTP/1.1 とは異なります。SetSessionOptions アクションで永続的な ClickHouse 設定を指定できます (DoAction を参照) 。
サーバー設定リファレンス
サポート対象のRPCメソッド
GetFlightInfo
クエリを実行し、結果のスキーマ、データ取得用チケット付きのエンドポイント、行数、バイト数を含むFlightInfo を返します。
受け取る FlightDescriptor には、次のいずれかを指定できます。
- PATH descriptor: テーブル名として解釈される単一要素の path です。
SELECT * FROM <table>を生成します。 - CMD descriptor: 生の SQL クエリ文字列、またはシリアライズされた Flight SQL protobuf コマンドです (Flight SQL Commands を参照) 。
PollFlightInfo
長時間実行されるクエリの結果を、段階的に取得できるようにします。GetFlightInfo のようにクエリ全体の完了を待つのではなく、PollFlightInfo は結果をブロック単位で返します。
最初の呼び出しでクエリの実行が開始され、レスポンスには次の内容が含まれます。
- その時点で利用可能なデータブロックに対応するエンドポイントを含む
FlightInfo - 次回のポーリングに使用する
FlightDescriptor(さらに結果が返される見込みがある場合)
現在の実装では、データブロックが利用可能になるまで待機し、データがない場合に即座に返すことはありません。
GetSchema
クエリ全体を実行せずに、クエリ結果の Arrow スキーマを返します。GetFlightInfo と同じ種類のディスクリプタを受け付けます。
DoGet
指定された ticket に対応するデータを取得します。次のいずれかを受け付けます。GetFlightInfoまたはPollFlightInfoが返す ticket。- ticket の値として指定する、生の SQL query 文字列。
DoPut
ClickHouse にデータを送信します。FlightDescriptor と Arrow レコードバッチのストリームを受け取ります。
テーブル名による insert (PATH ディスクリプタ) :
CommandStatementUpdate による DDL/DML の実行:
Flight SQL クライアントは、DDL/DML ステートメント (CREATE、INSERT、ALTER など) の実行に CommandStatementUpdate を使用します。レスポンスには、影響を受けた行数が含まれます。
Flight SQL CommandStatementIngest による一括取り込み:
サポートされているのは、既存のテーブルへの追記のみです (TABLE_NOT_EXIST_OPTION_FAIL + TABLE_EXISTS_OPTION_APPEND) 。このコマンドでは、カタログと一時テーブルはサポートされていません。
transaction_id は CommandStatementUpdate と CommandStatementIngest ではサポートされていません。指定した場合、ClickHouse は NotImplemented エラーを返します。
データ転送に使用できるのは
Arrow フォーマットのみです。SQL で他のフォーマット (例: FORMAT JSON) を指定すると、エラーになります。DoAction
名前付きアクションを実行します。サポートされているアクションは次のとおりです。CancelFlightInfo
FlightInfo に関連付けられた実行中のクエリをキャンセルします。クエリ ID は FlightInfo の app_metadata フィールドから抽出されます。また、そのクエリに関連付けられたすべての poll ディスクリプタもキャンセルします。
SetSessionOptions
現在のセッションに対する ClickHouse のサーバー設定を行います。x-clickhouse-session-id ヘッダーでセッション ID が設定されている必要があります。
サポートされる値の型: string、boolean、integer、double、および string list。
設定名が不明な場合は、error INVALID_NAME が返されます。値をパースできない場合は、error INVALID_VALUE が返されます。
GetSessionOptions
現在のセッションの ClickHouse 設定とその値をすべて返します。設定名から文字列値へのマップを返します (内部的にはsystem.settings にクエリします) 。
CreatePreparedStatement
サーバー側のプリペアドステートメントを作成し、ステートメントハンドルを返します。リクエストには、? プレースホルダーを含む SQL クエリテキストが含まれます。
このアクションでは transaction_id はサポートされていません。指定した場合、ClickHouse は NotImplemented エラーを返します。
クエリステートメントの場合、レスポンスには次が含まれることがあります。
dataset_schema: 結果セットのスキーマ。parameter_schema: ステートメントパラメータのスキーマ。
NULL に置き換えることが有効でない場合) 、ClickHouse はプリペアドステートメントを作成し、dataset_schema を含めずにハンドルを返します。
dataset_schema は、Flight SQL 仕様が意図しているとおり、あくまで最善の推測です。仕様では、結果スキーマはパラメータに依存する可能性があり、サーバーは最善の推測を返すべきであり、クライアントはそのスキーマが正確であると想定してはならないとされています。これに依存しないでください。データを表すスキーマを得るには、ステートメントを実行してください。ClickHouse では、次の 2 つの理由により、実際に返されるものと異なる場合があります。
- 推論では各
?をNULLに置き換えるため、結果カラムを決定するプレースホルダーは、後でバインドする値ではなくそのNULLから型付けされます。SELECT ? AS xではNothing型のカラムが推論されますが、5をバインドするとUInt8が返されます。SELECT id, name FROM t WHERE id = ?のように、predicate の中でのみ使用されるプレースホルダーでは、結果の型はテーブルから決まるため、この問題は発生しません。 - Arrow に同等の型が存在しないカラムは、
output_format_arrow_unsupported_typesから Arrow の型が決まりますが、これは呼び出しごとに、その呼び出しを行うセッションから解決されます。ハンドルは単一のセッションではなくユーザーに属するため、後の呼び出しでは異なる解決結果となり、utf8と通知されていたところでbinaryが返される、またはその逆が起こることがあります。プリペアドクエリ自体の中でモードを設定すれば、両方について固定できます。
arrowflight.prepared_statements_lifetime_seconds は有効期限の動作を制御します。
> 0: 設定された値をステートメントの有効期間として使用します。セッションに紐づくステートメントとセッションレスステートメントの両方で、リクエストのたびに有効期限が更新されます。0: プリペアドステートメントは自動的に期限切れになりません。-1(デフォルト): ステートメントがセッション内で作成された場合、その有効期間はそのセッションのタイムアウトに従い、そのセッション内のリクエストごとに更新されます。セッションなしでステートメントが作成された場合、自動的に期限切れにはなりません。
arrowflight.max_prepared_statements_per_user のカウント対象にも含まれなくなります。
ClosePreparedStatement
リクエストに空でないステートメントハンドルが含まれている場合、プリペアドステートメントを閉じ、関連するサーバー側リソースを解放します。 ClickHouse は、ハンドルが空の場合、ClosePreparedStatement による一括クローズもサポートしています。
x-clickhouse-session-idが存在する場合、そのセッション内で認証済みユーザーのすべてのプリペアドステートメントを閉じます。- セッション ID が存在しない場合、認証済みユーザーのセッションに属さないプリペアドステートメントのみを閉じます。
x-clickhouse-session-id を介して) 作成された場合、そのセッションが閉じられると、そのステートメントも自動的に閉じられます。
Flight SQL コマンド
CMD ディスクリプタにシリアライズされた Flight SQL protobuf メッセージが含まれている場合、ClickHouse は以下のコマンドを処理します。
GetFlightInfo / GetSchema でサポート
DoPut 経由でサポートされるもの
ClickHouse でサポートされていないもの
これらのコマンドは ClickHouse が提供していない機能に対応しているため、Arrow Flight SQL インターフェイスではサポートされていません。完全な使用例
Query
Response
データフォーマット
すべてのデータは Apache Arrow IPC フォーマットで転送されます。サポートされるのはArrow フォーマットのみで、他の ClickHouse フォーマット (例: FORMAT JSON、FORMAT CSV) を指定するとエラーになります。
ClickHouse データ型は、シリアライゼーション時に Arrow の型へマッピングされます。Arrow Flight は常に canonical な Arrow マッピングを使用し、Arrow および ArrowStream 出力フォーマットとは異なり、型の表現方法を変更する output_format_arrow_* 系の設定には従いません。output_format_arrow_string_as_string、output_format_arrow_low_cardinality_as_dictionary、output_format_arrow_date_as_uint16、output_format_arrow_fixed_string_as_fixed_byte_array、および dictionary インデックス関連の設定は、ここでは効果がありません。したがって、同一のクエリであっても Arrow Flight 経由では FORMAT Arrow 経由と異なるスキーマになることがありますが、これは次の 2 つの理由による意図的な設計です。
- Flight SQL はメタデータ応答のスキーマを固定しています。たとえば
CommandGetTablesはcatalog_name: utf8, db_schema_name: utf8, table_name: utf8 not null, table_type: utf8 not null, table_schema: bytes not nullを返す必要があります。session setting によってこれらのutf8カラムがbinaryに変わってしまうと、ClickHouse はあらゆる Flight SQL ドライバーに対して非準拠となり、さらに ClickHouse がtable_schema内で公開するテーブルごとのスキーマも変わってしまいます。 - Flight クライアントは、スキーマとデータを別々の呼び出し (
GetFlightInfoまたはGetSchema、続いてDoGet) で取得します。スキーマを変更し得る設定が存在すると、その間に session が変化した場合に、公開されたスキーマと実際に配信されるストリームが食い違う余地が生まれます。
JSON、Dynamic、QBit、AggregateFunction のように Arrow に対応する型がまったく存在しないケースです。基準とすべき canonical なマッピングがないため、ClickHouse は何らかの表現を選択せざるを得ず、output_format_arrow_unsupported_types でどの表現を使うかを指定できます。
AggregateFunction カラムは、text モードであっても Arrow の Binary カラムのままとなる唯一の型です。その text form は生の aggregate state であり valid UTF-8 ではない一方、Arrow の Utf8 カラムは valid UTF-8 を保持しなければならないためです。読みやすい値が必要な場合は finalizeAggregation を使用してください。
同じ理由から、ClickHouse は text の値に含まれるすべての invalid UTF-8 sequence を、Utf8 カラムへ書き込む前に U+FFFD (�) に置き換えます。String を保持する Dynamic はそのバイト列をそのままシリアライズし、その内容は任意のバイトになり得るため、この処理がなければカラムが Arrow 仕様に違反し、厳格なクライアントに拒否される可能性があります。変化するのは、もともと valid text ではない値だけです。バイト列を厳密に保持する必要がある場合は binary モードを使用してください。
output_format_arrow_string_as_string は、FORMAT Arrow の場合も含めてこれらのカラムには適用されません。この設定が制御するのは実際の String および FixedString カラムのみです。したがって、clickhouse.opaque カラムの Arrow 型は、保持している encoding を常に示します。text form であれば Utf8、バイナリ形式であれば Binary です。
これが、AggregateFunction カラムでは問題にならないにもかかわらず、Dynamic に保持された aggregate state が text モードでは情報を失う理由です。カラムは Dynamic として型付けされるため各行が何を保持しているかは分からず、しかもスキーマは値を 1 つも見ない段階で確定するため、その state に専用の Binary カラムを割り当てることはできません。保持したい場合は binary モードを使用してください。Variant は取り得る型を列挙するため、その中に含まれる AggregateFunction は専用の Binary の子を持ち、影響を受けません。
こうしたカラムは、それ以外の点では本物の Utf8/Binary カラムと区別できないため、Arrow の extension 型として宣言されます。フィールドのメタデータには ARROW:extension:name = clickhouse.opaque が保持され、元の ClickHouse 型名は ARROW:extension:metadata に格納されます。extension 名を認識しないクライアントは、Arrow 仕様が定めるとおり、素の storage 型として認識します。nested カラムはそれぞれ自身のフィールドにタグ付けされるため、Array(JSON) ではその子がタグを持ち、Map(JSON, ...) ではそのキーがタグを持ちます。コンテナ自体ではありません。
従来のブール値設定 output_format_arrow_unsupported_types_as_binary も引き続き使用でき、0 の場合は throw、1 の場合は binary と同等です。この設定は、output_format_arrow_unsupported_types がデフォルト値のままの場合にのみ参照されます。
互換性
Arrow Flight インターフェイスは、Arrow Flight または Arrow Flight SQL プロトコルをサポートするあらゆるクライアントやツールと互換性があります。具体的には、次のようなものが含まれます。- Python (
pyarrow) - Java (
org.apache.arrow.flight) - C++ (
arrow::flight) - Go (
apache/arrow/go) - ADBC (Arrow Database Connectivity) ドライバー
- DBeaver など、Flight SQL をサポートするその他のツール