欢迎,chDB。
在 ClickHouse,我们经常谈论社区和开源。这种对话中蕴含着一种信念,即有时最酷、最令人兴奋的想法来自我们的社区。出于这个原因,我们已开始在每月举行的 ClickHouse 社区电话会议上,重点介绍社区正在创造的一些惊人成果。
本月,我们有机会重点介绍 chDB。
chDB 由 ClickHouse 社区贡献者 Auxten 和 Lorenzo Mangani 开发,并在 社区 的帮助下完成。chDB 是一个由 ClickHouse 提供支持的嵌入式 SQL OLAP 引擎。更简单地说,它使 ClickHouse 引擎可以作为“开箱即用”的 Python 模块使用,允许用户直接在代码中利用 ClickHouse 的全部功能和性能。
这种数据库交互模型在数据科学家和数据工程师中越来越受欢迎,近年来 DuckDB 等项目也越来越受欢迎。虽然 ClickHouse 是一款功能齐全的用于实时分析的 OLAP 数据库,能够在托管 PB 级数据的多节点架构中运行,并且仍然提供亚秒级的查询响应时间,但我们也意识到,很多分析是在用户笔记本电脑和工作站上执行的,尤其是在处理较小的数据集时。这些数据交互在许多项目阶段都很常见,无论是早期数据探索、一次性 ETL 任务、开发和测试,还是对较小数据集的简单 SQL 查询,这些查询需要 SQL 但不需要服务器的强大功能。借助 Python(通常是这些任务的首选语言),chDB 提供了一流的集成,并允许用户在代码中利用 ClickHouse。
为什么要嵌入 ClickHouse?
一段时间以来,ClickHouse 一直提供 clickhouse-local。它提供了一个可本地执行的二进制文件,用户可以使用 ClickHouse 的全部功能来查询本地和远程文件(例如,在 S3 中)。clickhouse-local 提供了完整的客户端控制台,以及通过 stdout 传递查询和响应以集成到脚本中的方法,它解决了上述常见的临时数据任务,并避免了用户部署完整服务器的需要。我们继续投资 clickhouse-local,它受益于与服务器相同的核心代码,并尤其受益于最近的改进,例如更快的 Parquet 查询。
虽然 clickhouse-local 已经证明非常受欢迎,尤其是在简单的 SQL 查询就足够的情况下非常强大,但我们也了解到 Python 无处不在,并且通常是数据任务的首选工具。例如,用户经常需要将 SQL 集成到更广泛的逻辑中,尤其是在 Python 作为训练和调用机器学习模型的最流行方法的情况下。chDB 解决了这个问题,允许用户将 ClickHouse 与 Pandas 等标准数据操作和分析库一起使用。
首先引起我们注意的一件事是 chDB 如何解决了将 ClickHouse 作为 Python 模块提供的挑战:**如何** 对我们来说与 **为什么** 一样重要。一个简单的实现可能会将 clickhouse-local 二进制文件直接包含在 Python 包中,并通过类似于 popen
的东西通过 stdin 和 stdout 传递查询和响应。这种管道方法虽然可能对一次性脚本简单且足够,但存在一些缺点,例如
- 为每个查询启动一个独立的进程会稍微影响性能,导致查询时间增加约 10 到 50 毫秒。
- 不可避免地会出现 SQL 查询结果的多个副本。
- 与 Python 的集成有限,难以实现 Python UDF 并支持 Pandas DataFrame 上的 SQL。
对团队来说,最重要的是它缺乏优雅 ????
团队花费了大量时间(以及他的农历新年)来实现健壮且高性能的集成。chDB 并非依赖管道,而是与 ClickHouse 的读写缓冲区紧密集成,以 通过 MemoryView 交换查询和结果。这解决了上述挑战,确保代码中可以使用 ClickHouse 的单个进程,避免代价高昂的内存复制,并固有地支持并行管道而不会阻塞。
对于有兴趣的人,我们打算在后续博客中发布一篇更深入的客座博客,深入探讨实现过程以及 auxen 和 Lorenzo 面临的一些挑战。或者,如果您等不及详细内容,只需访问 开源仓库!
一些快速示例
在 Python 代码中使用 chDB 非常简单。与任何其他 Python 模块一样,快速 pip install 即可开始使用。
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 绑定添加会话允许用户通过创建表来在查询之间持久化状态,其中 可以插入和查询数据。这将 ClickHouse MergeTree 和稀疏索引 的全部功能带入了 Python 代码,并有望开启本地分析的新规模!
社区计划将这些会话扩展到其他绑定,包括对用户定义函数 (UDF) 的支持。除了确保 chDB 及时更新以支持最新版本的 ClickHouse 之外,团队甚至还抽出时间最近添加了 ARM64/AARCH64 支持。
我们期待着见证 chDB 的发展,并希望了解您已经如何使用它。
最后,对于希望在我们的每月社区电话会议上突出显示其基于 ClickHouse 的项目的用户,请联系 [email protected]。