QueryContexts
QueryContext. QueryContext содержит ключевые структуры, используемые для построения запросов к базе данных ClickHouse, а также конфигурацию, которая используется для преобразования результата в QueryResult или другую структуру данных ответа. Сюда входят сам запрос, параметры, настройки, форматы чтения и другие свойства.
QueryContext можно получить с помощью клиентского метода create_query_context. Этот метод принимает те же параметры, что и основной метод запроса. Затем этот контекст можно передать в методы query, query_df или query_np как именованный аргумент context вместо части или всех остальных аргументов этих методов. Обратите внимание, что дополнительные аргументы, указанные при вызове метода, переопределяют любые свойства QueryContext.
Наиболее понятный сценарий использования QueryContext — отправка одного и того же запроса с разными значениями параметров привязки. Все значения параметров можно обновить, вызвав метод QueryContext.set_parameters и передав ему словарь, а любое отдельное значение — вызвав QueryContext.set_parameter с нужной парой key, value.
QueryContext не являются потокобезопасными, однако в многопоточной среде можно получить их копию, вызвав метод QueryContext.updated_copy.
Стриминг запросов
query_column_block_stream— Возвращает данные запроса блоками как последовательность столбцов с использованием собственных объектов Pythonquery_row_block_stream— Возвращает данные запроса как блок строк с использованием собственных объектов Pythonquery_rows_stream— Возвращает данные запроса как последовательность строк с использованием собственных объектов Pythonquery_np_stream— Возвращает каждый блок данных запроса ClickHouse как массив NumPyquery_df_stream— Возвращает каждый блок данных запроса ClickHouse как DataFrame Pandasquery_arrow_stream— Возвращает данные запроса в виде PyArrow RecordBlocksquery_df_arrow_stream— Возвращает каждый блок данных запроса ClickHouse как DataFrame Pandas на базе Arrow или как DataFrame Polars в зависимости от аргументаdataframe_library(по умолчанию — “pandas”).
ContextStream, который необходимо открыть с помощью оператора with, чтобы начать чтение потока.
Блоки данных
query как поток блоков, получаемых от сервер ClickHouse. Эти блоки передаются в собственном формате “Native” в ClickHouse и из ClickHouse. «Блок» — это просто последовательность столбцов бинарных данных, где каждый столбец содержит одинаковое количество значений указанного типа данных. (Поскольку ClickHouse — колоночная база данных, он хранит эти данные в похожем виде.) Размер блока, возвращаемого запросом, определяется двумя пользовательскими настройками, которые можно задавать на нескольких уровнях (профиль пользователя, пользователь, сеанс или запрос). Вот они:
- max_block_size — Ограничение на размер блока в строках. По умолчанию — 65536.
- preferred_block_size_bytes — Мягкое ограничение на размер блока в байтах. По умолчанию — 1,000,0000.
preferred_block_size_setting, каждый блок никогда не будет содержать более max_block_size строк. В зависимости от типа запроса фактически возвращаемые блоки могут быть любого размера. Например, запросы к distributed таблице, охватывающей много сегментов, могут содержать блоки меньшего размера, полученные напрямую из каждого сегмента.
При использовании одного из методов клиента query_*_stream результаты возвращаются по блокам. ClickHouse Connect загружает только один блок за раз. Это позволяет обрабатывать большие объёмы данных без необходимости загружать в память весь большой результирующий набор. Обратите внимание: приложение должно быть готово обработать любое количество блоков, а точный размер каждого блока нельзя контролировать.
HTTP-буфер данных для медленной обработки
http_buffer_size. В этой ситуации большие значения http_buffer_size допустимы, если приложению доступно достаточно памяти. Данные в буфере хранятся в сжатом виде при использовании сжатия lz4 или zstd, поэтому эти типы сжатия увеличивают общий доступный размер буфера.
StreamContexts
query_*_stream (например, query_row_block_stream) возвращает объект ClickHouse StreamContext, который сочетает в себе Python-контекст и генератор. Вот базовое использование:
StreamContext без оператора with вызовет ошибку. Использование контекста Python гарантирует, что поток (в данном случае — потоковый HTTP-ответ) будет корректно закрыт, даже если будут прочитаны не все данные и/или в ходе обработки возникнет исключение. Кроме того, StreamContext можно использовать для чтения потока только один раз. Попытка использовать StreamContext после выхода из него приведёт к ошибке StreamClosedError.
Вы можете использовать свойство source объекта StreamContext, чтобы получить доступ к родительскому объекту QueryResult, который содержит имена столбцов и типы.
Типы потоков
query_column_block_stream возвращает блок как последовательность данных столбцов в нативных типах данных Python. Если использовать приведённые выше запросы taxi_trips, возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список (или кортеж), содержащий все данные соответствующего столбца. То есть block[0] будет кортежем, содержащим только строковые значения. Форматы с ориентацией по столбцам чаще всего используются для выполнения агрегатных операций над всеми значениями в столбце, например для подсчёта общей стоимости поездок.
Метод query_row_block_stream возвращает блок как последовательность строк, как в традиционной реляционной базе данных. Для поездок на такси возвращённые данные будут представлять собой список, где каждый элемент — это ещё один список, представляющий строку данных. То есть block[0] будет содержать все поля (по порядку) для первой поездки на такси, block[1] — строку со всеми полями второй поездки на такси, и так далее. Результаты с ориентацией по строкам обычно используются для отображения или преобразования данных.
query_row_stream — это вспомогательный метод, который автоматически переходит к следующему блоку при итерации по потоку. В остальном он идентичен query_row_block_stream.
Метод query_np_stream возвращает каждый блок как двумерный массив NumPy. Внутри массивы NumPy (как правило) хранятся по столбцам, поэтому отдельные методы для строк и столбцов не нужны. «Форма» массива NumPy будет выражена как (столбцы, строки). Библиотека NumPy предоставляет множество методов для работы с массивами NumPy. Обратите внимание: если все столбцы в запросе имеют один и тот же NumPy dtype, то и возвращённый массив NumPy тоже будет иметь только один dtype, и его можно будет переупорядочивать по форме/поворачивать без фактического изменения его внутренней структуры.
Метод query_df_stream возвращает каждый блок ClickHouse как двумерный Pandas DataFrame. Ниже приведён пример, показывающий, что объект StreamContext можно использовать как контекстный менеджер в отложенном режиме (но только один раз).
query_df_arrow_stream возвращает каждый блок ClickHouse в виде DataFrame с dtype-бэкендом PyArrow. Этот метод поддерживает DataFrame как в Pandas (2.x и выше), так и в Polars через параметр dataframe_library (по умолчанию — "pandas"). На каждой итерации выдаётся DataFrame, преобразованный из record batch PyArrow, что обеспечивает более высокую производительность и более эффективное использование памяти для некоторых типов данных.
Наконец, метод query_arrow_stream возвращает результат ClickHouse в формате ArrowStream в виде pyarrow.ipc.RecordBatchStreamReader, обёрнутого в StreamContext. На каждой итерации потока возвращается PyArrow RecordBlock.
Примеры стриминга
Поток строк
Потоковая передача блоков со строками
Потоковая передача Pandas DataFrame
Потоковая передача батчей Arrow
Запросы NumPy, Pandas и Arrow
Запросы NumPy
query_np возвращает результаты запроса в виде массива NumPy, а не объекта ClickHouse Connect QueryResult.
Запросы Pandas
query_df возвращает результаты запроса в виде объекта Pandas DataFrame, а не ClickHouse Connect QueryResult.
Запросы PyArrow
query_arrow возвращает результаты запроса в виде таблицы PyArrow. Он напрямую использует формат ClickHouse Arrow, поэтому из аргументов основного метода query поддерживает только три: query, parameters и settings. Кроме того, есть дополнительный аргумент use_strings, который определяет, будут ли типы ClickHouse String в таблице Arrow представлены как строки (если True) или как байты (если False).
DataFrame на основе Arrow
DataFrame из результатов Arrow с помощью методов query_df_arrow и query_df_arrow_stream. Это тонкие обёртки над методами Arrow-запросов, которые по возможности выполняют преобразование в DataFrame без копирования:
query_df_arrow: Выполняет запрос, используя выходной формат ClickHouseArrow, и возвращаетDataFrame.- Для
dataframe_library='pandas'возвращаетDataFramepandas 2.x с типами данных на основе Arrow (pd.ArrowDtype). Для этого требуется pandas 2.x; где возможно, используются буферы без копирования, что обеспечивает высокую производительность и низкие накладные расходы по памяти. - Для
dataframe_library='polars'возвращаетDataFramePolars, созданный из таблицы Arrow (pl.from_arrow); он также работает эффективно и в зависимости от данных может не требовать копирования.
- Для
query_df_arrow_stream: Передаёт результаты потоком как последовательностьDataFrame(pandas 2.x или Polars), преобразованных из батчей потока Arrow.
Запрос к DataFrame на базе Arrow
Примечания и ограничения
- Сопоставление типов Arrow: при возврате данных в формате Arrow ClickHouse сопоставляет типы с ближайшими поддерживаемыми типами Arrow. Для некоторых типов ClickHouse нет прямого эквивалента в Arrow, поэтому они возвращаются как необработанные байты в полях Arrow (обычно
BINARYилиFIXED_SIZE_BINARY).- Примеры:
IPv4представляется как ArrowUINT32;IPv6и большие целые числа (Int128/UInt128/Int256/UInt256) часто представляются какFIXED_SIZE_BINARY/BINARYс необработанными байтами. - В таких случаях столбец DataFrame будет содержать байтовые значения из поля Arrow; интерпретация или преобразование этих байтов в соответствии с семантикой ClickHouse выполняется на стороне клиентского кода.
- Примеры:
- Неподдерживаемые типы данных Arrow (например, UUID/ENUM как полноценные типы Arrow) не выводятся; при выводе значения представляются с использованием ближайшего поддерживаемого типа Arrow (часто в виде бинарных байтов).
- Требование Pandas: типы данных на базе Arrow требуют pandas 2.x. Для более старых версий pandas используйте
query_df(без Arrow). - Строки и двоичные данные: параметр
use_strings(если он поддерживается настройкой сервераoutput_format_arrow_string_as_string) определяет, будут ли столбцы ClickHouseStringвозвращаться как строки Arrow или как двоичные данные.
Примеры преобразования типов ClickHouse/Arrow при несовпадении
FIXED_SIZE_BINARY или BINARY), преобразование этих байтов в подходящие типы Python выполняет прикладной код. Примеры ниже показывают, что некоторые преобразования удобно выполнять через API библиотеки DataFrame, тогда как в других случаях могут понадобиться чисто Python-решения, такие как struct.unpack (они уступают в производительности, но сохраняют гибкость).
Столбцы Date могут приходить как UINT16 (число дней с эпохи Unix, 1970‑01‑01). Преобразование внутри DataFrame эффективно и выполняется просто:
Int128 могут поступать в виде FIXED_SIZE_BINARY с сырыми байтами. Polars нативно поддерживает 128-битные целые числа:
dtype для 128-битных целых чисел нет, поэтому приходится использовать чистый Python — например, так:
Форматы чтения
query, query_np и query_df. (raw_query и query_arrow не изменяют данные, поступающие из ClickHouse, поэтому управление форматами к ним не применяется.) Например, если формат чтения для UUID изменён со стандартного формата native на альтернативный string, значения столбца UUID в результате запроса к ClickHouse будут возвращаться как строки (в стандартном формате RFC 1422 8-4-4-4-12), а не как объекты Python UUID.
Аргумент “тип данных” для любой функции форматирования может включать подстановочные шаблоны. Формат представляет собой одну строку в нижнем регистре.
Форматы чтения можно задавать на нескольких уровнях:
- Глобально, с помощью методов, определённых в пакете
clickhouse_connect.datatypes.format. Это будет задавать формат для настроенного типа данных во всех запросах.
- Для всего запроса — с использованием необязательного аргумента словаря
query_formats. В этом случае любой столбец (или подстолбец) указанных типов данных будет использовать заданный формат.
- Для значений в конкретном столбце — с использованием необязательного аргумента словаря
column_formats. Ключом служит имя столбца в том виде, в котором его возвращает ClickHouse, а значением — формат для столбца данных или вложенный словарь второго уровня “format”, где ключом является имя типа ClickHouse, а значением — форматы запроса. Этот вторичный словарь можно использовать для вложенных типов столбцов, таких как Tuples или Maps.
Параметры формата чтения (типы Python)
| Тип ClickHouse | Нативный тип Python | Форматы чтения | Комментарии |
|---|---|---|---|
| Int[8-64], UInt[8-32] | int | - | |
| UInt64 | int | signed | В настоящее время Superset не обрабатывает большие беззнаковые значения UInt64 |
| [U]Int[128,256] | int | string | Значения int в Pandas и NumPy ограничены 64 битами, поэтому они могут возвращаться как строки |
| BFloat16 | float | - | Все значения float в Python внутренне являются 64-битными |
| Float32 | float | - | Все значения float в Python внутренне являются 64-битными |
| Float64 | float | - | |
| Decimal | decimal.Decimal | - | |
| String | string | bytes | У столбцов String в ClickHouse нет встроенной кодировки, поэтому они также используются для двоичных данных переменной длины |
| FixedString | bytes | string | FixedString — это массивы байтов фиксированного размера, но иногда они интерпретируются как строки Python |
| Enum[8,16] | string | string, int | Перечисления Python не поддерживают пустые строки, поэтому все enum возвращаются либо как строки, либо как базовые значения int. |
| Date | datetime.date | int | ClickHouse хранит Date как количество дней с 01/01/1970. Это значение доступно как int |
| Date32 | datetime.date | int | То же, что и Date, но для более широкого диапазона дат |
| DateTime | datetime.datetime | int | ClickHouse хранит DateTime как количество секунд с начала epoch. Это значение доступно как int |
| DateTime64 | datetime.datetime | int | Точность Python datetime.datetime ограничена микросекундами. Доступно исходное 64-битное значение int |
| Time | datetime.timedelta | int, string, time | Момент времени сохраняется как Unix-временная метка. Это значение доступно как int |
| Time64 | datetime.timedelta | int, string, time | Точность Python datetime.timedelta ограничена микросекундами. Доступно исходное 64-битное значение int |
| IPv4 | ipaddress.IPv4Address | string | IP-адреса можно читать как строки, а строки в корректном формате — вставлять как IP-адреса |
| IPv6 | ipaddress.IPv6Address | string | IP-адреса можно читать как строки, а строки в корректном формате — вставлять как IP-адреса |
| Tuple | dict or tuple | tuple, json | Именованные кортежи по умолчанию возвращаются как словари. Именованные кортежи также могут возвращаться как строки JSON |
| Map | dict | - | |
| Nested | Sequence[dict] | - | |
| UUID | uuid.UUID | string | UUID можно читать как строки, отформатированные в соответствии с RFC 4122 |
| JSON | dict | string | По умолчанию возвращается словарь Python. Формат string возвращает строку JSON |
| Variant | object | - | Возвращает соответствующий тип Python для типа данных ClickHouse, в котором хранится значение |
| Dynamic | object | - | Возвращает соответствующий тип Python для типа данных ClickHouse, в котором хранится значение |
Внешние данные
query* принимают необязательный параметр external_data, позволяющий использовать эту возможность. Значением параметра external_data должен быть объект clickhouse_connect.driver.external.ExternalData. Конструктор этого объекта принимает следующие аргументы:
| Имя | Тип | Описание |
|---|---|---|
| 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-подзаголовок |
directors, уже существующей на сервере ClickHouse:
ExternalData с помощью метода add_file, который принимает те же параметры, что и конструктор. При использовании HTTP все внешние данные передаются в составе загрузки файла multi-part/form-data.
Часовые пояса
DateTime64 как число без привязки к часовому поясу, представляющее секунды с начала эпохи 1970-01-01 00:00:00 UTC. Для значений DateTime64 представление может быть в миллисекундах, микросекундах или наносекундах с начала эпохи в зависимости от precision. В результате любая информация о часовом поясе всегда применяется на стороне клиента. Обратите внимание, что это требует дополнительных вычислений, поэтому в приложениях, критичных к производительности, рекомендуется рассматривать типы DateTime как временные метки эпохи, за исключением отображения для пользователя и преобразования (например, Pandas Timestamps всегда представляют собой 64-битное целое число, обозначающее наносекунды с начала эпохи, для повышения производительности).
При использовании в запросах типов данных с учетом часового пояса — в частности, объекта Python datetime.datetime — clickhouse-connect применяет часовой пояс на стороне клиента по следующим правилам приоритета:
- Если для запроса указан parameter метода
client_tzs, применяется часовой пояс конкретного столбца - Если у столбца ClickHouse есть метаданные timezone (то есть это тип вроде DateTime64(3, ‘America/Denver’)), применяется часовой пояс столбца ClickHouse. (Обратите внимание, что эти метаданные timezone недоступны для clickhouse-connect для столбцов DateTime в версиях ClickHouse до 23.2)
- Если для запроса указан parameter метода
query_tz, применяется «часовой пояс запроса». - Если к запросу или сеансу применена настройка timezone, применяется этот часовой пояс. (Эта функциональность еще не выпущена в сервер ClickHouse)
- Наконец, если parameter клиента
apply_server_timezoneустановлен в True (по умолчанию), применяется часовой пояс сервер ClickHouse.
clickhouse-connect всегда вернет объект Python datetime.datetime без привязки к часовому поясу. При необходимости прикладной код затем может добавить к этому объекту дополнительную информацию о часовом поясе.