QueryContexts
ClickHouse Connect выполняет стандартные запросы в контексте QueryContext. QueryContext содержит ключевые структуры, используемые для построения запросов к базе данных ClickHouse, а также конфигурацию, которая используется для преобразования результата в QueryResult или другую структуру данных ответа. Сюда входят сам запрос, параметры, настройки, форматы чтения и другие свойства.
QueryContext можно получить с помощью клиентского метода create_query_context. Этот метод принимает те же параметры, что и основной метод запроса. Затем этот контекст можно передать в методы query, query_df или query_np как именованный аргумент context вместо части или всех остальных аргументов этих методов. Обратите внимание, что дополнительные аргументы, указанные при вызове метода, переопределяют любые свойства QueryContext.
Наиболее понятный сценарий использования QueryContext — отправка одного и того же запроса с разными значениями параметров привязки. Все значения параметров можно обновить, вызвав метод QueryContext.set_parameters и передав ему словарь, а любое отдельное значение — вызвав QueryContext.set_parameter с нужной парой key, value.
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,)Обратите внимание, что объекты QueryContext не являются потокобезопасными, однако в многопоточной среде можно получить их копию, вызвав метод QueryContext.updated_copy.
Стриминг запросов
Клиент ClickHouse Connect предоставляет несколько методов для получения данных в виде потока (реализованного как генератор Python):
query_column_block_stream– Возвращает данные запроса блоками как последовательность столбцов с использованием собственных объектов Pythonquery_row_block_stream– Возвращает данные запроса как блок строк с использованием собственных объектов Pythonquery_rows_stream– Возвращает данные запроса как последовательность строк с использованием собственных объектов Pythonquery_np_stream– Возвращает каждый блок данных запроса ClickHouse как массив NumPyquery_df_stream– Возвращает каждый блок данных запроса ClickHouse как DataFrame Pandasquery_arrow_stream– Возвращает данные запроса как объекты PyArrowRecordBatchquery_df_arrow_stream– Возвращает каждый батч Arrow как DataFrame Pandas или Polars, выбранный с помощьюdataframe_library
Каждый метод возвращает StreamContext, который необходимо открыть с помощью оператора with. Методы стриминга async client ожидаются через await и открываются с помощью async with.
Блоки данных
ClickHouse Connect обрабатывает все данные из основного метода query как поток блоков, получаемых от сервер ClickHouse. Эти блоки передаются в собственном формате "Native" в ClickHouse и из ClickHouse. «Блок» — это просто последовательность столбцов бинарных данных, где каждый столбец содержит одинаковое количество значений указанного типа данных. (Поскольку ClickHouse — колоночная база данных, он хранит эти данные в похожем виде.) Размер блока, возвращаемого запросом, определяется двумя пользовательскими настройками, которые можно задавать на нескольких уровнях (профиль пользователя, пользователь, сеанс или запрос). Вот они:
- max_block_size – Максимальный размер блока в строках.
- preferred_block_size_bytes – Предпочтительный размер блока в байтах.
Независимо от preferred_block_size_bytes, блок не будет превышать max_block_size строк. Фактический размер может быть меньше и не должен считаться стабильным.
При использовании одного из методов клиента query_*_stream результаты возвращаются по блокам. ClickHouse Connect загружает только один блок за раз. Это позволяет обрабатывать большие объёмы данных без необходимости загружать в память весь большой результирующий набор. Обратите внимание: приложение должно быть готово обработать любое количество блоков, а точный размер каждого блока нельзя контролировать.
HTTP-буфер данных для медленной обработки
Если приложение получает блоки значительно медленнее, чем сервер их отправляет, HTTP-соединение может закрыться до завершения обработки. Увеличьте значение общей настройки http_buffer_size, если у приложения достаточно памяти для буферизации большего объёма данных ответа. По умолчанию это значение равно 10 MiB. Данные ответа, сжатые с помощью lz4 и zstd, остаются в этом буфере в сжатом виде, что увеличивает его фактическую ёмкость.
StreamContexts
Каждый из методов query_*_stream (например, query_row_block_stream) возвращает объект ClickHouse StreamContext, который сочетает в себе Python-контекст и генератор. Вот базовое использование:
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)Обратите внимание: попытка использовать StreamContext без оператора with вызовет ошибку. Использование контекста Python гарантирует, что поток (в данном случае — потоковый HTTP-ответ) будет корректно закрыт, даже если будут прочитаны не все данные и/или в ходе обработки возникнет исключение. Кроме того, StreamContext можно использовать для чтения потока только один раз. Попытка использовать StreamContext после выхода из него приведёт к ошибке StreamClosedError.
Если соединение прерывается во время чтения результата, вместо молчаливого возврата усечённого результата возникает StreamFailureError. Его сообщение соответствует настройке клиента show_clickhouse_errors.
Вы можете использовать свойство source объекта StreamContext, чтобы получить доступ к родительскому объекту результата, который содержит имена столбцов и типы. Для большинства потоков это QueryResult; методы query_np_stream и query_df_stream вместо этого возвращают NumpyResult.
Типы потоков
Метод query_column_block_stream возвращает блок как последовательность данных столбцов в нативных типах данных Python. Если использовать приведённые выше запросы taxi_trips, возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список (или кортеж), содержащий все данные соответствующего столбца. То есть block[0] будет кортежем, содержащим только строковые значения. Форматы с ориентацией по столбцам чаще всего используются для выполнения агрегатных операций над всеми значениями в столбце, например для подсчёта общей стоимости поездок.
Метод query_row_block_stream возвращает блок как последовательность строк, как в традиционной реляционной базе данных. Для поездок на такси возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список, представляющий строку данных. То есть block[0] будет содержать все поля по порядку для первой поездки на такси, block[1] — строку со всеми полями второй поездки на такси, и так далее. Результаты с ориентацией по строкам обычно используются для отображения или преобразования данных.
Метод query_rows_stream автоматически переходит к следующему блоку и выдаёт по одной строке за раз. Это построчный аналог query_row_block_stream.
Метод query_np_stream возвращает каждый блок как массив NumPy. Когда все столбцы результата имеют общий NumPy dtype, массив является двумерным и имеет форму (строки, столбцы). Смешанные результаты возвращаются как одномерный структурированный массив или используют dtype object.
Метод query_df_stream возвращает каждый блок ClickHouse как двумерный Pandas DataFrame. Ниже приведён пример, показывающий, что объект StreamContext можно использовать как контекстный менеджер в отложенном режиме (но только один раз).
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)Метод query_df_arrow_stream преобразует батчи Arrow в Pandas или Polars DataFrame. Выберите библиотеку с помощью dataframe_library (по умолчанию — "pandas").
Наконец, метод query_arrow_stream оборачивает ответ ClickHouse ArrowStream в StreamContext. На каждой итерации возвращается PyArrow RecordBatch.
Примеры стриминга
Поток строк
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 followПотоковая передача блоков со строками
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")Потоковая передача Pandas DataFrame
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))Потоковая передача батчей 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")Асинхронный стриминг строк
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())Запросы NumPy, Pandas и Arrow
ClickHouse Connect предоставляет специализированные методы для работы со структурами данных NumPy, Pandas и Arrow. Эти методы позволяют получать результаты запроса напрямую в этих популярных форматах данных без ручного преобразования.
Запросы NumPy
Метод query_np возвращает результаты запроса в виде массива NumPy, а не объекта ClickHouse Connect QueryResult.
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]]Запросы Pandas
Метод query_df возвращает результаты запроса в виде объекта Pandas DataFrame, а не ClickHouse Connect QueryResult.
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 8Запросы PyArrow
Метод query_arrow возвращает таблицу PyArrow, напрямую используя формат вывода ClickHouse Arrow. Он принимает query, parameters, settings, external_data и transport_settings. Параметр use_strings определяет, будут ли столбцы ClickHouse String выводиться как строки Arrow или как двоичные значения.
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 на базе Arrow
ClickHouse Connect поддерживает эффективное создание DataFrame из результатов в формате Arrow с помощью query_df_arrow и query_df_arrow_stream. Эти методы позволяют избежать преобразования через объекты строк в Python и повторно использовать буферы Arrow там, где это поддерживается целевой библиотекой:
query_df_arrow: Выполняет запрос, используя выходной формат ClickHouseArrow, и возвращает DataFrame.dataframe_library="pandas"возвращает DataFrame Pandas 2.0 или более поздней версии с использованиемpd.ArrowDtype.dataframe_library="polars"возвращает DataFrame Polars, созданный с помощьюpl.from_arrow.
query_df_arrow_stream: Передаёт батчи Arrow в виде DataFrame Pandas или Polars.
Запрос к DataFrame на базе 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}")Примечания и ограничения
- ClickHouse определяет схему Arrow. Типы, для которых в Arrow нет прямого представления, могут возвращаться в совместимом физическом типе, включая двоичные поля. Проверяйте
table.schemaили dtypes DataFrame, прежде чем применять специфичные для приложения преобразования. - Результаты Pandas на базе Arrow требуют Pandas 2.0 или более поздней версии.
use_stringsопределяет, будут ли столбцы ClickHouseStringиспользовать строковые или двоичные поля Arrow, если сервер поддерживаетoutput_format_arrow_string_as_string.tz_mode="schema"пока не поддерживается методами запросов на базе Arrow. Они выдают предупреждение и сохраняют метаданные часового пояса, переданные в ответе Arrow.
Форматы чтения
Форматы чтения определяют значения, возвращаемые query, query_np и query_df. Они не применяются к методам raw или Arrow, поскольку эти методы напрямую используют формат вывода сервера. Например, если задать для UUID формат чтения "string", будут возвращаться строки UUID, а не объекты uuid.UUID.
Аргумент "тип данных" для любой функции форматирования может включать подстановочные шаблоны. Формат задается одной строкой в нижнем регистре. Обертки-контейнеры, такие как Array, Nullable и LowCardinality, сохраняют выбранный формат для своего типа элементов.
Форматы чтения можно задавать на нескольких уровнях:
- Глобально — с помощью методов, определенных в пакете
clickhouse_connect.datatypes.format. Это задает формат для настроенного типа данных во всех запросах.
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")- Для всего запроса — с использованием необязательного аргумента словаря
query_formats. В этом случае любой столбец (или подстолбец) указанных типов данных будет использовать настроенный формат.
# Return any UUID column as a string
client.query(
"SELECT user_id, user_uuid, device_uuid FROM users",
query_formats={"UUID": "string"},
)- Для отдельного столбца результата используйте необязательный словарь
column_formats. Каждый ключ — это имя возвращаемого столбца. Его значение — строка формата или вложенное сопоставление имён типов ClickHouse с форматами, что полезно для Tuple, Map и других контейнерных типов.
# 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"},
)Параметры форматов чтения (типы Python)
| Тип ClickHouse | Нативный тип Python | Форматы чтения | Комментарии |
|---|---|---|---|
| Int[8-64], UInt[8-32] | int | string | |
| UInt64 | int | signed | Superset пока не поддерживает большие беззнаковые значения UInt64 |
| [U]Int[128,256] | int | string | Значения int в Pandas и NumPy ограничены 64 битами, поэтому они могут возвращаться как строки |
| BFloat16 | float | - | Все значения float в Python внутри представлены 64 битами |
| Float32 | float | string | Все значения float в Python внутри представлены 64 битами |
| Float64 | float | string | |
| Decimal | decimal.Decimal | - | |
| String | str | bytes | Столбцы String в ClickHouse не имеют встроенного кодирования, поэтому также используются для бинарных данных переменной длины |
| FixedString | bytes | string | FixedString — это байтовые массивы фиксированного размера, но иногда они интерпретируются как строки Python |
| Enum[8,16] | str | int | Нативный формат возвращает метки; int возвращает базовое целочисленное значение. |
| Date | datetime.date | int | Целочисленный формат возвращает количество дней с 1970-01-01. |
| Date32 | datetime.date | int | Целочисленный формат возвращает расширенное знаковое смещение в днях. |
| DateTime | datetime.datetime | int | Целочисленный формат возвращает секунды epoch. |
| DateTime64 | datetime.datetime | int | Целочисленный формат возвращает ticks с точностью столбца. Python datetime ограничен микросекундами. |
| Time | datetime.timedelta | int, string, time | Целочисленный формат возвращает секунды. Формат time ограничен значениями, которые помещаются в datetime.time. |
| Time64 | datetime.timedelta | int, string, time | Целочисленный формат возвращает ticks с точностью столбца. Python timedelta ограничен микросекундами. |
| IPv4 | ipaddress.IPv4Address |
string, int | IP-адреса можно читать как строки или целые числа. |
| IPv6 | ipaddress.IPv6Address |
string | IP-адреса можно читать как строки; при правильном форматировании их можно вставлять как IP-адреса |
| Tuple | dict or tuple | tuple, dict, json | Именованные Tuple по умолчанию возвращают словари; неименованные Tuple возвращают кортежи. |
| Map | dict | - | |
| Nested | Sequence[dict] | - | |
| UUID | uuid.UUID | string | UUID можно читать как строки, отформатированные в соответствии с RFC 4122 |
| JSON | dict | string | По умолчанию возвращается словарь Python. Формат string возвращает JSON-строку |
| Variant | object | typed | typed возвращает TypedVariant(value, type_name), чтобы сохранить исходный тип элемента. |
| Dynamic | object | - | Возвращает соответствующий тип Python для типа данных ClickHouse, хранящегося в значении |
| QBit | list[float] | - | Если установлен NumPy, он автоматически используется для более быстрого транспонирования битов. |
Внешние данные
Запросы ClickHouse могут принимать внешние данные в любом поддерживаемом формате ввода. Клиент отправляет данные как часть запроса, а запрос может ссылаться на них как на временную внешнюю таблицу. См. документацию ClickHouse по внешним данным. Методы клиентских запросов принимают объект clickhouse_connect.driver.external.ExternalData через параметр external_data.
| Name | Type | Description |
|---|---|---|
| file_path | str | Путь к файлу в локальной файловой системе, из которого считываются внешние данные. Необходимо указать либо file_path, либо data |
| file_name | str | Имя внешнего "файла" данных. Если не указано, берётся из имени файла в file_path. Имя внешней таблицы — имя файла без расширения |
| data | bytes | Внешние данные в бинарном виде (вместо чтения из файла). Необходимо указать либо data, либо file_path |
| fmt | str | ClickHouse формат ввода данных. По умолчанию используется TSV |
| types | str or seq of str | Список типов данных столбцов во внешних данных. Если указана строка, типы должны быть разделены запятыми. Необходимо указать либо types, либо structure |
| structure | str or seq of str | Список пар «имя столбца + тип данных» в данных (см. примеры). Необходимо указать либо structure, либо types |
| mime_type | str | Необязательный MIME-тип данных файла. В настоящее время ClickHouse игнорирует этот HTTP-подзаголовок |
В этом примере внешний CSV-файл объединяется через JOIN с таблицей directors, хранящейся на сервере:
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_rowsДополнительные внешние файлы данных можно добавить в исходный объект ExternalData с помощью метода add_file, который принимает те же параметры, что и конструктор. При использовании HTTP все внешние данные передаются как часть загрузки файла multi-part/form-data.
backend chDB не поддерживает внешние данные.
Часовые пояса
Значения ClickHouse DateTime и DateTime64 передаются как числовые значения на основе epoch. ClickHouse Connect преобразует их в объекты Python datetime, используя метаданные столбцов, переопределения запроса и политику часовых поясов клиента.
У клиента есть два независимых параметра часового пояса:
tz_sourceзадаёт резервный часовой пояс для столбцов без явных метаданных часового пояса:"auto"используется по умолчанию. В этом режиме используется часовой пояс сервера, если клиент может надёжно определить его с учётом переходов на летнее время; в противном случае используется локальный часовой пояс."server"всегда использует часовой пояс сервера."local"всегда использует локальный часовой пояс процесса.
tz_modeуправляет учётом часового пояса:"naive_utc"используется по умолчанию. Результаты в UTC и эквивалентных UTC часовых поясах возвращаются как naive-объектыdatetimeдля обратной совместимости."aware"сохраняетtzinfoUTC и возвращает UTC-значения с информацией о часовом поясе."schema"возвращает значения с информацией о часовом поясе только в том случае, если тип столбца объявляет часовой пояс, и naive-значения для обычных столбцовDateTime/DateTime64.
Для обычных запросов с "naive_utc" и "aware" активный часовой пояс выбирается в следующем порядке:
- Переопределение
column_tzsдля отдельного столбца. - Метаданные часового пояса в типе столбца ClickHouse.
- Переопределение
query_tzдля всего запроса. - Информация о часовом поясе, возвращённая в HTTP-ответе.
- Резервный часовой пояс, выбранный через
tz_source.
tz_mode="schema" игнорирует часовые пояса запроса и резервные часовые пояса, но явное переопределение column_tzs по-прежнему имеет приоритет.
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 NoneНазвания часовых поясов обрабатываются стандартным модулем библиотеки zoneinfo. В Windows tzdata устанавливается автоматически. В минимальных Linux-образах без базы часовых поясов IANA установите clickhouse-connect[tzdata].
Результаты Pandas сохраняют естественную точность каждого типа ClickHouse, например datetime64[s] для DateTime и datetime64[ms] для DateTime64(3). Методы DataFrame на базе Arrow query_df_arrow и query_df_arrow_stream пока не поддерживают tz_mode="schema" и выдают предупреждение, если запрошен этот режим. query_arrow и query_arrow_stream возвращают метаданные часового пояса из ответа Arrow без изменений.