Saltar al contenido principal

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 cliente. 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.
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 cliente 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 Python
  • query_row_block_stream — Devuelve los datos de la consulta como un bloque de filas utilizando objetos nativos de Python
  • query_rows_stream — Devuelve los datos de la consulta como una secuencia de filas utilizando objetos nativos de Python
  • query_np_stream — Devuelve cada bloque de datos de la consulta de ClickHouse como un array de NumPy
  • query_df_stream — Devuelve cada bloque de datos de la consulta de ClickHouse como un DataFrame de Pandas
  • query_arrow_stream — Devuelve los datos de la consulta en bloques de registros de PyArrow
  • query_df_arrow_stream — Devuelve cada bloque de datos de la consulta de ClickHouse como un DataFrame de Pandas basado en Arrow o un DataFrame de Polars, según el argumento con nombre dataframe_library (el valor predeterminado es “pandas”).
Cada uno de estos métodos devuelve un objeto ContextStream que debe abrirse mediante una sentencia with para empezar a consumir el stream.

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 — Límite del tamaño del bloque en filas. Valor predeterminado: 65536.
  • preferred_block_size_bytes — Límite flexible del tamaño del bloque en bytes. Valor predeterminado: 1,000,0000.
Independientemente de preferred_block_size_setting, ningún bloque tendrá nunca más de max_block_size filas. Según el tipo de consulta, los bloques devueltos reales pueden ser de cualquier tamaño. Por ejemplo, las consultas a una tabla distribuida que abarca muchos segmentos pueden contener bloques más pequeños recuperados directamente de cada segmento. 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

Debido a las limitaciones del protocolo HTTP, si los bloques se procesan a una velocidad significativamente menor que aquella a la que el servidor ClickHouse transmite los datos, el servidor ClickHouse cerrará la conexión, lo que hará que se lance una excepción en el hilo de procesamiento. Esto puede mitigarse en parte aumentando el tamaño del búfer de streaming HTTP (cuyo valor predeterminado es de 10 megabytes) mediante la configuración común http_buffer_size. Los valores altos de http_buffer_size suelen ser adecuados en esta situación si la aplicación dispone de suficiente memoria. Los datos del búfer se almacenan comprimidos si se usa compresión lz4 o zstd, por lo que usar estos tipos de compresión aumentará el tamaño total del búfer disponible.

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:
Ten en cuenta que intentar usar un StreamContext sin una instrucción 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. Puedes usar la propiedad source del StreamContext para acceder al objeto QueryResult padre, que incluye los nombres de las columnas y los tipos.

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. query_row_stream es un método auxiliar que pasa automáticamente al siguiente bloque al iterar por el flujo. Por lo demás, es idéntico a query_row_block_stream. El método query_np_stream devuelve cada bloque como un array de NumPy bidimensional. Internamente, los arrays de NumPy se almacenan (normalmente) como columnas, por lo que no se necesitan métodos distintos para filas o columnas. La “forma” del array de NumPy se expresará como (columnas, filas). La biblioteca NumPy proporciona muchos métodos para manipular arrays de NumPy. Ten en cuenta que, si todas las columnas de la consulta comparten el mismo dtype de NumPy, el array de NumPy devuelto también tendrá un único dtype y podrá reformarse o rotarse sin cambiar realmente su estructura interna. 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).
El método query_df_arrow_stream devuelve cada bloque de ClickHouse como un DataFrame con el backend de dtype de PyArrow. Este método admite DataFrames de Pandas (2.x o posterior) y de Polars mediante el parámetro dataframe_library (cuyo valor predeterminado es "pandas"). Cada iteración genera un DataFrame convertido a partir de record batches de PyArrow, lo que ofrece mejor rendimiento y mayor eficiencia de memoria para ciertos tipos de datos. Por último, el método query_arrow_stream devuelve un resultado de ClickHouse en formato ArrowStream como un pyarrow.ipc.RecordBatchStreamReader encapsulado en StreamContext. Cada iteración del stream devuelve un RecordBlock de PyArrow.

Ejemplos de streaming

Transmitir filas en streaming

Transmitir bloques de filas

Transmitir DataFrames de Pandas

Transmitir lotes de Arrow

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.

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.

Consultas con PyArrow

El método query_arrow devuelve los resultados de la consulta como una tabla de PyArrow. Utiliza directamente el formato Arrow de ClickHouse, por lo que solo comparte tres argumentos con el método principal query: query, parameters y settings. Además, hay un argumento adicional, use_strings, que determina si la tabla Arrow mostrará los tipos String de ClickHouse como cadenas (si es True) o como bytes (si es False).

DataFrames basados en Arrow

ClickHouse Connect admite la creación rápida y eficiente en memoria de DataFrames a partir de resultados de Arrow mediante los métodos query_df_arrow y query_df_arrow_stream. Son envoltorios ligeros de los métodos de consulta de Arrow y realizan conversiones sin copia a DataFrames cuando es posible:
  • query_df_arrow: Ejecuta la consulta con el formato de salida Arrow de ClickHouse y devuelve un DataFrame.
    • Para dataframe_library='pandas', devuelve un DataFrame de pandas 2.x que usa tipos de datos basados en Arrow (pd.ArrowDtype). Esto requiere pandas 2.x y aprovecha búferes sin copia siempre que sea posible para ofrecer un rendimiento excelente y una baja sobrecarga de memoria.
    • Para dataframe_library='polars', devuelve un DataFrame de Polars creado a partir de la tabla Arrow (pl.from_arrow), que es igual de eficiente y puede no requerir copia, según los datos.
  • query_df_arrow_stream: Transmite los resultados como una secuencia de DataFrames (pandas 2.x o Polars) convertidos a partir de lotes del flujo Arrow.

Consulta a un DataFrame basado en Arrow

Notas y advertencias

  • Correspondencia de tipos de Arrow: Al devolver datos en formato Arrow, ClickHouse asigna los tipos a los tipos de Arrow compatibles más cercanos. Algunos tipos de ClickHouse no tienen un equivalente nativo en Arrow y se devuelven como bytes sin procesar en campos de Arrow (normalmente BINARY o FIXED_SIZE_BINARY).
    • Ejemplos: IPv4 se representa como Arrow UINT32; IPv6 y los enteros grandes (Int128/UInt128/Int256/UInt256) suelen representarse como FIXED_SIZE_BINARY/BINARY con bytes sin procesar.
    • En estos casos, la columna del DataFrame contendrá valores de bytes respaldados por el campo de Arrow; corresponde al código cliente interpretar o convertir esos bytes según la semántica de ClickHouse.
  • Los tipos de datos de Arrow no compatibles (p. ej., UUID/ENUM como verdaderos tipos de Arrow) no se emiten; los valores se representan usando el tipo de Arrow compatible más cercano (a menudo, como bytes binarios) para la salida.
  • Requisito de pandas: Los dtypes basados en Arrow requieren pandas 2.x. Para versiones anteriores de pandas, use query_df (sin Arrow) en su lugar.
  • Strings frente a binario: La opción use_strings (cuando es compatible con la configuración del servidor output_format_arrow_string_as_string) controla si las columnas String de ClickHouse se devuelven como cadenas de Arrow o como binario.

Ejemplos de conversión entre tipos incompatibles de ClickHouse/Arrow

Cuando ClickHouse devuelve columnas como datos binarios sin procesar (p. ej., FIXED_SIZE_BINARY o BINARY), corresponde al código de la aplicación convertir esos bytes en los tipos de Python adecuados. Los ejemplos siguientes muestran que algunas conversiones pueden realizarse con las API de bibliotecas de DataFrame, mientras que otras pueden requerir enfoques de Python puro, como struct.unpack (que sacrifican rendimiento, pero mantienen la flexibilidad). Las columnas Date pueden llegar como UINT16 (días desde la época Unix, 1970‑01‑01). Convertirlas dentro del DataFrame es eficiente y sencillo:
Las columnas como Int128 pueden llegar como FIXED_SIZE_BINARY con bytes sin procesar. Polars ofrece soporte nativo para enteros de 128 bits:
A partir de NumPy 2.3 no hay ningún dtype público para enteros de 128 bits, así que debemos recurrir a Python puro y podemos hacer algo como esto:
La conclusión clave: el código de aplicación debe encargarse de estas conversiones en función de las capacidades de la biblioteca DataFrame elegida y de las compensaciones de rendimiento aceptables. Cuando no se dispone de conversiones nativas de DataFrame, los enfoques basados en Python puro siguen siendo una opción.

Formatos de lectura

Los formatos de lectura controlan los tipos de datos de los valores devueltos por los métodos query, query_np y query_df del cliente. (Los métodos raw_query y query_arrow no modifican los datos entrantes de ClickHouse, por lo que el control de formato no se aplica). Por ejemplo, si el formato de lectura de un UUID se cambia del formato native predeterminado al formato alternativo string, una consulta de ClickHouse sobre una columna UUID se devolverá como valores de cadena (usando el formato RFC 1422 estándar 8-4-4-4-12) en lugar de objetos UUID de Python. El argumento “tipo de dato” de cualquier función de formateo puede incluir comodines. El formato es una única cadena en minúsculas. Los formatos de lectura se pueden establecer en varios niveles:
  • Globalmente, usando los métodos definidos en el paquete clickhouse_connect.datatypes.format. Esto controlará el formato del tipo de dato configurado para todas las consultas.
  • Para una consulta completa, mediante el argumento de diccionario opcional query_formats. En ese caso, cualquier columna (o subcolumna) de los tipos de datos especificados usará el formato configurado.
  • Para los valores de una columna específica, mediante el argumento de diccionario opcional column_formats. La clave es el nombre de la columna tal como lo devuelve ClickHouse, y el valor es el formato de la columna de datos o un diccionario “format” de segundo nivel, con un nombre de tipo de ClickHouse como clave y un valor de formatos de consulta. Este diccionario secundario se puede usar para tipos de columna anidados, como Tuples o Maps.

Opciones de formato de lectura (tipos de Python)

Datos externos

Las consultas de ClickHouse pueden aceptar datos externos en cualquier formato de ClickHouse. Estos datos binarios se envían junto con la cadena de consulta para utilizarlos en el procesamiento de los datos. Los detalles de la funcionalidad External Data están aquí. Los métodos query* del cliente aceptan un parámetro opcional external_data para aprovechar esta funcionalidad. El valor del parámetro external_data debe ser un objeto clickhouse_connect.driver.external.ExternalData. El constructor de ese objeto acepta los siguientes argumentos: Para enviar una consulta con un archivo CSV externo que contiene datos de “movie” y combinar esos datos con una tabla directors ya presente en el servidor de ClickHouse:
Se 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. Para HTTP, todos los datos externos se transmiten como parte de una carga de archivos multi-part/form-data.

Zonas horarias

Existen varios mecanismos para aplicar una zona horaria a los valores DateTime y DateTime64 de ClickHouse. Internamente, el servidor ClickHouse siempre almacena cualquier objeto DateTime o DateTime64 como un número sin zona horaria que representa los segundos transcurridos desde el epoch, 1970-01-01 00:00:00 UTC. Para los valores DateTime64, la representación puede ser en milisegundos, microsegundos o nanosegundos desde el epoch, según la precisión. Como resultado, cualquier información de zona horaria se aplica siempre en el cliente. Ten en cuenta que esto implica un cálculo adicional significativo, por lo que, en aplicaciones donde el rendimiento es crítico, se recomienda tratar los tipos DateTime como timestamps epoch, salvo para la visualización y conversión para el usuario (por ejemplo, los Pandas Timestamps siempre son un entero de 64 bits que representa nanosegundos desde el epoch para mejorar el rendimiento). Al usar tipos de datos con zona horaria en las consultas, en particular el objeto datetime.datetime de Python, clickhouse-connect aplica una zona horaria en el cliente según las siguientes reglas de precedencia:
  1. Si se especifica el parámetro del método de consulta client_tzs para la consulta, se aplica la zona horaria específica de la columna
  2. Si la columna de ClickHouse tiene metadatos de zona horaria (es decir, es de un tipo como DateTime64(3, ‘America/Denver’)), se aplica la zona horaria de la columna de ClickHouse. (Ten en cuenta que estos metadatos de zona horaria no están disponibles para clickhouse-connect en las columnas DateTime anteriores a la versión 23.2 de ClickHouse)
  3. Si se especifica el parámetro del método de consulta query_tz para la consulta, se aplica la “zona horaria de la consulta”.
  4. Si se aplica una configuración de zona horaria a la consulta o a la sesión, se aplica esa zona horaria. (Esta funcionalidad aún no se ha publicado en el servidor ClickHouse)
  5. Por último, si el parámetro del cliente apply_server_timezone se ha establecido en True (el valor predeterminado), se aplica la zona horaria del servidor ClickHouse.
Ten en cuenta que, si la zona horaria aplicada según estas reglas es UTC, clickhouse-connect siempre devolverá un objeto datetime.datetime de Python sin zona horaria. Si se desea, el application code puede añadir después información adicional de zona horaria a este objeto sin zona horaria.
Última modificación el 25 de junio de 2026