FORMAT Native のトラフィックのみです。具体的には、query、query_np、query_df、およびそれらの block・row ストリーミング版、さらに insert_df を含む insert が対象です。Arrow の methods は FORMAT Arrow を使用するため影響を受けません。raw クエリ、raw insert、Native 以外のフォーマットも同様です。
この codec は experimental であり、オプトイン方式です。デフォルトは引き続き Python codec です。
インストール
コンパイル済みの codec はclickhouse-connect-core という名前の独立した wheel として提供され、_ch_core 拡張機能モジュールを提供します。評価する場合は、codec と PyArrow を併せてインストールしてください:
query_np、query_df、それらのストリーミング版、および query(..., use_numpy=True) です。PyArrow がない場合、native_codec="rust" は警告をログに出力し、これらのクエリを Python codec で実行します。native_codec="rust_strict" の場合は、代わりに NotSupportedError を送出します。
rust エクストラ単体は、標準的な Python の行結果、行またはカラム block のストリーム、および NumPy や Pandas の出力を要求しない insert のみを使用するアプリケーション向けに、軽量なまま維持されます。これらのパスでは PyArrow は不要です:
NotSupportedError が送出されます。
codec の有効化
native_codec client オプションで codec を選択します:
デフォルト値は、
native_codec 共通設定または CLICKHOUSE_CONNECT_NATIVE_CODEC 環境変数であらかじめ指定することもできます。優先順位は、client の keyword argument、共通設定、環境変数の順です。
このオプションは interface="chdb" の clients では無視され、常に Python codec が使用されます。
Rust codec を使うべき場面
Rust codec は、String、LowCardinality、Map、Array、JSON、Decimal、UUID といったテキスト型・コンテナー型・複合型を含む大規模な DataFrame の結果で最も効果を発揮します。また、大規模な行ブロックおよびカラムブロックのストリーム、同時実行のクエリ workload、bulk insert でも効果があります。
小規模な結果やネットワーク律速のクエリでは、ほとんど変化が見られないことがあります。フラットな数値のみの結果は Python codec でもすでに効率的なバルク処理パスを利用しているため、同様に効果は小さくなる傾向があります。
非常に横に広い結果や全カラムが数値の結果に対するバッファリングされた query() の呼び出しは、現時点では Rust codec の方が遅く、ピークメモリも多くなる場合があります。そうした workload では query_df、query_row_block_stream、query_column_block_stream の利用を推奨します。ストリーミングであればメモリ使用量を一定の範囲に抑えられます。
codec を採用する前に、ご自身の workload でベンチマークを実施してください。測定時には native_codec="rust_strict" を指定してください。そうすることで、未サポートのオプションや依存関係の欠落があった場合に、クエリが黙って Python へ回されるのではなく例外が送出されます。
フォールバックルール
フォールバックの判断はバイトの読み取りや送信が始まる前に行われるため、ストリームの途中でcodecが切り替わることはありません。クエリの場合、この選択はresponse bodyが消費される前に行われます。insertの場合、すべてのcolumn typeがサポートされているときにのみRustエンコーダーが選択され、そうでなければinsert全体がPython codecで実行されます。naive_datetime_insert="server" が有効な場合、rust は DateTime または DateTime64 のcolumnを含むinsertをPython codecへルーティングし、宣言されたcolumnのtimezoneまたはserver timezoneが適用されるようにします。rust_strict はこの組み合わせを拒否します。デフォルトの naive_datetime_insert="local" モードでは、引き続きRustエンコーダーが使用されます。
SQLAlchemyのdialect reflection文を含むドライバー内部のメタデータクエリは、どのモードでも常に、通知なくPython codecを使用します。
Rust codecが検出した不正な形式のNativeペイロードは DataError を発生させます。
Versioning
clickhouse-connect-core は clickhouse-connect とは独立してバージョン管理されます。ドライバーは rust extra で互換性のあるバージョン範囲を宣言し、モジュールはバインディング API のバージョンをエクスポートします。このバージョンは、Rust codec が選択された時点でドライバーによって検証されます。インストールされている wheel がドライバーに対して古すぎる場合、Client の作成時に NotSupportedError が送出され、アップグレード用のコマンドが示されます:
clickhouse-connect-core のリリースとして提供されるため、互換性のある core wheel へのアップグレードで取り込めます。ドライバーの Rust インテグレーションに関する変更を取り込むには、clickhouse-connect のアップグレードが必要です。
既知の動作の相違点
Rust codec は、Python codec とのセル単位での完全な一致を目指しています。既知の相違点は以下のとおりです。Variantカラムに対するquery_npおよびquery_dfの結果には、numpy のスカラー値ではなくプレーンな Python オブジェクトが含まれます。値は同一ですが、セルの型が異なります。Time64を含むDynamicの値は、Rust のquery_npおよびquery_dfの結果ではdatetime.timedeltaとしてマテリアライズされます。スケール 0、3、6、9 では値は Python codec のnumpy.timedelta64セルと等しくなりますが、セルの型が異なります。それ以外のスケールでは、Rust codec はdatetime.timedeltaを返しますが、Python codec は NumPy に対応する単位が存在しないためProgrammingErrorを送出します。Rust によるデコード後は Dynamic のメンバーメタデータがドライバーに公開されないため、NumPy のセル型やサポート対象外スケールの検証が必要な場合はnative_codec="python"を使用してください。query_dfでは、Python codec が JSON の shared data に格納された複合値を文字列化する場合があります。Rust codec はデコード済みのオブジェクトを返し、両codecのquery_npの結果と一致します。Array(Variant(...))のようにセル単位でマテリアライズされるコンテナー内のLowCardinalityの候補型では、値としては等しいセルが生成されますが、Python codec で見られるような dictionary の slot ごとのオブジェクト同一性は共有されません。- 1 つ以上の elements を持つ
Nullable(Tuple(...))カラムは、Rust codec では正しくデコードされます。Python codec はこの layout を誤って読み取るため、Rust の結果が基準となる動作です。両codecともNullable(Tuple())をサポートします。 rust_strictは、クエリごとのカスタムなquery_formatsなど、Rust パスが実装していないクエリオプションについて、暗黙のうちに動作を変更するのではなくエラーとして拒否します。- Rust の insert における変換エラーおよび検証エラーでは、Python codec が
ValueErrorを送出する場面でDataErrorが送出されることがあり、メッセージの文言も異なる場合があります。例としては、無効なTimeおよびTime64の値、IPv6 アドレス、QBit の dimension、FixedStringの length、Float64の文字列、Tuple()カラムへの elements の挿入の試行などが挙げられます。 - Rust エンコーダーは、
FixedString(N)に対するb""や、整数カラムに対する"2"のような数値文字列を拒否します。一方、Python codec は空のFixedStringの値をゼロ埋めし、数値文字列を強制変換します。 - Python codec が値を raw bytes のまま残す場合でも、Rust codec は一部の
Dynamicの shared variant の値を対応する Python の型にデコードします。例えば、格納されたDateは Rust ではdatetime.dateとして返され、Python ではバイナリ値として返されます。