0
119
0
0
首页/专栏/ 版本发布/ 查看内容

ClickHouse 发布 24.2 版本

 admin   发表于  2024-10-15 14:45
专栏 版本发布

新贡献者

像往常一样,我们特别欢迎所有在 24.2 版中的新贡献者!ClickHouse 的受欢迎程度在很大程度上归功于社区的努力贡献。看到这个社区不断壮大总是令人感到自豪的。

以下是新贡献者的名字:

johnnymatthews, AlexeyGrezz, Aris Tritas, Charlie, Fille, HowePa, Joshua Hildred, Juan Madurga, Kirill Nikiforov, Nickolaj Jepsen, Nikolai Fedorovskikh, Pablo Musa, Ronald Bradford, YenchangChan, conicliu, jktng, mikhnenko, rogeryk, una, Кирилл Гарбар_

提示:如果您想知道我们是如何生成这个列表的...请点击这里(https://gist.github.com/gingerwizard/5a9a87a39ba93b422d8640d811e269e9)

如果您在这里看到了您的名字,请与我们联系...不过我们也会在 Twitter 等地方找到您。

您也可以在 YouTube 上查看本次版本视频,查看演示文稿的幻灯片。(https://presentations.clickhouse.com/release_24.2/#)

好的,让我们进入功能介绍吧!


自动检测文件格式

由 Pavel Kruglov 贡献

在处理文件时,即使文件没有有效的扩展名,ClickHouse 也会自动检测文件的类型。例如,以下文件 foo 包含了 JSON 行格式的数据:

$ cat foo
{"name": "John Doe", "age": 30, "city": "New York"}{"name": "Jane Doe", "age": 25, "city": "Los Angeles"}{"name": "Jim Beam", "age": 35, "city": "Chicago"}{"name": "Jill Hill", "age": 28, "city": "Houston"}{"name": "Jack Black", "age": 40, "city": "Philadelphia"}
让我们尝试使用 file 函数处理该文件:
SELECT *FROM file('foo')
┌─name───────┬─age─┬─city─────────┐│ John Doe │ 30New York ││ Jane Doe │ 25 │ Los Angeles ││ Jim Beam │ 35 │ Chicago ││ Jill Hill │ 28 │ Houston ││ Jack Black │ 40 │ Philadelphia │└────────────┴─────┴──────────────┘
5 rows in set. Elapsed: 0.003 sec.
非常酷。现在让我们将内容写入 Parquet 格式:
SELECT *FROM file('foo')INTO OUTFILE 'bar'FORMAT Parquet
我们可以在不告诉 ClickHouse 文件格式的情况下读取它吗?
SELECT *FROM file('bar')
┌─name───────┬─age─┬─city─────────┐│ John Doe │ 30New York ││ Jane Doe │ 25 │ Los Angeles ││ Jim Beam │ 35 │ Chicago ││ Jill Hill │ 28 │ Houston ││ Jack Black │ 40 │ Philadelphia │└────────────┴─────┴──────────────┘
5 rows in set. Elapsed: 0.003 sec.
当然可以!自动检测功能在从 URL 读取时同样适用。所以如果我们在上述文件周围启动一个本地 HTTP 服务器:
python -m http.server
然后我们可以像这样读取它们:
SELECT *FROM url('http://localhost:8000/bar')
┌─name───────┬─age─┬─city─────────┐│ John Doe │ 30New York ││ Jane Doe │ 25 │ Los Angeles ││ Jim Beam │ 35 │ Chicago ││ Jill Hill │ 28 │ Houston ││ Jack Black │ 40 │ Philadelphia │└────────────┴─────┴──────────────┘
这就是现在的足够的示例,但您也可以将此功能与 s3hdfsazureBlobStorage 表函数一起使用。


漂亮格式更漂亮了

RogerYK

如果您曾经需要快速解释查询结果中的大数字,那么这个功能就适合您。当您返回单个数字列时,如果该列中的值大于一百万,则可读数量将作为注释显示在值本身旁边。

SELECT 765432198
┌─765432198─┐765432198-- 765.43 million└───────────┘


视图的安全性

由 Artem Brustovetskii 贡献

在此版本之前,如果您在表上定义了视图,要想用户访问该视图,他们还需要访问该表。这不是理想的情况,在 24.2 版本中,我们为 CREATE VIEW 查询添加了 SQL SECURITYDEFINER 规范,以解决这个问题。

假设我们有一个公司的工资表,其中包含员工的姓名、部门、工资和地址详情。我们可能希望允许人力资源团队访问所有信息,但也允许其他用户查看员工姓名和部门。

让我们首先创建一个表并填充它:

CREATE TABLE payroll (  name String,  address String,  department LowCardinality(String),  salary UInt32)Engine = MergeTreeORDER BY name;
INSERT INTO payroll (`name`, `address`, `department`, `salary`) VALUES('John Doe', '123 Maple Street, Anytown, AT 12345', 'HR', 50000),('Jane Smith', '456 Oak Road, Sometown, ST 67890', 'Marketing', 55000),('Emily Jones', '789 Pine Lane, Thistown, TT 11223', 'IT', 60000),('Michael Brown', '321 Birch Blvd, Othertown, OT 44556', 'Sales', 52000),('Sarah Davis', '654 Cedar Ave, Newcity, NC 77889', 'HR', 53000),('Daniel Wilson', '987 Elm St, Oldtown, OT 99000', 'IT', 62000),('Laura Martinez', '123 Spruce Way, Mytown, MT 22334', 'Marketing', 56000),('James Garcia', '456 Fir Court, Yourtown, YT 33445', 'Sales', 51000);
我们有两个用户 - Alice 是人力资源团队的成员,Bob 是工程团队的成员。Alice 在人力资源团队中,并且可以访问工资表,而 Bob 则不行!
CREATE USER alice IDENTIFIED WITH sha256_password BY 'alice';GRANT SELECT ON default.payroll TO alice;GRANT SELECT ON default.employees TO alice  WITH GRANT OPTION;
CREATE USER bob IDENTIFIED WITH sha256_password BY 'bob';
Alice 创建了一个名为 employees 的视图:
CREATE VIEW employees  DEFINER = alice SQL SECURITY DEFINERAS SELECT name, departmentFROM payroll;
然后 Alice 将该视图的访问权限授予了自己和 Bob:
GRANT SELECT ON default.employees TO alice;GRANT SELECT ON default.employees TO bob;
如果我们以 Bob 的身份登录:
clickhouse client -u bob
我们可以查询 employees 表:
SELECT *FROM employees
┌─name───────────┬─department─┐│ Daniel Wilson │ IT ││ Emily Jones │ IT ││ James Garcia │ Sales ││ Jane Smith │ Marketing ││ John Doe │ HR ││ Laura Martinez │ Marketing ││ Michael Brown │ Sales ││ Sarah Davis │ HR │└────────────────┴────────────┘
但是他无法查询底层的工资表,这是我们所预期的:
SELECT *FROM payroll
Received exception from server (version 24.3.1):Code: 497. DB::Exception: Received from localhost:9000. DB::Exception: bob: Not enough privileges. To execute this query, it's necessary to have the grant SELECT(name, address, department, salary) ON default.payroll. (ACCESS_DENIED)


矢量化距离函数

由 Robert Schulze 贡献

在最近的博客文章中,我们探讨了 ClickHouse 如何在用户需要高性能线性扫描以获得准确结果和/或能够通过 SQL 将向量搜索与元数据过滤和聚合相结合时,作为向量数据库使用。用户可以利用这些功能通过检索增强生成(RAG)流水线为基于 LLM 的应用程序提供上下文。我们在底层支持向量搜索方面的投入继续进行,最近的工作重点是改进计算两个向量之间距离的函数族的性能。有关背景信息,我们建议阅读这篇文章以及我们自己 Mark 的最新视频:(https://www.youtube.com/watch?v=BFtWe2xG5cU)

尽管对于较大的数据集,向量搜索的查询性能很容易受到 I/O 限制,但许多用户只需要搜索适合内存的较小数据集的 SQL。在这些情况下,ClickHouse 中的性能可能会受到 CPU 的限制。因此,确保该代码被适当地矢量化并使用最新的指令集,可以显著提高性能,并将性能限制为内存带宽 - 对于具有 DDR-5 的机器,这意味着更高的扫描性能。

在 24.2 版本中,我们很高兴地宣布,cosineDistance、dotProduct 和 L2Distance(欧几里德距离)函数都已经优化,以利用最新的指令集。对于 x86,这意味着使用了融合乘-加(FMA)和 AVX-512 指令进行水平加-减运算,并针对 ARM 进行了自动矢量化。

作为潜在改进的示例,请考虑以下在几乎正式的 ANN 基准测试中流行的 glove 数据集。这个特定的子集(我们已经提供了 Parquet 格式,大小为 2.5GiB),包含了从 840B CommonCrawl 标记中训练的 2.1m 个向量。该集合中的每个向量都有 300 维,并表示一个单词。鉴于简单的架构,这需要几秒钟加载到 ClickHouse 中:

CREATE TABLE glove(  `word` String,  `vector` Array(Float32))ENGINE = MergeTreeORDER BY word;
INSERT INTO glove SELECT *FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/glove/glove_840b_300d.parquet')
0 rows in set. Elapsed: 49.779 sec. Processed 2.20 million rows, 2.66 GB (44.12 thousand rows/s., 53.44 MB/s.)Peak memory usage: 1.03 GiB.

机器规格:

i3en.3xlarge - 12vCPU Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz,96GiB RAM

我们可以通过找到与特定单词的向量最接近的单词,来比较不同版本 ClickHouse 的性能。例如,在 23.12 版本中:

WITH 'dog' AS search_term,(  SELECT vector  FROM glove  WHERE word = search_term  LIMIT 1) AS target_vectorSELECT word, cosineDistance(vector, target_vector) AS scoreFROM gloveWHERE lower(word) != lower(search_term)ORDER BY score ASCLIMIT 5
┌─word────┬──────score─┐│ dogs │ 0.11640692│ puppy │ 0.14147866│ pet │ 0.19425482│ cat │ 0.19831467│ puppies │ 0.24826884└─────────┴────────────┘
5 rows in set. Elapsed: 0.407 sec. Processed 2.14 million rows, 2.60 GB (5.25 million rows/s., 6.38 GB/s.)Peak memory usage: 248.94 MiB.
这里重要的是这个数据集适合文件系统缓存,如其在磁盘上的压缩大小所示:
SELECT  name,  formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,  formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size,  round(sum(data_uncompressed_bytes) / sum(data_compressed_bytes), 2) AS ratioFROM system.columnsWHERE table LIKE 'glove'GROUP BY nameORDER BY name DESC
┌─name───┬─compressed_size─┬─uncompressed_size─┬─ratio─┐│ word │ 13.41 MiB │ 18.82 MiB │ 1.4│ vector │ 2.46 GiB │ 2.47 GiB │ 1└────────┴─────────────────┴───────────────────┴───────┘
2 rows in set. Elapsed: 0.003 sec.
单词列和向量列的总大小约为 2.65 GB,完全适合内存。

在 24.2 版本中,同样的查询性能提高了超过 25%:

5 rows in set. Elapsed: 0.286 sec. Processed 1.91 million rows, 2.32 GB (6.68 million rows/s., 8.12 GB/s.)Peak memory usage: 216.89 MiB.
这些差异将根据处理器、数据集大小、向量基数和内存性能而变化。

关于点积的一小点说明

在 24.2 版本之前,dotProduct 函数没有被矢量化。在确保这一点尽可能高效的同时,我们注意到该函数还执行了任何常量参数的必要解包操作(最常见的用例即我们传递一个常量向量进行比较),这导致了不必要的内存复制。这意味着实际函数运行时间主要受内存操作的影响 - 在这种情况下,矢量化只是相对较小的收益。一旦消除了这一点,基准测试的性能就提高了惊人的 270 倍!

虽然与以前版本的这个函数进行性能比较并不值得(它们有点令人尴尬 :)),但我们认为利用这些改进的机会可以展示出用户现在可以利用的一个很好的性能优化。

读者可能还记得余弦距离和点积之间的密切关系。更具体地说,余弦距离测量多维空间中两个向量之间的夹角的余弦。它是从余弦相似度导出的,其中余弦距离定义为 1 - 余弦相似度。余弦相似度计算为向量的点积除以它们的大小的乘积,即 1- ((a.b)/||a||||b||)。相反,点积测量两个数字序列的对应条目的乘积的总和,即具有分量 ai 和 bi 的向量 A 和 B 的点积为 A⋅B=∑aibi。

当规范化向量时(即两个向量的大小都为 1 时),余弦距离和点积变得特别相关。在这种情况下,余弦相似度实际上就是点积,因为余弦相似度公式中的分母(向量的大小)都是 1,从而相互抵消。因此,我们的余弦距离简单地变为 1-(a.b)。

我们如何利用这一点?

我们可以在插入时使用 L2Norm 函数(向量大小)对我们的向量进行规范化,从而使我们能够在查询时使用 dotProduct 函数。这样做的主要动机是 dotProduct 函数的计算更简单(我们不必为每个向量计算大小),因此可能节省一些查询时间。

要在查询时执行规范化:

INSERT INTO gloveSETTINGS schema_inference_make_columns_nullable = 0SELECT  word,  vector / L2Norm(vector) AS vectorFROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/glove/glove_840b_300d.parquet')SETTINGS schema_inference_make_columns_nullable = 0
0 rows in set. Elapsed: 51.699 sec. Processed 2.20 million rows, 2.66 GB (42.48 thousand rows/s., 51.46 MB/s.)
我们之前的查询变成了:
WITH  'dog' AS search_term,  (      SELECT vector      FROM glove      WHERE word = search_term      LIMIT 1  ) AS target_vectorSELECT  word,  1 - dotProduct(vector, target_vector) AS scoreFROM gloveWHERE lower(word) != lower(search_term)ORDER BY score ASCLIMIT 5
┌─────────┬─────────────────────┐│ word │ score │├─────────┼─────────────────────┤│ dogs │ 0.11640697717666626│ puppy │ 0.1414787769317627│ pet │ 0.19425475597381592│ cat │ 0.19831448793411255│ puppies │ 0.24826878309249878└─────────┴─────────────────────┘<

路过

雷人

握手

鲜花

鸡蛋

版权声明:本文为 clickhouse 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
返回顶部