QueryContexts
QueryContext 내에서 실행합니다. QueryContext에는 ClickHouse 데이터베이스에 대해 쿼리를 구성하는 데 사용되는 핵심 데이터 구조와, 결과를 QueryResult 또는 다른 응답 데이터 구조로 처리하는 데 사용되는 구성이 포함됩니다. 여기에는 쿼리 자체, 매개변수, 설정, 읽기 포맷, 기타 속성이 포함됩니다.
QueryContext는 클라이언트의 create_query_context 메서드를 사용해 생성할 수 있습니다. 이 메서드는 핵심 쿼리 메서드와 동일한 매개변수를 받습니다. 이렇게 생성한 쿼리 컨텍스트는 query, query_df, query_np 메서드에 context 키워드 인수로 전달할 수 있으며, 이때 해당 메서드의 다른 인수 일부 또는 전체를 대체할 수 있습니다. 메서드 호출 시 추가로 지정한 인수는 QueryContext의 속성을 재정의합니다.
QueryContext의 가장 명확한 사용 사례는 바인딩 매개변수 값만 바꿔 같은 쿼리를 보내는 것입니다. 모든 매개변수 값은 딕셔너리를 사용해 QueryContext.set_parameters 메서드를 호출하여 업데이트할 수 있으며, 개별 값은 원하는 key, value 쌍과 함께 QueryContext.set_parameter를 호출하여 업데이트할 수 있습니다.
QueryContext는 스레드 안전하지 않으므로, 멀티스레드 환경에서는 QueryContext.updated_copy 메서드를 호출해 복사본을 얻을 수 있다는 점에 유의하십시오.
스트리밍 쿼리
query_column_block_stream— 네이티브 Python 객체를 사용해 쿼리 데이터를 컬럼 시퀀스 형태의 블록으로 반환합니다query_row_block_stream— 네이티브 Python 객체를 사용해 쿼리 데이터를 행 블록으로 반환합니다query_rows_stream— 네이티브 Python 객체를 사용해 쿼리 데이터를 행 시퀀스로 반환합니다query_np_stream— 쿼리 데이터의 각 ClickHouse 블록을 NumPy 배열로 반환합니다query_df_stream— 쿼리 데이터의 각 ClickHouse 블록을 Pandas DataFrame으로 반환합니다query_arrow_stream— 쿼리 데이터를 PyArrow RecordBlocks로 반환합니다query_df_arrow_stream— kwargdataframe_library에 따라 쿼리 데이터의 각 ClickHouse 블록을 Arrow 기반 Pandas DataFrame 또는 Polars DataFrame으로 반환합니다(기본값은 “pandas”입니다).
ContextStream 객체를 반환하며, 스트림 소비를 시작하려면 with 문으로 열어야 합니다.
데이터 블록
query 메서드의 모든 데이터를 ClickHouse 서버에서 수신한 블록 스트림으로 처리합니다. 이러한 블록은 ClickHouse와 주고받을 때 사용자 정의 “Native” 포맷으로 전송됩니다. “블록”은 바이너리 데이터 컬럼의 시퀀스이며, 각 컬럼에는 지정된 데이터 타입의 값이 동일한 개수로 들어 있습니다. (컬럼형 데이터베이스인 ClickHouse는 이 데이터를 유사한 형태로 저장합니다.) 쿼리에서 반환되는 블록 크기는 여러 수준(사용자 프로필, 사용자, 세션 또는 쿼리)에서 설정할 수 있는 두 가지 사용자 설정에 따라 결정됩니다. 다음과 같습니다.
- max_block_size — 행 수 기준 블록 크기 제한입니다. 기본값은 65536입니다.
- preferred_block_size_bytes — 바이트 기준 블록 크기의 소프트 리밋입니다. 기본값은 1,000,0000입니다.
preferred_block_size_setting과 관계없이 각 블록은 max_block_size행을 절대 초과하지 않습니다. 쿼리 유형에 따라 실제로 반환되는 블록 크기는 얼마든지 달라질 수 있습니다. 예를 들어, 많은 세그먼트에 걸쳐 있는 분산 테이블에 대한 쿼리는 각 세그먼트에서 직접 가져온 더 작은 블록을 포함할 수 있습니다.
Client query_*_stream 메서드 중 하나를 사용하면 결과가 블록 단위로 반환됩니다. ClickHouse Connect는 한 번에 하나의 블록만 로드합니다. 따라서 큰 result set 전체를 메모리에 로드하지 않고도 대량의 데이터를 처리할 수 있습니다. 애플리케이션은 블록 수에 관계없이 처리할 수 있도록 준비되어 있어야 하며, 각 블록의 정확한 크기는 제어할 수 없다는 점에 유의하십시오.
느린 처리 시 HTTP 데이터 버퍼
http_buffer_size 설정을 사용해 HTTP streaming 버퍼 크기(기본값은 10MB)를 늘려 어느 정도 완화할 수 있습니다. 애플리케이션에서 사용할 수 있는 메모리가 충분하다면 이 경우 http_buffer_size 값을 크게 설정해도 괜찮습니다. lz4 또는 zstd compression을 사용하는 경우 버퍼의 데이터는 압축된 상태로 저장되므로, 이러한 compression 유형을 사용하면 전체적으로 사용 가능한 버퍼 용량이 증가합니다.
StreamContexts
query_*_stream 메서드(예: query_row_block_stream)는 각각 Python 컨텍스트와 제너레이터가 결합된 ClickHouse StreamContext 객체를 반환합니다. 기본 사용법은 다음과 같습니다.
with 문과 함께 사용하지 않고 StreamContext를 사용하려고 하면 오류가 발생한다는 점에 유의하십시오. Python 컨텍스트를 사용하면 스트림(이 경우 스트리밍 HTTP 응답)이 모든 데이터가 소비되지 않거나 처리 중 예외가 발생하더라도 올바르게 닫히도록 보장됩니다. 또한 StreamContext는 스트림 소비에 한 번만 사용할 수 있습니다. StreamContext가 종료된 후 다시 사용하려고 하면 StreamClosedError가 발생합니다.
StreamContext의 source 속성을 사용하면 상위 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 메서드는 각 블록을 2차원 NumPy 배열로 반환합니다. 내부적으로 NumPy 배열은 (일반적으로) 컬럼 단위로 저장되므로, 별도의 행 또는 컬럼 메서드가 필요하지 않습니다. NumPy 배열의 “shape”는 (컬럼, 행)으로 표현됩니다. NumPy 라이브러리는 NumPy 배열을 조작하는 다양한 메서드를 제공합니다. 쿼리의 모든 컬럼이 동일한 NumPy dtype을 공유하면, 반환되는 NumPy 배열도 하나의 dtype만 가지며 내부 구조를 실제로 변경하지 않고도 재구성하거나 회전할 수 있습니다.
query_df_stream 메서드는 각 ClickHouse Block을 2차원 Pandas DataFrame으로 반환합니다. 다음은 StreamContext 객체를 지연된 방식으로 컨텍스트로 사용할 수 있음을 보여주는 예시입니다(단, 한 번만 사용할 수 있습니다).
query_df_arrow_stream 메서드는 각 ClickHouse Block을 PyArrow dtype backend를 사용하는 DataFrame으로 반환합니다. 이 메서드는 dataframe_library 매개변수를 통해 Pandas(2.x 이상)와 Polars DataFrame을 모두 지원하며, 기본값은 "pandas"입니다. 각 반복에서는 PyArrow record batch에서 변환된 DataFrame을 반환하므로, 특정 데이터 타입에서 더 나은 성능과 메모리 효율성을 제공합니다.
마지막으로, query_arrow_stream 메서드는 ClickHouse ArrowStream 포맷의 결과를 StreamContext로 래핑된 pyarrow.ipc.RecordBatchStreamReader로 반환합니다. 스트림의 각 반복에서는 PyArrow RecordBlock을 반환합니다.
스트리밍 예시
행 단위로 스트리밍
행 블록 스트리밍하기
Pandas DataFrames 스트리밍
Arrow 배치 스트리밍
NumPy, Pandas, and Arrow 쿼리
NumPy 쿼리
query_np 메서드는 쿼리 결과를 ClickHouse Connect QueryResult 대신 NumPy 배열로 반환합니다.
Pandas 쿼리
query_df 메서드는 쿼리 결과를 ClickHouse Connect의 QueryResult가 아니라 Pandas DataFrame으로 반환합니다.
PyArrow 쿼리
query_arrow 메서드는 쿼리 결과를 PyArrow Table로 반환합니다. 이 메서드는 ClickHouse Arrow 포맷을 직접 사용하므로, 기본 query 메서드와 공통으로 사용하는 인수는 query, parameters, settings 3개뿐입니다. 여기에 추가 인수 use_strings도 있으며, 이 인수는 Arrow Table에서 ClickHouse String 타입을 문자열로 표시할지(True인 경우), 아니면 바이트로 표시할지(False인 경우)를 결정합니다.
Arrow 기반 DataFrames
query_df_arrow 및 query_df_arrow_stream 메서드를 통해 Arrow 결과로부터 빠르고 메모리 효율적인 DataFrame 생성을 지원합니다. 이 메서드들은 Arrow 쿼리 메서드를 얇게 감싼 래퍼로, 가능한 경우 DataFrame으로 zero-copy 변환을 수행합니다:
query_df_arrow: ClickHouseArrow출력 형식을 사용해 쿼리를 실행하고 DataFrame을 반환합니다.dataframe_library='pandas'의 경우, Arrow 기반 dtype(pd.ArrowDtype)을 사용하는 pandas 2.x DataFrame을 반환합니다. 이를 사용하려면 pandas 2.x가 필요하며, 가능한 경우 zero-copy 버퍼를 활용해 뛰어난 성능과 낮은 메모리 오버헤드를 제공합니다.dataframe_library='polars'의 경우, Arrow 테이블(pl.from_arrow)로부터 생성된 Polars DataFrame을 반환합니다. 이 또한 효율적이며, 데이터에 따라 zero-copy가 가능할 수 있습니다.
query_df_arrow_stream: Arrow 스트림 배치에서 변환된 DataFrame(pandas 2.x 또는 Polars) 시퀀스로 결과를 스트리밍합니다.
쿼리를 Arrow 기반 DataFrame으로 변환
참고 사항 및 유의점
- 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 기반 dtype을 사용하려면 pandas 2.x가 필요합니다. 이전 pandas 버전에서는 대신
query_df(비 Arrow)를 사용하십시오. - 문자열과 바이너리:
use_strings옵션은 (output_format_arrow_string_as_string서버 설정이 지원되는 경우) ClickHouseString컬럼을 Arrow 문자열로 반환할지, 바이너리로 반환할지를 제어합니다.
ClickHouse/Arrow 타입 변환 불일치 예시
FIXED_SIZE_BINARY 또는 BINARY)로 반환하는 경우, 이 바이트를 적절한 Python 타입으로 변환하는 작업은 애플리케이션 코드의 책임입니다. 아래 예시에서는 일부 변환은 DataFrame 라이브러리 API로 처리할 수 있지만, 다른 변환은 struct.unpack 같은 순수 Python 방식이 필요할 수 있음을 보여줍니다(이 경우 성능은 떨어질 수 있지만 유연성은 유지됩니다).
Date 컬럼은 UINT16(Unix epoch인 1970‑01‑01부터 경과한 일수)로 전달될 수 있습니다. DataFrame 내부에서 변환하는 방법은 효율적이고 간단합니다:
Int128과 같은 컬럼은 원시 바이트 형태의 FIXED_SIZE_BINARY로 들어올 수 있습니다. Polars는 128비트 정수를 네이티브로 지원합니다:
읽기 포맷
query, query_np, query_df 메서드에서 반환되는 값의 데이터 타입을 제어합니다. (raw_query 및 query_arrow는 ClickHouse에서 들어오는 데이터를 변환하지 않으므로 포맷 제어가 적용되지 않습니다.) 예를 들어 UUID의 읽기 포맷을 기본 native 포맷에서 대체 string 포맷으로 변경하면, UUID 컬럼에 대한 ClickHouse 쿼리 결과는 Python UUID 객체 대신 문자열 값(표준 8-4-4-4-12 RFC 1422 포맷 사용)으로 반환됩니다.
모든 포맷 함수의 “data type” 인수에는 와일드카드를 포함할 수 있습니다. 포맷은 소문자로 된 단일 문자열입니다.
읽기 포맷은 여러 수준에서 설정할 수 있습니다:
clickhouse_connect.datatypes.format패키지에 정의된 메서드를 사용해 전역적으로 설정할 수 있습니다. 이렇게 하면 모든 쿼리에서 구성된 데이터 타입의 포맷이 제어됩니다.
- 전체 쿼리에는 선택적
query_formats딕셔너리 인수를 사용할 수 있습니다. 이 경우 지정한 데이터 타입의 모든 컬럼(또는 하위 컬럼)에 구성된 포맷이 적용됩니다.
- 선택적
column_formats딕셔너리 인수를 사용하면 특정 컬럼의 값에 포맷을 지정할 수 있습니다. 키는 ClickHouse가 반환하는 컬럼 이름이며, 값은 데이터 컬럼에 적용할 포맷이거나 ClickHouse 타입 이름을 키로, 쿼리 포맷을 값으로 갖는 2단계format딕셔너리입니다. 이 보조 딕셔너리는 튜플이나 맵 같은 중첩 컬럼 타입에 사용할 수 있습니다.
읽기 포맷 옵션(Python 타입)
| ClickHouse Type | 네이티브 Python 타입 | 읽기 포맷 | 설명 |
|---|---|---|---|
| Int[8-64], UInt[8-32] | int | - | |
| UInt64 | int | signed | Superset는 현재 큰 unsigned UInt64 값을 처리하지 못합니다 |
| [U]Int[128,256] | int | string | Pandas와 NumPy의 int 값은 최대 64비트까지이므로, 이러한 값은 문자열로 반환될 수 있습니다 |
| BFloat16 | float | - | 모든 Python float는 내부적으로 64비트입니다 |
| Float32 | float | - | 모든 Python float는 내부적으로 64비트입니다 |
| Float64 | float | - | |
| Decimal | decimal.Decimal | - | |
| String | string | bytes | ClickHouse String 컬럼에는 고유한 인코딩이 없으므로, 가변 길이 바이너리 데이터에도 사용됩니다 |
| FixedString | bytes | string | FixedString은 고정 크기 바이트 배열이지만, 경우에 따라 Python 문자열로도 처리됩니다 |
| Enum[8,16] | string | string, int | Python enum은 빈 문자열을 허용하지 않으므로, 모든 enum은 문자열 또는 기반 int 값으로 렌더링됩니다. |
| Date | datetime.date | int | ClickHouse는 Date를 1970/01/01부터 경과한 일수로 저장합니다. 이 값은 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 timestamp로 저장됩니다. 이 값은 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 | 이름이 지정된 Tuple은 기본적으로 딕셔너리로 반환됩니다. 이름이 지정된 Tuple은 JSON 문자열로도 반환될 수 있습니다 |
| Map | dict | - | |
| Nested | Sequence[dict] | - | |
| UUID | uuid.UUID | string | UUID는 RFC 4122 형식의 문자열로 읽을 수 있습니다 |
| JSON | dict | string | 기본적으로 Python 딕셔너리가 반환됩니다. string 포맷은 JSON 문자열을 반환합니다 |
| Variant | object | - | 값에 저장된 ClickHouse 데이터 타입에 해당하는 Python 타입을 반환합니다 |
| Dynamic | object | - | 값에 저장된 ClickHouse 데이터 타입에 해당하는 Python 타입을 반환합니다 |
외부 데이터
query* 메서드는 이 기능을 활용할 수 있도록 선택적 external_data 매개변수를 받습니다. external_data 매개변수의 값은 clickhouse_connect.driver.external.ExternalData 객체여야 합니다. 이 객체의 생성자는 다음 인수를 받습니다.
| Name | Type | Description |
|---|---|---|
| file_path | str | 외부 데이터를 읽어올 로컬 시스템의 파일 경로입니다. file_path 또는 data 중 하나는 필수입니다 |
| file_name | str | 외부 데이터 “file”의 이름입니다. 지정하지 않으면 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 테이블과 결합하려면 다음과 같이 하십시오:
add_file 메서드를 사용해 초기 ExternalData 객체에 추가할 수 있습니다. HTTP에서는 모든 외부 데이터가 multi-part/form-data 파일 업로드의 일부로 전송됩니다.
시간대
DateTime64 객체를 항상 시간대 정보가 없는 숫자로 저장하며, 이 숫자는 epoch인 1970-01-01 00:00:00 UTC를 기준으로 경과한 초를 나타냅니다. DateTime64 값은 정밀도에 따라 epoch 이후의 밀리초, 마이크로초 또는 나노초로 표현될 수 있습니다. 따라서 시간대 정보는 항상 클라이언트 측에서 적용됩니다. 이 과정에는 무시할 수 없는 추가 계산이 수반되므로, 성능이 중요한 애플리케이션에서는 사용자 표시 및 변환을 제외하고 DateTime 타입을 epoch 타임스탬프로 처리하는 것이 좋습니다(예를 들어 Pandas Timestamp는 성능 향상을 위해 항상 epoch 나노초를 나타내는 64비트 정수입니다).
쿼리에서 시간대 정보를 포함하는 데이터 타입, 특히 Python datetime.datetime 객체를 사용할 때 clickhouse-connect는 다음 우선순위 규칙에 따라 클라이언트 측 시간대를 적용합니다.
- 쿼리 메서드 매개변수
client_tzs가 지정된 경우, 해당 컬럼별 시간대가 적용됩니다 - ClickHouse 컬럼에 시간대 메타데이터가 있는 경우(예: DateTime64(3, ‘America/Denver’) 타입), ClickHouse 컬럼의 시간대가 적용됩니다. (단, DateTime 컬럼의 경우 ClickHouse 23.2 이전 버전에서는 이 시간대 메타데이터를 clickhouse-connect에서 사용할 수 없습니다)
- 쿼리 메서드 매개변수
query_tz가 지정된 경우, “쿼리 시간대”가 적용됩니다. - 쿼리 또는 세션에 시간대 설정이 적용된 경우, 해당 시간대가 적용됩니다. (이 기능은 아직 ClickHouse 서버에 릴리스되지 않았습니다)
- 마지막으로, 클라이언트
apply_server_timezone매개변수가 True로 설정되어 있으면(기본값), ClickHouse 서버 시간대가 적용됩니다.
clickhouse-connect는 항상 시간대 정보가 없는 Python datetime.datetime 객체를 반환합니다. 필요한 경우 이후 애플리케이션 코드에서 이 시간대 정보 없는 객체에 추가 시간대 정보를 적용할 수 있습니다.