Inserción de datos con ClickHouse Connect: uso avanzado
InsertContexts
ClickHouse Connect ejecuta las inserciones en Native format, los métodos insert e insert_df, dentro de un InsertContext. Los métodos insert_arrow, insert_df_arrow y raw_insert envían sus payloads directamente y no usan ninguno. El InsertContext incluye todos los valores enviados como argumentos al método insert del cliente. Además, cuando se crea un InsertContext, ClickHouse Connect recupera los tipos de datos de las columnas de inserción necesarios para realizar inserciones eficientes en Native format. Al reutilizar el InsertContext para varias inserciones, se evita esta "consulta previa" y las inserciones se ejecutan de forma más rápida y eficiente.
Se puede obtener un InsertContext mediante el método create_insert_context del cliente. El método acepta los mismos argumentos que la función insert, excepto context en sí. Tenga en cuenta que, para reutilizarlo, solo debe modificarse la propiedad data de los InsertContext. Esto concuerda con su propósito: proporcionar un objeto reutilizable para inserciones repetidas de datos nuevos en la misma tabla.
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] == 113InsertContexts incluyen un estado mutable que se actualiza durante el proceso de inserción, así que no es seguro usarlos desde varios hilos.
Formatos de escritura
Los formatos de escritura están implementados para un número limitado de tipos. En la mayoría de los casos, ClickHouse Connect determina automáticamente el formato de escritura correcto para una columna a partir de su primer valor de datos no nulo. Por ejemplo, cuando el primer valor de una columna DateTime es un entero, el Client lo trata como un segundo desde la época.
Normalmente no es necesario aplicar una sobrescritura a un formato de escritura, pero los métodos de clickhouse_connect.datatypes.format pueden establecer uno de forma global. Las envolturas de contenedor, como Array, Nullable y LowCardinality, conservan el comportamiento de formato del tipo de elemento.
Opciones de formato de escritura
| Tipo de ClickHouse | Tipo nativo de Python | Formatos de escritura | Comentarios |
|---|---|---|---|
| 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 | Una columna debe contener siempre texto o bytes de forma consistente. | |
| FixedString | bytes | string | Los valores de cadena se rellenan con bytes cero. Los bytes vacíos se escriben como bytes completamente cero. |
| Enum[8,16] | str or int | Inserte las etiquetas como cadenas o como sus valores enteros subyacentes. | |
| Date | datetime.date | int | Los valores enteros se interpretan como días desde 1970-01-01. |
| Date32 | datetime.date | int | Los valores enteros se interpretan como desplazamientos de días con signo. |
| DateTime | datetime.datetime | int | Los valores enteros se interpretan como segundos desde la época Unix. |
| DateTime64 | datetime.datetime | int | Los valores enteros se interpretan como ticks con la precisión de la columna. |
| Time | datetime.timedelta | int, string, time | Los valores enteros se interpretan como segundos. |
| Time64 | datetime.timedelta | int, string, time | Los valores enteros se interpretan como ticks con la precisión de la columna. |
| IPv4 | ipaddress.IPv4Address |
string | Se pueden insertar cadenas con el formato adecuado como direcciones IPv4 |
| IPv6 | ipaddress.IPv6Address |
string | Se pueden insertar cadenas con el formato adecuado como direcciones IPv6 |
| Tuple | dict or tuple | ||
| Map | dict | ||
| Nested | Sequence[dict] | ||
| UUID | uuid.UUID | string | Se pueden insertar cadenas con el formato adecuado como UUIDs de ClickHouse |
| JSON | dict | string | Se admiten diccionarios y cadenas con objetos JSON. El tipo heredado Object('json') no es compatible. |
| Variant | object | Los valores usan la serialización nativa del miembro. Use clickhouse_connect.datatypes.dynamic.typed_variant cuando los tipos de Python sean ambiguos. |
|
| Dynamic | object | Actualmente, los valores se insertan mediante su representación en String. | |
| QBit | Sequence[float] | NumPy se usa automáticamente para una transposición de bits más rápida cuando está instalado. |
Métodos especializados de inserción
ClickHouse Connect proporciona métodos especializados de inserción para formatos de datos habituales:
insert_df– Inserta un DataFrame de Pandas como datos Native orientados a columnas. También admite nombres y tipos de columna explícitos o unInsertContextreutilizable.insert_arrow– Inserta una tabla de PyArrow usando el formato de entrada Arrow de ClickHouse.insert_df_arrow– Inserta un DataFrame de Pandas respaldado por Arrow o un DataFrame de Polars. Todas las columnas de Pandas deben usardtypesbasados en Arrow.
Los tres métodos aceptan database, settings y transport_settings HTTP por solicitud.
Inserción con DataFrame de Pandas
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)Inserción de tablas de PyArrow
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)Inserción de DataFrame respaldado por Arrow (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)Crear una tabla a partir de un esquema de PyArrow
create_table_from_arrow_schema genera una instrucción CREATE TABLE a partir de campos escalares comunes de Arrow. La correspondencia abarca enteros con y sin signo, valores de coma flotante, booleanos, cadenas, fechas y marcas de tiempo. Crea intencionadamente columnas de ClickHouse que no admiten NULL y genera TypeError para tipos de Arrow no compatibles, así que revise el DDL generado antes de ejecutarlo.
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)Zonas horarias
Al insertar objetos datetime de Python en columnas DateTime o DateTime64, ClickHouse Connect los convierte en valores de época.
Objetos datetime con zona horaria
Los objetos con zona horaria conservan el instante representado. La zona horaria de origen no tiene que coincidir con la zona horaria declarada en la columna de 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]Objetos datetime sin zona horaria
La configuración global naive_datetime_insert controla la inserción de objetos nativos de Python con valores datetime sin zona horaria. También se aplica a las cadenas ISO sin zona horaria aceptadas por las columnas DateTime64.
"local"es el valor predeterminado en 1.x. Python interpreta el valor en la zona horaria del proceso al llamar a.timestamp(). Esto conserva el comportamiento existente."server"interpreta el valor como hora local en la zona horaria declarada por la columnaDateTimeoDateTime64. Si la columna no tiene zona horaria, utiliza la zona horaria del servidor indicada cuando se conectó el Client.
Configure la opción antes de realizar una inserción. Se lee al serializar cada columna de inserción nativa que contiene objetos datetime de Python o cadenas ISO DateTime64, por lo que el cambio se aplica a los Clients existentes y a los contextos de inserción reutilizables.
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"])Con "server", ClickHouse Connect asigna el tzinfo de destino antes de convertir el valor a una época. Para las zonas horarias IANA, sigue las reglas de la biblioteca estándar para las transiciones de horario de verano. En una superposición de otoño se usa el valor fold de datetime. El valor predeterminado fold=0 selecciona el desplazamiento anterior a la transición, mientras que fold=1 selecciona el posterior. En un salto de primavera se usa la misma selección de desplazamiento, y no se rechaza ni se normaliza.
Las horas de reloj inexistentes durante un salto de primavera pueden no conservarse en un recorrido de ida y vuelta mediante un parámetro de consulta en modo de reloj, ya que el análisis de texto de ClickHouse puede seleccionar un desplazamiento diferente. Use un datetime con zona horaria o una hora de reloj válida cuando el instante sea importante.
La opción solo se aplica a inserciones nativas de objetos Python de valores datetime y cadenas ISO sin zona horaria aceptadas por DateTime64. Las columnas de NumPy y Pandas con dtype datetime64 sin zona horaria conservan su conversión actual de hora de reloj UTC.
Para representar un instante específico independientemente de cualquiera de los modos, asigne la zona horaria deseada o proporcione explícitamente un entero de época.
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"])Los parámetros de consulta datetime sin zona horaria usan la configuración independiente naive_datetime_binding. De forma predeterminada, el modo "wall" envía los campos de hora local sin conversión a la hora local del host. Consulte la sección Argumento Parameters.
Columnas DateTime con metadatos de zona horaria
Las columnas de ClickHouse pueden declarar metadatos de zona horaria, por ejemplo DateTime('America/Denver') o DateTime64(3, 'Asia/Tokyo'). Estos metadatos controlan cómo se presentan los valores al consultarlos.
Al insertar un valor con zona horaria, ClickHouse Connect conserva el instante representado. Para un valor sin zona horaria, la configuración naive_datetime_insert controla si se usa la zona horaria del proceso o la de la columna. Al consultar, el resultado usa la zona horaria de la columna, a menos que se proporcione una sobrescritura por columna con el argumento column_tzs. El argumento query_tz no sobrescribe la zona horaria declarada de la columna.
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")Inserciones de archivos
clickhouse_connect.driver.tools.insert_file carga un archivo local en una tabla existente por streaming y delega el análisis en ClickHouse.
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
client |
Client |
Obligatorio | Client síncrono utilizado para la inserción. |
table |
str | Obligatorio | Tabla de destino simple o calificada con la base de datos. |
file_path |
str | Obligatorio | Ruta local al archivo de entrada. |
fmt |
str | "CSV" or "CSVWithNames" |
Formato de entrada. El valor predeterminado es "CSV" cuando se proporciona column_names y "CSVWithNames" en caso contrario. |
column_names |
Sequence[str] | None |
Columnas representadas por el archivo. No es obligatorio para los formatos que incluyen nombres. |
database |
str | None |
Base de datos de destino cuando la tabla no está calificada. |
settings |
dict | None |
Consulte argumento Settings. |
compression |
str | None |
Compresión existente del archivo, como "zstd", "lz4" o "gzip". gzip se infiere a partir de los nombres de archivo .gz y .gzip. |
La configuración del formato de entrada, como input_format_allow_errors_ratio y input_format_allow_errors_num, puede pasarse mediante 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,
},
)Para un AsyncClient, usa await con insert_file_async y los mismos argumentos:
from clickhouse_connect.driver.tools import insert_file_async
await insert_file_async(async_client, "example_table", "my_data.csv")La función auxiliar async lee el archivo en un hilo de trabajo antes de hacer await de raw_insert, por lo que el contenido del archivo se mantiene en memoria.