Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

高度なデータ挿入

ClickHouse Connectを使ったデータの挿入: 高度な使い方

InsertContexts

ClickHouse Connect は、Native-format の挿入である insert および insert_df メソッドを、InsertContext 内で実行します。insert_arrowinsert_df_arrowraw_insert の各メソッドはペイロードを直接送信するため、これを使用しません。InsertContext には、クライアントの insert メソッドに引数として渡すすべての値が含まれます。さらに、InsertContext の初回作成時には、効率的な Native format での挿入に必要な対象カラムのデータ型を ClickHouse Connect が取得します。複数回の挿入で InsertContext を再利用すると、この"事前クエリ"を省略できるため、挿入をより高速かつ効率的に実行できます。

InsertContext は、クライアントの create_insert_context メソッドを使って取得できます。このメソッドは、context 自体を除き、insert 関数と同じ引数を受け取ります。再利用時に変更すべきなのは、InsertContextdata プロパティだけである点に注意してください。これは、同じテーブルに新しいデータを繰り返し挿入するための再利用可能なオブジェクトを提供するという、本来の目的に沿ったものです。

test_data = [[13, "v1", "v2"], [79, "v3", "v4"]]
ic = client.create_insert_context(table="test_table", data=test_data)
client.insert(context=ic)
assert client.command("SELECT count() FROM test_table") == 2

new_data = [[101, "v5", "v6"], [113, "v7", "v8"]]
ic.data = new_data
client.insert(context=ic)
qr = client.query("SELECT * FROM test_table ORDER BY key DESC")
assert qr.row_count == 4
assert qr.first_row[0] == 113

InsertContextには、挿入処理中に更新される可変状態が含まれているため、スレッドセーフではありません。

書き込みフォーマット

書き込みフォーマットは、一部の型に対してのみ実装されています。ほとんどの場合、ClickHouse Connect はカラムの最初の非 NULL 値に基づいて、適切な書き込みフォーマットを自動的に判定します。たとえば、DateTime カラムの最初の値が整数であれば、クライアントはそれをエポック秒として扱います。

通常、書き込みフォーマットを上書きする必要はありませんが、clickhouse_connect.datatypes.format のメソッドを使うとグローバルに設定できます。ArrayNullableLowCardinality などのコンテナーラッパーは、要素型のフォーマット動作を保持します。

書き込みフォーマットのオプション

ClickHouse Type Native Python Type 書き込みフォーマット Comments
Int[8-64], UInt[8-32] int
UInt64 int
[U]Int[128,256] int
BFloat16 float
Float32 float
Float64 float
Decimal decimal.Decimal
String str or bytes 1つのカラムには、テキストまたはバイト列のいずれか一方だけを一貫して含める必要があります。
FixedString bytes string 文字列値はゼロバイトで埋められます。空のバイト列はすべてゼロバイトとして書き込まれます。
Enum[8,16] str or int ラベルは文字列、または対応する整数値として挿入します。
Date datetime.date int 整数値は、1970-01-01 からの日数として解釈されます。
Date32 datetime.date int 整数値は、符号付きの日オフセットとして解釈されます。
DateTime datetime.datetime int 整数値は、エポック秒として解釈されます。
DateTime64 datetime.datetime int 整数値は、カラムの精度におけるティックとして解釈されます。
Time datetime.timedelta int, string, time 整数値は、秒として解釈されます。
Time64 datetime.timedelta int, string, time 整数値は、カラムの精度におけるティックとして解釈されます。
IPv4 ipaddress.IPv4Address string 正しい形式の文字列は IPv4 アドレスとして挿入できます
IPv6 ipaddress.IPv6Address string 正しい形式の文字列は IPv6 アドレスとして挿入できます
Tuple dict or tuple
Map dict
Nested Sequence[dict]
UUID uuid.UUID string 正しい形式の文字列は ClickHouse UUID として挿入できます
JSON dict string 辞書および JSONオブジェクト文字列がサポートされます。従来の Object('json') 型はサポートされていません。
Variant object 値には各メンバー型のネイティブなシリアライゼーションが使用されます。Python の型が曖昧な場合は clickhouse_connect.datatypes.dynamic.typed_variant を使用してください。
Dynamic object 値は現在、String 表現を介して挿入されます。
QBit Sequence[float] インストールされている場合、より高速なビット転置のために NumPy が自動的に使用されます。

専用の 挿入 メソッド

ClickHouse Connect では、一般的なデータフォーマット向けに専用の 挿入 メソッドが用意されています。

  • insert_df – Pandas DataFrame をカラム指向の Native データとして 挿入 します。明示的なカラム名 / 型、または再利用可能な InsertContext もサポートします。
  • insert_arrow – ClickHouse の Arrow input format を使用して PyArrow Table を 挿入 します。
  • insert_df_arrow – Arrow ベースの Pandas DataFrame または Polars DataFrame を 挿入 します。Pandas のカラムはすべて Arrow ベースの dtype を使用している必要があります。

これら 3 つのメソッドはいずれも、databasesettings、およびリクエストごとの HTTP transport_settings を受け付けます。

Pandas DataFrame の挿入

import clickhouse_connect
import pandas as pd

client = clickhouse_connect.get_client()

df = pd.DataFrame({
    "id": [13, 79],
    "name": ["user_1", "user_2"],
    "age": [25, 30],
})

client.insert_df("users", df)

PyArrow Table を使った挿入

import clickhouse_connect
import pyarrow as pa

client = clickhouse_connect.get_client()

arrow_table = pa.table({
    "id": [13, 79],
    "name": ["user_1", "user_2"],
    "age": [25, 30],
})

client.insert_arrow("users", arrow_table)

ArrowベースのDataFrame挿入 (pandas 2.x)

import clickhouse_connect
import pandas as pd

client = clickhouse_connect.get_client()

# Convert to Arrow-backed dtypes for better performance
df = pd.DataFrame({
    "id": [13, 79],
    "name": ["user_1", "user_2"],
    "age": [25, 30],
}).convert_dtypes(dtype_backend="pyarrow")

client.insert_df_arrow("users", df)

PyArrow スキーマからテーブルを作成する

create_table_from_arrow_schema は、一般的なスカラー Arrow フィールドから CREATE TABLE ステートメントを生成します。このマッピングは、符号付き整数、符号なし整数、浮動小数点値、ブール値、文字列、日付、タイムスタンプをカバーします。意図的に NULL を許容しない ClickHouse カラムを作成し、サポートされていない Arrow 型に対しては TypeError を送出するため、実行前に生成された DDL を確認してください。

import clickhouse_connect
import pyarrow as pa

from clickhouse_connect.driver.ddl import create_table_from_arrow_schema

client = clickhouse_connect.get_client()
schema = pa.schema(
    [
        ("id", pa.uint32()),
        ("name", pa.string()),
        ("event_time", pa.timestamp("ms", tz="UTC")),
    ]
)
ddl = create_table_from_arrow_schema(
    table_name="arrow_events",
    schema=schema,
    engine="MergeTree",
    engine_params={"ORDER BY": "id"},
)
client.command(ddl)

タイムゾーン

Python の datetime オブジェクトを DateTime または DateTime64 カラムに挿入する際、ClickHouse Connect はそれらを epoch 値に変換します。

タイムゾーン対応の datetime オブジェクト

タイムゾーン対応のオブジェクトは、表している時点を保持します。ソースのタイムゾーンは、ClickHouse のカラムで宣言されているタイムゾーンと一致している必要はありません。

from datetime import datetime, timezone
from zoneinfo import ZoneInfo

client.command("CREATE TABLE events (event_time DateTime) ENGINE Memory")

data = [
    [datetime(2023, 6, 15, 10, 30, tzinfo=timezone.utc)],
    [datetime(2023, 6, 15, 10, 30, tzinfo=ZoneInfo("America/Denver"))],
    [datetime(2023, 6, 15, 10, 30, tzinfo=ZoneInfo("Asia/Tokyo"))],
]

client.insert("events", data, column_names=["event_time"])
results = client.query(
    "SELECT event_time FROM events ORDER BY event_time",
    query_tz="UTC",
    tz_mode="aware",
)
assert [row[0].hour for row in results.result_rows] == [1, 10, 16]

タイムゾーン情報を持たない datetime オブジェクト

グローバル設定 naive_datetime_insert は、タイムゾーン情報を持たない datetime 値をネイティブ Python オブジェクトとして挿入する際の動作を制御します。また、DateTime64 カラムで受け付けられるタイムゾーン情報を持たない ISO 文字列にも適用されます。

  • "local" は 1.x でのデフォルトです。Python は .timestamp() の呼び出し時に、プロセスのタイムゾーンで値を解釈します。これにより既存の動作が維持されます。
  • "server" は、値を DateTime または DateTime64 カラムで宣言されたタイムゾーンの実時間として解釈します。カラムにタイムゾーンが指定されていない場合は、クライアント接続時に取得したサーバーのタイムゾーンを使用します。

挿入前にこのオプションを設定してください。Python の datetime オブジェクトまたは DateTime64 ISO 文字列を含むネイティブ挿入の各カラムをシリアル化する際に読み取られるため、変更は既存のクライアントおよび再利用可能な挿入コンテキストにも適用されます。

from datetime import datetime

from clickhouse_connect import common

common.set_setting("naive_datetime_insert", "server")

naive_time = datetime(2023, 6, 15, 10, 30)
client.insert("events", [[naive_time]], column_names=["event_time"])

"server" では、ClickHouse Connect は値をエポックに変換する前に、対象の tzinfo を付与します。IANA タイムゾーンでは、夏時間切り替えに関する標準ライブラリの規則に従います。秋の重複時間では、datetime の fold 値が使用されます。デフォルトの fold=0 は切り替え前のオフセットを選択し、fold=1 は切り替え後のオフセットを選択します。春のギャップでも同じオフセット選択が使用され、拒否や正規化は行われません。

春のギャップにある存在しない実時間は、ClickHouse のテキストパースで別のオフセットが選択される可能性があるため、実時間モードのクエリパラメータを介してラウンドトリップできない場合があります。時点が重要な場合は、タイムゾーン対応の datetime または有効な実時間を使用してください。

このオプションは、datetime 値をネイティブ Python オブジェクトとして insert する場合と、DateTime64 が受け付けるタイムゾーン情報のない ISO 文字列にのみ適用されます。タイムゾーン情報のない datetime64 dtype の NumPy および Pandas カラムでは、既存の UTC 実時間変換が維持されます。

どちらのモードにも依存せずに特定の時点を表すには、意図したタイムゾーンを付与するか、エポック整数を明示的に指定してください。

from datetime import datetime, timezone

utc_time = datetime(2023, 6, 15, 10, 30, tzinfo=timezone.utc)
client.insert("events", [[utc_time]], column_names=["event_time"])

naive_time = datetime(2023, 6, 15, 10, 30)
epoch_timestamp = int(naive_time.replace(tzinfo=timezone.utc).timestamp())
client.insert("events", [[epoch_timestamp]], column_names=["event_time"])

タイムゾーン情報を持たない datetime のクエリパラメータには、個別の naive_datetime_binding 設定が使用されます。デフォルトの "wall" モードでは、ホストのローカル時刻への変換を行わずに日時フィールドが送信されます。Parameters argument セクションを参照してください。

タイムゾーン メタデータを持つ DateTime カラム

ClickHouse のカラムでは、DateTime('America/Denver')DateTime64(3, 'Asia/Tokyo') のようにタイムゾーン メタデータを宣言できます。このメタデータは、クエリ時に値がどのように表示されるかを制御します。

タイムゾーン対応の値を挿入する際、ClickHouse Connect はその値が表す時点を保持します。タイムゾーン情報のない値の場合、naive_datetime_insert 設定によってプロセスのタイムゾーンとカラムのタイムゾーンのどちらを使用するかが決まります。クエリ時には、column_tzs 引数でカラムごとの上書きを指定しない限り、結果にはそのカラムのタイムゾーンが使用されます。query_tz 引数では、カラムに宣言されたタイムゾーンは上書きされません。

from datetime import datetime
from zoneinfo import ZoneInfo

client.command(
    "CREATE TABLE events_with_timezone "
    "(event_time DateTime('America/Los_Angeles')) "
    "ENGINE Memory"
)

data = datetime(2023, 6, 15, 10, 30, tzinfo=ZoneInfo("America/New_York"))
client.insert("events_with_timezone", [[data]], column_names=["event_time"])

result = client.query("SELECT event_time FROM events_with_timezone")
returned = result.first_row[0]
assert returned.hour == 7
assert returned.tzinfo == ZoneInfo("America/Los_Angeles")

ファイルの挿入

clickhouse_connect.driver.tools.insert_file はローカルファイルを既存のテーブルにストリームで挿入し、パースは ClickHouse に委ねます。

Parameter Type Default Description
client Client 必須 挿入に使用する同期 Client。
table str 必須 単純名、またはデータベース修飾されたターゲットテーブル。
file_path str 必須 入力ファイルへのローカルパス。
fmt str "CSV" or "CSVWithNames" 入力フォーマット。column_names が指定されている場合のデフォルトは "CSV"、それ以外の場合は "CSVWithNames" です。
column_names Sequence[str] None ファイル内のカラム。名前を含むフォーマットでは不要です。
database str None テーブルが修飾されていない場合のターゲットデータベース。
settings dict None Settings argument を参照してください。
compression str None "zstd""lz4""gzip" などの既存のファイル圧縮。gzip は .gz および .gzip のファイル名から推論されます。

input_format_allow_errors_ratioinput_format_allow_errors_num などの入力フォーマット設定は、settings 経由で渡せます。

import clickhouse_connect

from clickhouse_connect.driver.tools import insert_file

client = clickhouse_connect.get_client()
insert_file(
    client,
    "example_table",
    "my_data.csv",
    settings={
        "input_format_allow_errors_ratio": 0.2,
        "input_format_allow_errors_num": 5,
    },
)

AsyncClient の場合は、同じ引数を使って insert_file_async を await します:

from clickhouse_connect.driver.tools import insert_file_async

await insert_file_async(async_client, "example_table", "my_data.csv")

async ヘルパーは、raw_insert を await する前にワーカースレッドでファイルを読み込むため、ファイルの内容はメモリ上に保持されます。

Navigation