跳到主要内容
跳到主要内容

在 ClickHouse 中使用 Parquet

Parquet 是一种高效的文件格式,用于以列式方式存储数据。 ClickHouse 提供对读取和写入 Parquet 文件的支持。

提示

当您在查询中引用文件路径时,ClickHouse 尝试从中读取的位置将取决于您正在使用的 ClickHouse 变体。

如果您正在使用 clickhouse-local,它将从相对于您启动 ClickHouse Local 的位置读取。如果您通过 clickhouse client 使用 ClickHouse Server 或 ClickHouse Cloud,它将从相对于服务器上 /var/lib/clickhouse/user_files/ 目录的位置读取。

从 Parquet 导入

在加载数据之前,我们可以使用 file() 函数来探索 示例 parquet 文件 结构

DESCRIBE TABLE file('data.parquet', Parquet);

我们使用了 Parquet 作为第二个参数,因此 ClickHouse 知道文件格式。这将打印具有类型的列

┌─name─┬─type─────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ path │ Nullable(String) │ │ │ │ │ │
│ date │ Nullable(String) │ │ │ │ │ │
│ hits │ Nullable(Int64) │ │ │ │ │ │
└──────┴──────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘

我们还可以使用 SQL 的所有功能在实际导入数据之前探索文件

SELECT *
FROM file('data.parquet', Parquet)
LIMIT 3;
┌─path──────────────────────┬─date───────┬─hits─┐
│ Akiba_Hebrew_Academy │ 2017-08-01 │ 241 │
│ Aegithina_tiphia │ 2018-02-01 │ 34 │
│ 1971-72_Utah_Stars_season │ 2016-10-01 │ 1 │
└───────────────────────────┴────────────┴──────┘
提示

我们可以跳过 file()INFILE/OUTFILE 的显式格式设置。在这种情况下,ClickHouse 将根据文件扩展名自动检测格式。

导入到现有表

让我们创建一个表,我们将把 Parquet 数据导入到其中

CREATE TABLE sometable
(
`path` String,
`date` Date,
`hits` UInt32
)
ENGINE = MergeTree
ORDER BY (date, path);

现在我们可以使用 FROM INFILE 子句导入数据

INSERT INTO sometable
FROM INFILE 'data.parquet' FORMAT Parquet;

SELECT *
FROM sometable
LIMIT 5;
┌─path──────────────────────────┬───────date─┬─hits─┐
│ 1988_in_philosophy │ 2015-05-01 │ 70 │
│ 2004_Green_Bay_Packers_season │ 2015-05-01 │ 970 │
│ 24_hours_of_lemans │ 2015-05-01 │ 37 │
│ 25604_Karlin │ 2015-05-01 │ 20 │
│ ASCII_ART │ 2015-05-01 │ 9 │
└───────────────────────────────┴────────────┴──────┘

请注意 ClickHouse 如何自动将 Parquet 字符串(在 date 列中)转换为 Date 类型。这是因为 ClickHouse 根据目标表中的类型自动进行类型转换。

将本地文件插入到远程服务器

如果您想将本地 Parquet 文件插入到远程 ClickHouse 服务器,您可以通过将文件内容管道传输到 clickhouse-client 来完成此操作,如下所示

clickhouse client -q "INSERT INTO sometable FORMAT Parquet" < data.parquet

从 Parquet 文件创建新表

由于 ClickHouse 读取 parquet 文件 schema,我们可以动态创建表

CREATE TABLE imported_from_parquet
ENGINE = MergeTree
ORDER BY tuple() AS
SELECT *
FROM file('data.parquet', Parquet)

这将自动从给定的 parquet 文件创建和填充表

DESCRIBE TABLE imported_from_parquet;
┌─name─┬─type─────────────┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐
│ path │ Nullable(String) │ │ │ │ │ │
│ date │ Nullable(String) │ │ │ │ │ │
│ hits │ Nullable(Int64) │ │ │ │ │ │
└──────┴──────────────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘

默认情况下,ClickHouse 对列名、类型和值是严格的。但有时,我们可以跳过导入期间不存在的列或不支持的值。这可以通过 Parquet 设置 进行管理。

导出为 Parquet 格式

提示

当将 INTO OUTFILE 与 ClickHouse Cloud 一起使用时,您需要在将写入文件的机器上的 clickhouse client 中运行命令。

要将任何表或查询结果导出到 Parquet 文件,我们可以使用 INTO OUTFILE 子句

SELECT *
FROM sometable
INTO OUTFILE 'export.parquet'
FORMAT Parquet

这将在工作目录中创建 export.parquet 文件。

ClickHouse 和 Parquet 数据类型

ClickHouse 和 Parquet 数据类型大多相同,但仍然 略有不同。例如,ClickHouse 会将 DateTime 类型导出为 Parquet 的 int64。如果我们然后将其导入回 ClickHouse,我们将看到数字(time.parquet 文件

SELECT * FROM file('time.parquet', Parquet);
┌─n─┬───────time─┐
│ 0 │ 1673622611 │
│ 1 │ 1673622610 │
│ 2 │ 1673622609 │
│ 3 │ 1673622608 │
│ 4 │ 1673622607 │
└───┴────────────┘

在这种情况下,可以使用 类型转换

SELECT
n,
toDateTime(time) <--- int to time
FROM file('time.parquet', Parquet);
┌─n─┬────toDateTime(time)─┐
│ 0 │ 2023-01-13 15:10:11 │
│ 1 │ 2023-01-13 15:10:10 │
│ 2 │ 2023-01-13 15:10:09 │
│ 3 │ 2023-01-13 15:10:08 │
│ 4 │ 2023-01-13 15:10:07 │
└───┴─────────────────────┘

进一步阅读

ClickHouse 引入了对多种格式(包括文本和二进制)的支持,以涵盖各种场景和平台。在以下文章中探索更多格式以及使用它们的方法

另请查看 clickhouse-local - 一个便携式全功能工具,用于处理本地/远程文件,而无需 Clickhouse 服务器。