欢迎,chDB。
在 ClickHouse,我们经常谈论社区和开源。在这种对话中,我们坚信,有时最酷、最令人兴奋的想法来自我们的社区。因此,我们开始在每月的 ClickHouse 社区电话会议上重点介绍社区正在创造的一些令人惊叹的事物。
本月,我们有机会重点介绍 chDB。
chDB 由 ClickHouse 社区贡献者 Auxten 和 Lorenzo Mangani 开发,并在 社区的帮助下完成,是一个由 ClickHouse 驱动的嵌入式 SQL OLAP 引擎。更简单地说,这使得 ClickHouse 引擎可以作为“开箱即用”的 Python 模块使用,允许用户直接在他们的代码中利用 ClickHouse 的全部功能和性能。
这种数据库交互模型已显示在数据科学家和数据工程师中越来越受欢迎,DuckDB 等项目近年来也越来越受欢迎。虽然 ClickHouse 是一个成熟的 OLAP 数据库,用于实时分析,能够在托管 PB 级数据的多节点架构中运行,并且仍然提供亚秒级查询响应时间,但我们也意识到,许多分析是在用户笔记本电脑和工作站上执行的 - 尤其是对于较小的数据集。这些数据交互在许多项目阶段都很典型,无论是早期数据探索、一次性 ETL 任务、开发和测试,还是对需要 SQL 但不需要服务器强大功能的小型数据集的简单问题。对于这些任务,Python 通常是首选语言,chDB 提供了first-class集成,并允许用户从他们的代码中利用 ClickHouse。
为什么要嵌入 ClickHouse?
在一段时间内,ClickHouse 提供了 clickhouse-local。这提供了一个本地可执行的二进制文件,用户可以使用 ClickHouse 的全部功能查询本地和远程文件(例如,S3)。clickhouse-local 同时提供完整的客户端控制台和通过 stdout 传递查询和响应以集成到脚本的方法,解决了上述常见的 ad hoc 数据任务,并避免了用户部署完整服务器的需求。我们将继续投资 clickhouse-local,它受益于与服务器相同的核心代码,并且特别受益于最近的改进,例如更快的 Parquet 查询。
虽然 clickhouse-local 已被证明非常受欢迎,并且在简单的 SQL 查询足够时尤其强大,但我们也理解 Python 无处不在,并且通常是数据任务的首选工具。例如,用户经常需要将 SQL 集成到他们更广泛的逻辑中 - 尤其是 Python 是训练和调用机器学习模型的最流行手段。chDB 解决了这个问题,允许用户将 ClickHouse 与标准数据操作和分析库(如 Pandas)一起使用。
最先引起我们注意的事情之一是 chDB 如何应对将 ClickHouse 作为 Python 模块提供的挑战:如何 对我们来说与 为什么 同等重要。一个幼稚的实现可能直接在 Python 包中包含 clickhouse-local 二进制文件,并通过类似 popen
的方法通过 stdin 和 stdout 传递查询和响应。这种管道方法虽然可能简单且足以用于一次性脚本,但有几个缺点,例如
- 为每个查询启动一个独立的进程会略微影响性能,查询时间会增加大约 10..50 毫秒。
- SQL 查询结果的多个副本是不可避免的。
- 与 Python 的集成是有限的,这使得实现 Python UDF 和支持 Pandas DataFrame 上的 SQL 变得困难。
对团队来说最重要的是,它缺乏优雅性 ????
该团队花费了大量时间(以及他的农历新年)来实现稳健且高性能的集成。chDB 没有依赖管道,而是与 ClickHouse 的读取和写入缓冲区紧密集成,以 通过 MemoryView 交换查询和结果。这解决了上述挑战,确保可以在代码中使用 ClickHouse 的单个进程,同时避免了昂贵的内存复制,并固有地支持并行管道而不会阻塞。
对于那些感兴趣的人,我们计划在本文之后发布一篇更深入的客座博客,深入探讨 auxen 和 Lorenzo 面临的实施和一些挑战。或者,如果您迫不及待想了解详细信息,请访问 开源存储库!
几个快速示例
在您的 Python 代码中使用 chDB 非常简单。像任何其他 python 模块一样,快速的 pip 安装即可开始使用。
pip install chdb
ClickHouse 的一个流行功能是能够查询托管在对象存储(如 S3)中的各种文件格式。下面,我们使用 s3 表函数查询表示为一组 Parquet 文件的流行的英国房产价格数据集。请注意,我们不需要指定文件的结构或其格式 - ClickHouse 的模式推断会自动处理此问题。
注意:我们使用 CSVWithNames 格式显式要求响应中的列标题 - CSV 的默认格式会省略这些标题。
import chdb
data = chdb.query("SELECT * FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/uk-house-prices/parquet/house_prices_2*.parquet') LIMIT 5","CSVWithNames")
print(data)
"price","date","postcode1","postcode2","type","is_new","duration","addr1","addr2","street","locality","town","district","county"
62000,9339,"SS6","8PN",2,0,1,"50","","CHURCH ROAD","RAYLEIGH","RAYLEIGH","ROCHFORD","ESSEX"
53500,9400,"SS6","8PW",2,0,1,"10","","LODGE CLOSE","RAYLEIGH","RAYLEIGH","ROCHFORD","ESSEX"
55950,9430,"SS6","8PX",2,0,1,"56","","GROVE ROAD","RAYLEIGH","RAYLEIGH","ROCHFORD","ESSEX"
50000,9198,"SS6","8PX",2,0,1,"58","","GROVE ROAD","RAYLEIGH","RAYLEIGH","ROCHFORD","ESSEX"
109995,9152,"SS6","8PY",3,1,1,"18","","THE RAMPARTS","RAYLEIGH","RAYLEIGH","ROCHFORD","ESSEX"
Pandas 库几乎无处不在,用于 Python 中的数据操作和分析,数据帧是有效表示表格数据的主要手段。利用 chDB 与此库的集成非常简单。下面,我们执行一个简单的聚合,以计算 2000 年以来伦敦每年的平均房价。
pip install pyarrow pandas matplotlib
import chdb
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
df = chdb.query("SELECT toYear(date::Date32) AS year, round(avg(price)) AS price "
"FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/uk-house-prices/parquet/house_prices_20*.parquet') WHERE town = 'LONDON' GROUP BY year ORDER BY year","Dataframe")
df['year'] = df['year'].astype(int)
plt.plot(df['year'], df['price'], marker='o', linestyle='-', color='b', label='Price')
plt.xlabel('Year')
plt.ylabel('Price')
plt.legend()
plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
plt.show(block=True)
用户还可以使用 chDB 查询现有的表格结构,例如 Pandas 数据帧,从而可以使用 ClickHouse SQL 简化和加速代码。在下面的示例中,我们使用一些虚拟日期填充数据帧,然后重复上述查询。请注意查询中使用的 __table__
语法。
import chdb.dataframe as cdf
from datetime import datetime, timedelta
import pandas as pd
import random
# Populate the DataFrame with random house sales data
data = []
start_date = datetime(2010, 1, 1)
end_date = datetime(2023, 12, 31)
for _ in range(10000):
date = start_date + timedelta(days=random.randint(0, (end_date - start_date).days)) # Random date
price = random.randint(100000, 1000000) # Random price between 100000 and 1000000
data.append({'date': date, 'price': price})
df = pd.DataFrame(data)
tbl = cdf.Table(dataframe=df)
df = tbl.query('SELECT toYear(date::Date32) AS year, round(avg(price)) AS price FROM __table__ GROUP BY year ORDER BY year')
print(df)
year price
0 2010 562323.0
1 2011 557704.0
2 2012 556884.0
3 2013 553141.0
4 2014 550012.0
5 2015 555865.0
6 2016 560128.0
7 2017 558746.0
8 2018 560938.0
9 2019 559185.0
10 2020 565041.0
11 2021 535593.0
12 2022 540023.0
13 2023 543916.0
最后,用户还可以查询 ClickHouse 支持的多种格式中的任何一种格式的数据并返回数据。下面我们查询英国房价数据集的 gzip CSV 样本,并以 Arrow 格式返回结果。
import chdb
res = chdb.query(
f"SELECT town, district, count() AS c, round(avg(price)) AS price "
f"FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/uk-house-prices/csv/house_prices.csv.gz') "
f"GROUP BY town, district HAVING c >= 100 ORDER BY price DESC LIMIT 10",
"ArrowTable")
print(res)
pyarrow.Table
town: binary
district: binary
c: uint64 not null
price: double
----
town: [[4C4F4E444F4E,4C4F4E444F4E,4C4F4E444F4E,56495247494E4941205741544552,4C45415448455248454144,4C4F4E444F4E,4E4F525448574F4F44,57494E44534F52,57494E444C455348414D,434F4248414D]]
district: [[43495459204F46204C4F4E444F4E,43495459204F4620574553544D494E53544552,4B454E53494E47544F4E20414E44204348454C534541,52554E4E594D454445,454C4D425249444745,43414D44454E,544852454520524956455253,425241434B4E454C4C20464F52455354,535552524559204845415448,454C4D425249444745]]
c: [[729,9605,6549,379,262,7399,150,111,232,925]]
price: [[3212987,2888615,2447372,2115944,2085028,1619476,1493810,1360590,1323741,1307596]]
有关更多示例,请参阅 chDB 存储库,作者在其中提供了常见问题和任务的解决方案。
不仅仅是 Python
虽然提供 Python 绑定是该项目的最初重点,但 chDB 很快就受益于社区的兴趣和贡献。Rust、NodeJS 和 Golang 的绑定正在积极开发中!我们很高兴看到这项工作以及它们将解锁的潜在应用。
chDB 已经为一些有趣的可能性打开了大门。除了使使用 ClickHouse 的 AWS lambda 函数更易于编写和部署之外,chDB 的服务器版本还提供了无状态体验,有助于测试函数和执行快速数据分析,甚至无需编写一行 Python 代码。Lorenzo 甚至演示了在 fly.io 上使用 简单配方运行此程序,以提供一个免费的 SQL 查询引擎,用于查询远程文件。
未来
自 chDB 问世以来,其发展速度令人印象深刻。最近,向 Python 绑定添加会话允许用户通过创建表来跨查询持久化状态,在这些表中,可以插入和查询数据。这为 Python 代码带来了 ClickHouse MergeTree 和稀疏索引 的全部功能,并有望解锁新的本地分析规模!
社区计划将这些会话扩展到其他绑定,包括支持用户自定义函数 (UDF)。除了确保及时更新 chDB 以支持最新版本的 ClickHouse 之外,该团队甚至还抽出时间最近添加了 ARM64/AARCH64 支持。
我们期待看到 chDB 的发展,并很想听听您是如何使用它的。
最后,对于希望在我们每月的社区电话会议上重点介绍其基于 ClickHouse 的项目的用户,请联系 [email protected]。