QueryContexts
QueryContext. Le QueryContext contient les structures clés utilisées pour construire des requêtes sur la base de données ClickHouse, ainsi que la configuration utilisée pour traiter le résultat en QueryResult ou dans une autre structure de données de réponse. Cela inclut la requête elle-même, les paramètres, les réglages, les formats de lecture et d’autres propriétés.
Un QueryContext peut être obtenu à l’aide de la méthode create_query_context du client. Cette méthode accepte les mêmes paramètres que la méthode de requête principale. Ce contexte de requête peut ensuite être transmis aux méthodes query, query_df ou query_np comme argument nommé context, à la place de tout ou partie des autres arguments de ces méthodes. Notez que les arguments supplémentaires spécifiés lors de l’appel de la méthode remplaceront toutes les propriétés du QueryContext.
Le cas d’utilisation le plus évident d’un QueryContext consiste à envoyer la même requête avec différentes valeurs de paramètres liés. Toutes les valeurs de paramètres peuvent être mises à jour en appelant la méthode QueryContext.set_parameters avec un dictionnaire, ou chaque valeur individuellement peut être mise à jour en appelant QueryContext.set_parameter avec la paire key, value souhaitée.
QueryContext ne sont pas thread-safe, mais qu’il est possible d’en obtenir une copie dans un environnement multithread en appelant la méthode QueryContext.updated_copy.
Requêtes en streaming
query_column_block_stream— renvoie les données de la requête par blocs sous forme de séquence de colonnes à l’aide d’objets Python natifsquery_row_block_stream— renvoie les données de la requête sous forme de bloc de lignes à l’aide d’objets Python natifsquery_rows_stream— renvoie les données de la requête sous forme de séquence de lignes à l’aide d’objets Python natifsquery_np_stream— renvoie chaque bloc ClickHouse de données de requête sous la forme d’un tableau NumPyquery_df_stream— renvoie chaque bloc ClickHouse de données de requête sous la forme d’un Pandas DataFramequery_arrow_stream— renvoie les données de la requête sous forme de PyArrow RecordBlocksquery_df_arrow_stream— renvoie chaque bloc ClickHouse de données de requête sous la forme d’un Pandas DataFrame basé sur Arrow ou d’un Polars DataFrame selon le kwargdataframe_library(la valeur par défaut est “pandas”).
ContextStream qui doit être ouvert dans une instruction with pour commencer à consommer le flux.
Blocs de données
query principale comme un flux de blocs reçus du serveur ClickHouse. Ces blocs sont transmis vers et depuis ClickHouse au format personnalisé « Native ». Un « bloc » est simplement une séquence de colonnes de données binaires, où chaque colonne contient le même nombre de valeurs du type de données spécifié. (En tant que base de données columnaire, ClickHouse stocke ces données sous une forme similaire.) La taille d’un bloc renvoyé par une requête dépend de deux paramètres utilisateur qui peuvent être définis à plusieurs niveaux (profil, utilisateur, session ou requête). Il s’agit de :
- max_block_size — Limite de la taille du bloc en lignes. Valeur par défaut : 65536.
- preferred_block_size_bytes — Limite souple de la taille du bloc en octets. Valeur par défaut : 1,000,0000.
preferred_block_size_setting, chaque bloc ne dépassera jamais max_block_size lignes. Selon le type de requête, les blocs réellement renvoyés peuvent être de taille quelconque. Par exemple, les requêtes sur une table distribuée couvrant de nombreux shards peuvent contenir des blocs plus petits récupérés directement depuis chaque shard.
Lors de l’utilisation de l’une des méthodes query_*_stream du Client, les résultats sont renvoyés bloc par bloc. ClickHouse Connect ne charge qu’un seul bloc à la fois. Cela permet de traiter de grands volumes de données sans devoir charger en mémoire l’ensemble d’un jeu de résultats volumineux. Notez que l’application doit être prête à traiter un nombre quelconque de blocs et que la taille exacte de chaque bloc ne peut pas être contrôlée.
Buffer de données HTTP pour un traitement lent
http_buffer_size. Des valeurs élevées de http_buffer_size conviennent dans cette situation si l’application dispose de suffisamment de mémoire. Les données du buffer sont stockées sous forme compressée lors de l’utilisation de la compression lz4 ou zstd ; l’utilisation de ces types de compression augmente donc la capacité globale du buffer disponible.
StreamContexts
query_*_stream (comme query_row_block_stream) renvoie un objet ClickHouse StreamContext, qui combine un contexte Python et un générateur. Voici l’usage de base :
with provoquera une erreur. L’utilisation d’un contexte Python garantit que le flux (dans ce cas, une réponse HTTP en streaming) sera correctement fermé, même si toutes les données ne sont pas consommées et/ou si une exception est levée pendant le traitement. De plus, les StreamContext ne peuvent être utilisés qu’une seule fois pour consommer le flux. Essayer d’utiliser un StreamContext après sa sortie du contexte produira une StreamClosedError.
Vous pouvez utiliser la propriété source du StreamContext pour accéder à l’objet parent QueryResult, qui inclut les noms de colonnes et les types.
Types de flux
query_column_block_stream renvoie le bloc sous la forme d’une séquence de données de colonnes stockées dans des types de données Python natifs. Avec les requêtes taxi_trips ci-dessus, les données renvoyées seront une liste dont chaque élément est une autre liste (ou un tuple) contenant toutes les données de la colonne correspondante. Ainsi, block[0] serait un tuple ne contenant que des chaînes de caractères. Les formats orientés colonnes sont surtout utilisés pour effectuer des opérations d’agrégation sur toutes les valeurs d’une colonne, comme additionner le total des tarifs.
La méthode query_row_block_stream renvoie le bloc sous la forme d’une séquence de lignes, comme dans une base de données relationnelle traditionnelle. Pour les trajets en taxi, les données renvoyées seront une liste dont chaque élément est une autre liste représentant une ligne de données. Ainsi, block[0] contiendrait tous les champs (dans l’ordre) du premier trajet en taxi, block[1] contiendrait tous les champs du deuxième trajet en taxi, et ainsi de suite. Les résultats orientés lignes sont généralement utilisés pour l’affichage ou les traitements de transformation.
query_row_stream est une méthode utilitaire qui passe automatiquement au bloc suivant lors de l’itération sur le flux. À part cela, elle est identique à query_row_block_stream.
La méthode query_np_stream renvoie chaque bloc sous la forme d’un Array NumPy à deux dimensions. En interne, les Arrays NumPy sont (généralement) stockés sous forme de colonnes ; il n’est donc pas nécessaire de disposer de méthodes distinctes pour les lignes et les colonnes. La “shape” du Array NumPy sera exprimée sous la forme (colonnes, lignes). La bibliothèque NumPy fournit de nombreuses méthodes pour manipuler les Arrays NumPy. Notez que si toutes les colonnes de la requête partagent le même Dtype NumPy, le Array NumPy renvoyé n’aura lui aussi qu’un seul Dtype et pourra être redimensionné ou pivoté sans modifier réellement sa structure interne.
La méthode query_df_stream renvoie chaque bloc ClickHouse sous la forme d’un Pandas DataFrame à deux dimensions. Voici un exemple montrant que l’objet StreamContext peut être utilisé comme contexte de manière différée (mais une seule fois).
query_df_arrow_stream renvoie chaque bloc ClickHouse sous forme de DataFrame avec le backend Dtype de PyArrow. Cette méthode prend en charge les DataFrames Pandas (2.x ou version ultérieure) et Polars via le paramètre dataframe_library (par défaut, "pandas"). À chaque itération, elle produit un DataFrame converti à partir de record batches PyArrow, ce qui offre de meilleures performances et une meilleure efficacité mémoire pour certains types de données.
Enfin, la méthode query_arrow_stream renvoie un résultat ClickHouse au format ArrowStream sous la forme d’un pyarrow.ipc.RecordBatchStreamReader encapsulé dans StreamContext. Chaque itération du flux renvoie un RecordBlock PyArrow.
Exemples en streaming
Lignes en continu
Diffuser des blocs de lignes en continu
Transmettre des DataFrames Pandas en flux
Transmettre des lots Arrow en continu
Requêtes NumPy, Pandas et Arrow
Requêtes NumPy
query_np renvoie les résultats de la requête sous forme de tableau NumPy au lieu d’un QueryResult de ClickHouse Connect.
Requêtes avec Pandas
query_df renvoie le résultat de la requête sous la forme d’un Pandas DataFrame plutôt que d’un QueryResult ClickHouse Connect.
Requêtes PyArrow
query_arrow renvoie le résultat de la requête sous forme de table PyArrow. Comme elle s’appuie directement sur le format Arrow de ClickHouse, elle n’accepte que trois arguments communs avec la méthode principale query : query, parameters et settings. Elle accepte en outre un argument supplémentaire, use_strings, qui détermine si la table Arrow représentera les types String de ClickHouse sous forme de chaînes (si True) ou d’octets (si False).
DataFrames adossés à Arrow
query_df_arrow et query_df_arrow_stream. Il s’agit de wrappers légers autour des méthodes de requête Arrow, avec conversion sans copie vers des DataFrames lorsque cela est possible :
query_df_arrow: exécute la requête en utilisant le format de sortie ClickHouseArrowet renvoie un DataFrame.- Pour
dataframe_library='pandas', renvoie un DataFrame pandas 2.x utilisant des Dtype adossés à Arrow (pd.ArrowDtype). Cela nécessite pandas 2.x et exploite des buffers sans copie lorsque cela est possible, pour d’excellentes performances et un faible surcoût mémoire. - Pour
dataframe_library='polars', renvoie un DataFrame Polars créé à partir de l’Arrow Table (pl.from_arrow), avec une efficacité comparable et, selon les données, sans copie.
- Pour
query_df_arrow_stream: diffuse les résultats sous forme d’une séquence de DataFrames (pandas 2.x ou Polars) convertis à partir de batches de flux Arrow.
Requête vers un DataFrame adossé à Arrow
Remarques et points de vigilance
- Correspondance des types Arrow : lors du renvoi de données au format Arrow, ClickHouse associe les types aux types Arrow pris en charge les plus proches. Certains types ClickHouse n’ont pas d’équivalent Arrow natif et sont renvoyés sous forme d’octets bruts dans des champs Arrow (généralement
BINARYouFIXED_SIZE_BINARY).- Exemples :
IPv4est représenté par ArrowUINT32;IPv6et les grands entiers (Int128/UInt128/Int256/UInt256) sont souvent représentés sous la formeFIXED_SIZE_BINARY/BINARY, avec des octets bruts. - Dans ces cas, la colonne du DataFrame contient des valeurs d’octets associées au champ Arrow ; c’est au code client d’interpréter/convertir ces octets conformément à la sémantique de ClickHouse.
- Exemples :
- Les data types Arrow non pris en charge (par exemple, UUID/ENUM en tant que véritables types Arrow) ne sont pas émis ; pour la sortie, les valeurs sont représentées à l’aide du type Arrow pris en charge le plus proche (souvent sous forme d’octets binaires).
- Prérequis Pandas : les
dtypesadossés à Arrow nécessitent pandas 2.x. Pour les anciennes versions de pandas, utilisez plutôtquery_df(sans Arrow). - Chaînes vs binaire : l’option
use_strings(lorsqu’elle est prise en charge par le server settingoutput_format_arrow_string_as_string) détermine si les colonnes ClickHouseStringsont renvoyées comme chaînes Arrow ou comme données binaires.
Exemples de conversion entre types ClickHouse/Arrow incompatibles
FIXED_SIZE_BINARY ou BINARY), c’est au code de l’application de convertir ces octets dans les types Python appropriés. Les exemples ci-dessous montrent que certaines conversions peuvent être effectuées à l’aide des API des bibliothèques de DataFrame, tandis que d’autres peuvent nécessiter des approches en Python pur, comme struct.unpack (au prix de performances moindres, mais avec davantage de flexibilité).
Les colonnes Date peuvent être renvoyées en UINT16 (nombre de jours depuis l’époque Unix, 1970‑01‑01). La conversion dans le DataFrame est efficace et simple :
Int128 peuvent être reçues sous forme de FIXED_SIZE_BINARY avec des octets bruts. Polars prend en charge nativement les entiers sur 128 bits :
dtype entier public sur 128 bits. Nous devons donc recourir à du Python pur et pouvons faire quelque chose comme :
Formats de lecture
query, query_np et query_df du client. (raw_query et query_arrow ne modifient pas les données reçues de ClickHouse ; le contrôle du format ne s’y applique donc pas.) Par exemple, si le format de lecture d’un UUID passe du format native par défaut au format alternatif string, les valeurs d’une colonne UUID renvoyées par une requête ClickHouse seront des chaînes (au format RFC 1422 standard 8-4-4-4-12) au lieu d’objets UUID Python.
L’argument « data type » de toute fonction de formatage peut inclure des caractères génériques. Le format est une chaîne unique en minuscules.
Les formats de lecture peuvent être définis à plusieurs niveaux :
- Globalement, à l’aide des méthodes définies dans le paquet
clickhouse_connect.datatypes.format. Cela contrôle le format du type de données configuré pour toutes les requêtes.
- Pour l’ensemble d’une requête, en utilisant l’argument de dictionnaire facultatif
query_formats. Dans ce cas, toute colonne (ou sous-colonne) des types de données spécifiés utilisera le format configuré.
- Pour les valeurs d’une colonne spécifique, à l’aide de l’argument dictionnaire facultatif
column_formats. La clé correspond au nom de colonne tel que renvoyé par ClickHouse, et la valeur correspond soit au format de la colonne de données, soit à un dictionnaire de second niveau “format” contenant un nom de type ClickHouse et une valeur de formats de requête. Ce dictionnaire secondaire peut être utilisé pour des types de colonnes imbriqués tels que les Tuples ou les Maps.
Options du format de lecture (types Python)
Données externes
query* du client acceptent un paramètre facultatif external_data pour tirer parti de cette fonctionnalité. La valeur du paramètre external_data doit être un objet clickhouse_connect.driver.external.ExternalData. Le constructeur de cet objet accepte les arguments suivants :
Pour envoyer une requête avec un fichier CSV externe contenant des données sur des « films » et combiner ces données avec une table
directors déjà présente sur le serveur ClickHouse :
ExternalData initial à l’aide de la méthode add_file, qui prend les mêmes paramètres que le constructeur. En HTTP, toutes les données externes sont transmises dans le cadre d’un téléversement de fichier multi-part/form-data.
Fuseaux horaires
DateTime64 sous la forme d’un nombre dépourvu d’information de fuseau horaire, représentant le nombre de secondes écoulées depuis l’epoch, soit 1970-01-01 00:00:00 UTC. Pour les valeurs DateTime64, cette représentation peut être en millisecondes, microsecondes ou nanosecondes depuis l’epoch, selon la précision. Par conséquent, toute information de fuseau horaire est toujours appliquée côté client. Notez que cela implique un surcroît de calcul non négligeable ; dans les applications où les performances sont critiques, il est donc recommandé de traiter les types DateTime comme des timestamps epoch, sauf pour l’affichage à l’utilisateur et les conversions (par exemple, les timestamps Pandas sont toujours des entiers 64 bits représentant des nanosecondes depuis l’epoch afin d’améliorer les performances).
Lors de l’utilisation, dans les requêtes, de types de données tenant compte du fuseau horaire — en particulier l’objet Python datetime.datetime — clickhouse-connect applique un fuseau horaire côté client selon les règles de préséance suivantes :
- Si le paramètre de méthode de requête
client_tzsest spécifié pour la requête, le fuseau horaire de la colonne concernée est appliqué - Si la colonne ClickHouse possède des métadonnées de fuseau horaire (c’est-à-dire si son type est, par exemple, DateTime64(3, ‘America/Denver’)), le fuseau horaire de la colonne ClickHouse est appliqué. (Notez que ces métadonnées de fuseau horaire ne sont pas disponibles pour clickhouse-connect pour les colonnes DateTime avant la version 23.2 de ClickHouse)
- Si le paramètre de méthode de requête
query_tzest spécifié pour la requête, le « fuseau horaire de la requête » est appliqué. - Si un paramètre de fuseau horaire est appliqué à la requête ou à la session, ce fuseau horaire est appliqué. (Cette fonctionnalité n’est pas encore disponible dans le serveur ClickHouse)
- Enfin, si le paramètre client
apply_server_timezonea été défini sur True (valeur par défaut), le fuseau horaire du serveur ClickHouse est appliqué.
clickhouse-connect renverra toujours un objet Python datetime.datetime sans fuseau horaire. Des informations de fuseau horaire supplémentaires peuvent ensuite être ajoutées à cet objet par le code de l’application si nécessaire.