QueryContexts
ClickHouse Connect ejecuta consultas estándar dentro de un QueryContext. El QueryContext contiene las estructuras clave que se utilizan para crear consultas en la base de datos ClickHouse, así como la configuración usada para procesar el resultado en un QueryResult u otra estructura de datos de respuesta. Esto incluye la propia consulta, parámetros, ajustes, formatos de lectura y otras propiedades.
Se puede obtener un QueryContext mediante el método create_query_context del Client. Este método acepta los mismos parámetros que el método principal de consulta. Después, este contexto de consulta puede pasarse a los métodos query, query_df o query_np como argumento con nombre context, en lugar de cualquiera o de todos los demás argumentos de esos métodos. Tenga en cuenta que los argumentos adicionales especificados en la llamada al método sobrescribirán cualquier propiedad de QueryContext.
El caso de uso más claro de un QueryContext es enviar la misma consulta con distintos valores de parámetros enlazados. Todos los valores de los parámetros pueden actualizarse llamando al método QueryContext.set_parameters con un diccionario, o bien se puede actualizar un valor individual llamando a QueryContext.set_parameter con el par key, value deseado.
qc = client.create_query_context(
query="SELECT {k:Int32}",
parameters={"k": 13},
)
result = client.query(context=qc)
assert result.first_row == (13,)
qc.set_parameter("k", 79)
result = client.query(context=qc)
assert result.first_row == (79,)Ten en cuenta que los QueryContexts no son seguros para su uso en varios hilos, pero se puede obtener una copia en un entorno multihilo llamando al método QueryContext.updated_copy.
Consultas en streaming
El Client ClickHouse Connect proporciona varios métodos para recuperar datos como un stream (implementado como un generador de Python):
query_column_block_stream– Devuelve los datos de la consulta en bloques, como una secuencia de columnas, utilizando objetos nativos de Pythonquery_row_block_stream– Devuelve los datos de la consulta como un bloque de filas utilizando objetos nativos de Pythonquery_rows_stream– Devuelve los datos de la consulta como una secuencia de filas utilizando objetos nativos de Pythonquery_np_stream– Devuelve cada bloque de datos de la consulta de ClickHouse como un array de NumPyquery_df_stream– Devuelve cada bloque de datos de la consulta de ClickHouse como un DataFrame de Pandasquery_arrow_stream– Devuelve los datos de la consulta como objetosRecordBatchde PyArrowquery_df_arrow_stream– Devuelve cada lote de Arrow como un DataFrame de Pandas o de Polars, seleccionado pordataframe_library
Cada método devuelve un StreamContext que debe abrirse con una sentencia with. Los métodos de streaming del Client async deben esperarse y abrirse con async with.
Bloques de datos
ClickHouse Connect procesa todos los datos del método query principal como un flujo de bloques recibidos del servidor ClickHouse. Estos bloques se transmiten hacia y desde ClickHouse en el formato personalizado "Native". Un "bloque" es simplemente una secuencia de columnas de datos binarios, en la que cada columna contiene la misma cantidad de valores de datos del tipo de dato especificado. (Como base de datos columnar, ClickHouse almacena estos datos de forma similar). El tamaño de un bloque devuelto por una consulta depende de dos configuraciones de usuario que pueden establecerse en varios niveles (perfil de usuario, usuario, sesión o consulta). Son:
- max_block_size – Tamaño máximo del bloque en filas.
- preferred_block_size_bytes – Tamaño preferido del bloque en bytes.
Independientemente de preferred_block_size_bytes, un bloque no superará max_block_size filas. El tamaño real puede ser menor y no debe considerarse estable.
Al usar uno de los métodos query_*_stream del cliente, los resultados se devuelven bloque por bloque. ClickHouse Connect solo carga un bloque a la vez. Esto permite procesar grandes cantidades de datos sin necesidad de cargar en memoria todo un conjunto de resultados grande. Ten en cuenta que la aplicación debe estar preparada para procesar cualquier cantidad de bloques y que el tamaño exacto de cada bloque no puede controlarse.
Búfer de datos HTTP para procesamiento lento
Si una aplicación consume bloques mucho más lentamente de lo que el servidor los produce, la conexión HTTP puede cerrarse antes de que termine el procesamiento. Aumente la configuración global http_buffer_size cuando la aplicación tenga suficiente memoria para almacenar en búfer más datos de respuesta. El valor predeterminado es de 10 MiB. Los bytes de respuesta de lz4 y zstd permanecen comprimidos en este búfer, lo que aumenta su capacidad efectiva.
StreamContexts
Cada uno de los métodos query_*_stream (como query_row_block_stream) devuelve un objeto StreamContext de ClickHouse, que combina un contexto y un generador de Python. Este es el uso básico:
with client.query_row_block_stream(
"SELECT pickup, dropoff, pickup_longitude, pickup_latitude FROM taxi_trips"
) as stream:
for block in stream:
for row in block:
process_trip(row)Ten en cuenta que intentar usar un StreamContext sin una sentencia with generará un error. El uso de un contexto de Python garantiza que el stream (en este caso, una respuesta HTTP en streaming) se cierre correctamente aunque no se consuman todos los datos y/o se produzca una excepción durante el procesamiento. Además, los StreamContext solo pueden usarse una vez para consumir el stream. Intentar usar un StreamContext después de haber salido de él producirá un StreamClosedError.
Si la conexión falla mientras se está leyendo un resultado, se genera un StreamFailureError en lugar de devolver silenciosamente un resultado truncado. Su mensaje sigue la configuración show_clickhouse_errors del client.
Puedes usar la propiedad source del StreamContext para acceder al objeto de resultado padre, que incluye los nombres de las columnas y los tipos. Para la mayoría de los streams, este es un QueryResult; los métodos query_np_stream y query_df_stream exponen un NumpyResult en su lugar.
Tipos de flujo
El método query_column_block_stream devuelve el bloque como una secuencia de datos de columna almacenados como tipos de datos nativos de Python. Si usamos las consultas taxi_trips anteriores, los datos devueltos serán una lista en la que cada elemento es otra lista (o tupla) que contiene todos los datos de la columna correspondiente. Así, block[0] sería una tupla que solo contendría cadenas. Los formatos orientados a columnas se usan sobre todo para realizar operaciones de agregación sobre todos los valores de una columna, como sumar las tarifas totales.
El método query_row_block_stream devuelve el bloque como una secuencia de filas, como en una base de datos relacional tradicional. Para los trayectos de taxi, los datos devueltos serán una lista en la que cada elemento es otra lista que representa una fila de datos. Así, block[0] contendría todos los campos (en orden) del primer trayecto de taxi, block[1] contendría una fila con todos los campos del segundo trayecto de taxi, y así sucesivamente. Los resultados orientados a filas normalmente se usan en procesos de visualización o transformación.
El método query_rows_stream pasa automáticamente al siguiente bloque y devuelve una fila cada vez. Es la contraparte fila por fila de query_row_block_stream.
El método query_np_stream devuelve cada bloque como un array de NumPy. Cuando todas las columnas del resultado comparten un dtype de NumPy, el array es bidimensional con forma (filas, columnas). Los resultados mixtos se devuelven como un array estructurado unidimensional o usan el dtype object.
El método query_df_stream devuelve cada bloque de ClickHouse como un DataFrame de Pandas bidimensional. Aquí tienes un ejemplo que muestra que el objeto StreamContext puede usarse como contexto de forma diferida (pero solo una vez).
df_stream = client.query_df_stream("SELECT * FROM hits")
column_names = df_stream.source.column_names
with df_stream:
for df in df_stream:
process_dataframe(df)El método query_df_arrow_stream convierte lotes de Arrow en DataFrames de Pandas o Polars. Selecciona la biblioteca con dataframe_library, cuyo valor predeterminado es "pandas".
Por último, query_arrow_stream encapsula una respuesta ArrowStream de ClickHouse en un StreamContext. Cada iteración devuelve un RecordBatch de PyArrow.
Ejemplos de streaming
Transmitir filas en streaming
import clickhouse_connect
client = clickhouse_connect.get_client()
# Stream large result sets row by row
with client.query_rows_stream("SELECT number, number * 2 as doubled FROM system.numbers LIMIT 100000") as stream:
for row in stream:
print(row) # Process each row
# Output:
# (0, 0)
# (1, 2)
# (2, 4)
# Additional rows followTransmitir bloques de filas
import clickhouse_connect
client = clickhouse_connect.get_client()
# Stream in blocks of rows (more efficient than row-by-row)
with client.query_row_block_stream("SELECT number, number * 2 FROM system.numbers LIMIT 100000") as stream:
for block in stream:
print(f"Received block with {len(block)} rows")Transmitir DataFrames de Pandas
import clickhouse_connect
client = clickhouse_connect.get_client()
# Stream query results as Pandas DataFrames
with client.query_df_stream("SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000") as stream:
for df in stream:
# Process each DataFrame block
print(f"Received DataFrame with {len(df)} rows")
print(df.head(3))Transmitir lotes de Arrow
import clickhouse_connect
client = clickhouse_connect.get_client()
# Stream query results as Arrow record batches
with client.query_arrow_stream("SELECT * FROM large_table") as stream:
for arrow_batch in stream:
# Process each Arrow batch
print(f"Received Arrow batch with {arrow_batch.num_rows} rows")Filas en streaming asíncrono
import asyncio
import clickhouse_connect
async def main():
async_client = await clickhouse_connect.get_async_client()
async with await async_client.query_rows_stream(
"SELECT number FROM numbers(100000)"
) as stream:
async for row in stream:
print(row)
asyncio.run(main())Consultas con NumPy, Pandas y Arrow
ClickHouse Connect proporciona métodos de consulta especializados para trabajar con estructuras de datos de NumPy, Pandas y Arrow. Estos métodos le permiten obtener los resultados de las consultas directamente en estos formatos de datos populares, sin necesidad de conversión manual.
Consultas con NumPy
El método query_np devuelve los resultados de la consulta como un array de NumPy en lugar de un QueryResult de ClickHouse Connect.
import clickhouse_connect
client = clickhouse_connect.get_client()
# Query returns a NumPy array
np_array = client.query_np("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")
print(type(np_array))
# Output:
# <class 'numpy.ndarray'>
print(np_array)
# Output:
# [[0 0]
# [1 2]
# [2 4]
# [3 6]
# [4 8]]Consultas con Pandas
El método query_df devuelve los resultados de la consulta como un DataFrame de Pandas en lugar de un QueryResult de ClickHouse Connect.
import clickhouse_connect
client = clickhouse_connect.get_client()
# Query returns a Pandas DataFrame
df = client.query_df("SELECT number, number * 2 AS doubled FROM system.numbers LIMIT 5")
print(type(df))
# Output: <class 'pandas.core.frame.DataFrame'>
print(df)
# Output:
# number doubled
# 0 0 0
# 1 1 2
# 2 2 4
# 3 3 6
# 4 4 8Consultas con PyArrow
El método query_arrow devuelve una tabla de PyArrow utilizando directamente el formato de salida Arrow de ClickHouse. Acepta query, parameters, settings, external_data y transport_settings. La opción use_strings controla si las columnas String de ClickHouse se emiten como cadenas de Arrow o como valores binarios.
import clickhouse_connect
client = clickhouse_connect.get_client()
# Query returns a PyArrow Table
arrow_table = client.query_arrow("SELECT number, toString(number) AS str FROM system.numbers LIMIT 3")
print(type(arrow_table))
# Output:
# <class 'pyarrow.lib.Table'>
print(arrow_table)
# Output:
# pyarrow.Table
# number: uint64 not null
# str: string not null
# ----
# number: [[0,1,2]]
# str: [["0","1","2"]]DataFrames basados en Arrow
ClickHouse Connect permite crear DataFrames de forma eficiente a partir de resultados de Arrow mediante query_df_arrow y query_df_arrow_stream. Estos métodos evitan la conversión mediante objetos fila de Python y reutilizan los búferes de Arrow cuando la biblioteca de destino lo permite:
query_df_arrow: Ejecuta la consulta con el formato de salidaArrowde ClickHouse y devuelve un DataFrame.dataframe_library="pandas"devuelve un DataFrame de Pandas 2.0 o posterior usandopd.ArrowDtype.dataframe_library="polars"devuelve un DataFrame de Polars creado conpl.from_arrow.
query_df_arrow_stream: Transmite lotes de Arrow como DataFrames de Pandas o Polars.
Consulta a un DataFrame basado en Arrow
import clickhouse_connect
client = clickhouse_connect.get_client()
# Query returns a Pandas DataFrame with Arrow dtypes (requires pandas 2.x)
df = client.query_df_arrow(
"SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
dataframe_library="pandas"
)
print(df.dtypes)
# Output:
# number uint64[pyarrow]
# str string[pyarrow]
# dtype: object
# Or use Polars
polars_df = client.query_df_arrow(
"SELECT number, toString(number) AS str FROM system.numbers LIMIT 3",
dataframe_library="polars"
)
print(polars_df.dtypes)
# Output:
# [UInt64, String]
# Streaming into batches of DataFrames (polars shown)
with client.query_df_arrow_stream(
"SELECT number, toString(number) AS str FROM system.numbers LIMIT 100000", dataframe_library="polars"
) as stream:
for df_batch in stream:
print(f"Received {type(df_batch)} batch with {len(df_batch)} rows and dtypes: {df_batch.dtypes}")Notas y advertencias
- ClickHouse controla el esquema de Arrow. Los tipos sin una representación directa en Arrow pueden devolverse usando un tipo físico compatible, incluidos los campos binarios. Inspeccione
table.schemao los dtypes del DataFrame antes de aplicar conversiones específicas de la aplicación. - Los resultados de Pandas basados en Arrow requieren Pandas 2.0 o posterior.
use_stringscontrola si las columnasStringde ClickHouse usan campos de cadena o binarios de Arrow cuando el servidor admiteoutput_format_arrow_string_as_string.tz_mode="schema"todavía no es compatible con los métodos de consulta basados en Arrow. Emiten una advertencia y conservan los metadatos de zona horaria proporcionados por la respuesta de Arrow.
Formatos de lectura
Los formatos de lectura controlan los valores devueltos por query, query_np y query_df. No se aplican a los métodos raw ni Arrow porque esos métodos usan directamente un formato de salida del servidor. Por ejemplo, establecer el formato de lectura de UUID en "string" devuelve cadenas UUID en lugar de objetos uuid.UUID.
El argumento "data type" de cualquier función de formatting puede incluir wildcards. El format es una única cadena en minúsculas. Los envoltorios de contenedor, como Array, Nullable y LowCardinality, conservan el formato seleccionado para su element type.
Los formatos de lectura pueden establecerse en varios niveles:
- Globalmente, usando los métodos definidos en el package
clickhouse_connect.datatypes.format. Esto controlará el formato del tipo de dato configurado para todas las consultas.
from clickhouse_connect.datatypes.format import set_read_format
# Return both IPv6 and IPv4 values as strings
set_read_format("IPv*", "string")
# Return all Date types as the underlying epoch second or epoch day
set_read_format("Date*", "int")- Para una consulta completa, con el argumento de diccionario opcional
query_formats. En ese caso, cualquier columna (o subcolumna) de los tipos de dato especificados usará el formato configurado.
# Return any UUID column as a string
client.query(
"SELECT user_id, user_uuid, device_uuid FROM users",
query_formats={"UUID": "string"},
)- Para una columna de resultado específica, use el diccionario opcional
column_formats. Cada clave es el nombre de una columna devuelta. Su valor es una cadena de formato o una correspondencia anidada entre nombres de tipos de ClickHouse y formatos, lo que resulta útil para Tuples, Maps y otros tipos contenedores.
# Return IPv6 values in the `dev_address` column as strings
client.query(
"SELECT device_id, dev_address, gw_address FROM devices",
column_formats={"dev_address": "string"},
)Opciones de formato de lectura (tipos de Python)
| Tipo de ClickHouse | Tipo nativo de Python | Formatos de lectura | Comentarios |
|---|---|---|---|
| Int[8-64], UInt[8-32] | int | string | |
| UInt64 | int | signed | Actualmente, Superset no admite valores UInt64 grandes sin signo |
| [U]Int[128,256] | int | string | Los valores int de Pandas y NumPy tienen un máximo de 64 bits, por lo que pueden devolverse como cadenas |
| BFloat16 | float | - | Todos los float de Python son internamente de 64 bits |
| Float32 | float | string | Todos los float de Python son internamente de 64 bits |
| Float64 | float | string | |
| Decimal | decimal.Decimal | - | |
| String | str | bytes | Las columna String de ClickHouse no tienen una codificación inherente, por lo que también se usan para datos binarios de longitud variable |
| FixedString | bytes | string | FixedStrings son arrays de bytes de tamaño fijo, pero a veces se tratan como cadenas de Python |
| Enum[8,16] | str | int | El formato nativo devuelve etiquetas; int devuelve el entero subyacente. |
| Date | datetime.date | int | El formato entero devuelve los días desde 1970-01-01. |
| Date32 | datetime.date | int | El formato entero devuelve el desplazamiento ampliado de días con signo. |
| DateTime | datetime.datetime | int | El formato entero devuelve segundos desde la época Unix. |
| DateTime64 | datetime.datetime | int | El formato entero devuelve ticks con la precisión de la columna. datetime de Python está limitado a microsegundos. |
| Time | datetime.timedelta | int, string, time | El formato entero devuelve segundos. El formato time está limitado a valores que caben en datetime.time. |
| Time64 | datetime.timedelta | int, string, time | El formato entero devuelve ticks con la precisión de la columna. timedelta de Python está limitado a microsegundos. |
| IPv4 | ipaddress.IPv4Address |
string, int | Las direcciones IP pueden leerse como cadenas o enteros. |
| IPv6 | ipaddress.IPv6Address |
string | Las direcciones IP pueden leerse como cadenas y, si tienen el formato adecuado, pueden insertarse como direcciones IP |
| Tuple | dict or tuple | tuple, dict, json | Las tuplas con nombre devuelven diccionarios de forma predeterminada; las tuplas sin nombre devuelven tuplas. |
| Map | dict | - | |
| Nested | Sequence[dict] | - | |
| UUID | uuid.UUID | string | Los UUIDs pueden leerse como cadenas con formato según RFC 4122 |
| JSON | dict | string | De forma predeterminada, se devuelve un diccionario de Python. El formato string devolverá una cadena JSON |
| Variant | object | typed | typed devuelve TypedVariant(value, type_name) para preservar el tipo de miembro original. |
| Dynamic | object | - | Devuelve el tipo de Python correspondiente al tipo de dato de ClickHouse almacenado para el valor |
| QBit | list[float] | - | NumPy se usa automáticamente para una transposición de bits más rápida cuando está instalado. |
Datos externos
Las consultas de ClickHouse pueden aceptar datos externos en cualquier formato de entrada admitido. El Client envía los datos como parte de la solicitud, y la consulta puede referirse a ellos como una tabla externa temporal. Consulte la documentación sobre datos externos de ClickHouse. Los métodos de consulta del Client aceptan un objeto clickhouse_connect.driver.external.ExternalData mediante el parámetro external_data.
| Nombre | Tipo | Descripción |
|---|---|---|
| file_path | str | Ruta a un archivo en el sistema local desde la que se leerán los datos externos. Se requiere file_path o data |
| file_name | str | El nombre del "archivo" de datos externos. Si no se proporciona, se toma de la parte correspondiente al nombre de archivo de file_path. El nombre de la tabla externa es el nombre del archivo sin la extensión |
| data | bytes | Los datos externos en forma binaria (en lugar de leerse desde un archivo). Se requiere data o file_path |
| fmt | str | El formato de entrada de los datos en ClickHouse. El valor predeterminado es TSV |
| types | str or seq of str | Una lista de tipos de datos de las columnas en los datos externos. Si es una cadena, los tipos deben separarse con comas. Se requiere types o structure |
| structure | str or seq of str | Una lista de nombres de columna + tipo de dato en los datos (consulte los ejemplos). Se requiere structure o types |
| mime_type | str | Tipo MIME opcional de los datos del archivo. Actualmente, ClickHouse ignora este subencabezado HTTP |
Este ejemplo realiza un join de un archivo CSV externo con una tabla directors almacenada en el server:
import clickhouse_connect
from clickhouse_connect.driver.external import ExternalData
client = clickhouse_connect.get_client()
ext_data = ExternalData(
file_path="/data/movies.csv",
fmt="CSV",
structure=[
"movie String",
"year UInt16",
"rating Decimal32(3)",
"director String",
],
)
result = client.query(
"SELECT name, avg(rating) "
"FROM directors INNER JOIN movies ON directors.name = movies.director "
"GROUP BY directors.name",
external_data=ext_data,
).result_rowsSe pueden añadir archivos de datos externos adicionales al objeto ExternalData inicial mediante el método add_file, que acepta los mismos parámetros que el constructor. En HTTP, todos los datos externos se transmiten como parte de una carga de archivos multi-part/form-data.
El backend de chDB no admite datos externos.
Zonas horarias
Los valores DateTime y DateTime64 de ClickHouse se transmiten como valores numéricos basados en la época Unix. ClickHouse Connect los convierte en objetos datetime de Python usando los metadatos de la columna, las sobrescrituras de la consulta y la política de zona horaria del Client.
El Client tiene dos opciones de zona horaria independientes:
tz_sourceselecciona la zona horaria de respaldo para las columnas sin metadatos explícitos de zona horaria:"auto"es la opción predeterminada. Usa la zona horaria del servidor cuando el Client puede resolverla de forma segura a través de los cambios de horario de verano; de lo contrario, usa la zona horaria local."server"siempre usa la zona horaria del servidor."local"siempre usa la zona horaria local del proceso.
tz_modecontrola la gestión de la zona horaria:"naive_utc"es la opción predeterminada. Los resultados en UTC y equivalentes a UTC se devuelven como objetosdatetimesin zona horaria, por compatibilidad con versiones anteriores."aware"conserva latzinfode UTC y devuelve valores UTC con zona horaria."schema"devuelve valores con zona horaria solo cuando el tipo de la columna declara una zona horaria, y valores sin zona horaria para columnasDateTime/DateTime64sin especificar.
Para las consultas normales "naive_utc" y "aware", la zona horaria activa se selecciona en este orden:
- Una sobrescritura
column_tzspor columna. - Metadatos de zona horaria en el tipo de columna de ClickHouse.
- La sobrescritura
query_tzpara toda la consulta. - La información de zona horaria devuelta con la respuesta HTTP.
- La zona horaria de respaldo seleccionada por
tz_source.
tz_mode="schema" ignora las zonas horarias de la consulta y de respaldo, pero una sobrescritura explícita de column_tzs sigue teniendo prioridad.
result = client.query(
"SELECT "
"toDateTime('2026-01-15 12:00:00', 'UTC') AS utc_time, "
"toDateTime('2026-01-15 12:00:00', 'America/Denver') AS denver_time",
tz_mode="aware",
)
assert result.first_row[0].tzinfo is not None
assert result.first_row[1].tzinfo is not NoneLos nombres de las zonas horarias se resuelven con el módulo estándar zoneinfo de la biblioteca. En Windows, tzdata se instala automáticamente. En las imágenes mínimas de Linux sin una base de datos de zonas horarias de IANA, instala clickhouse-connect[tzdata].
Los resultados de Pandas conservan la resolución natural de cada tipo de ClickHouse, como datetime64[s] para DateTime y datetime64[ms] para DateTime64(3). Los métodos de DataFrame basados en Arrow query_df_arrow y query_df_arrow_stream todavía no implementan tz_mode="schema" y mostrarán una advertencia cuando se solicite. query_arrow y query_arrow_stream devuelven los metadatos de zona horaria de la respuesta Arrow sin cambios.