使用 ClickHouse 的 UDF 解决语义版本的需求

Clickhouse 用户自定义外部函数 ·  Clickhouse 从 21.11 版本开始,除了提供类似SqlServer、MySQL CREATE FUNCTION 的自定义函数之外,还有一个用户自定义函数(UDF),与其说是“用户自定义函数”,为了避免混淆,称之为”用户自定义外部函数“更为准确。官方对此功能的解释: ClickHouse can call any external executable program or script to process data. 译文:ClickHouse可以调用任何外部可执行程序或脚本来处理数据 阅读详情

图片

本文字数:5775;估计阅读时间:15 分钟

作者:Juan S. Carrillo

本文在公众号【ClickHouseInc】首发

图片

我在 Embrace 工作,我们构建了唯一基于 OpenTelemetry 的用户中心移动应用可观测性解决方案,并使用 ClickHouse 为我们的时间序列分析产品提供支持。

应用版本是 Embrace 用户最重要的排序类别之一。应用版本通常采用语义版本控制(Semantic Versioning),版本格式为 <主版本>.<次版本>.<补丁版本>。按以下规则进行版本升级:

  1. 主版本号:进行不兼容的 API 更改时

  2. 次版本号:增加向后兼容的新功能时

  3. 补丁版本号:进行向后兼容的错误修复时

我们希望对应用版本排序时得到 2.1.0、2.1.2 和 2.1.10 这样的顺序,而不是按字典顺序排列得到的 2.1.0、2.1.10 和 2.1.2。

ClickHouse 并未直接提供语义版本排序支持。不过,从 ClickHouse v21.10 开始,我们可以通过用户定义函数(UDF)来解决这个问题。

我们最终实现的 UDF 如下。如果您有兴趣了解 UDF 的构建过程以及查询和逻辑改进,请继续阅读。

CREATE FUNCTION sortableSemVer AS version -> 
  arrayMap(
    x -> toUInt32OrZero(x), 
    splitByChar('.', extract(version, '(\\d+(\\.\\d+)+)'))
  )

将版本号转换为整数数组

数据库中版本通常以字符串形式存储,但按字典顺序排序无法得到预期的顺序。

SELECT *
FROM
(
    SELECT ['1.0', '2.0', '3.0.0', '10.0'] AS versions
)
ARRAY JOIN versions
ORDER BY versions DESC

┌─versions─┐
│ 3.0.0    │
│ 2.0      │
│ 10.0     │ << ???
│ 1.0      │
└──────────┘

我们可以将版本号转换为整数数组来解决此问题。将语义版本重写为整数数组后,排序将符合预期,且不同长度的版本也可以正常排序!

SELECT *
FROM
(
    SELECT [[1, 0], [2, 0], [3, 0, 0], [10, 0]] AS versions
)
ARRAY JOIN versions
ORDER BY versions DESC

┌─versions─┐
│ [10,0]   │
│ [3,0,0]  │
│ [2,0]    │
│ [1,0]    │
└──────────┘

可以用一个 lambda 函数,将版本字符串转换为整数数组。

SELECT
    version,
    arrayMap(x -> toUInt32(x), splitByChar('.', version)) AS sem_ver_arr
FROM
(
    SELECT ['1.0', '2.0', '3.0.0', '10.0'] AS version
)
ARRAY JOIN version
ORDER BY sem_ver_arr DESC

┌─version─┬─sem_ver_arr─┐
│ 10.0    │ [10,0]      │
│ 3.0.0   │ [3,0,0]     │
│ 2.0     │ [2,0]       │
│ 1.0     │ [1,0]       │
└─────────┴─────────────┘

具体步骤如下:

  1. splitByChar('.', version) 将版本字符串按 . 分割为字符串数组,例如将 10.0 转换为 ['10', '0']。

  2. arrayMap(x -> toUInt32(x), arr) 将每个数字字符串转换为 int32 类型。

为了简化代码编写,可以通过定义一个 UDF 来实现。

CREATE FUNCTION sortableSemVer AS version -> 
  arrayMap(x -> toUInt32(x), splitByChar('.', version));

让我们试试看!

SELECT
    version,
    sortableSemVer(version) AS sem_ver_arr
FROM
(
    SELECT ['1.0', '2.0', '3.0.0', '10.0'] AS version
)
ARRAY JOIN version
ORDER BY sem_ver_arr DESC

┌─version─┬─sem_ver_arr─┐
│ 10.0    │ [10,0]      │
│ 3.0.0   │ [3,0,0]     │
│ 2.0     │ [2,0]       │
│ 1.0     │ [1,0]       │
└─────────┴─────────────┘

实际上,您甚至可以完全省略 sem_ver_arr 列,仅在 ORDER BY 子句中使用 sortableSemVer。

SELECT version
FROM
(
    SELECT ['1.0', '2.0', '3.0.0', '10.0'] AS version
)
ARRAY JOIN version
ORDER BY sortableSemVer(version) DESC

┌─version─┐
│ 10.0    │
│ 3.0.0   │
│ 2.0     │
│ 1.0     │
└─────────┘

如果您的语义版本格式规范,可以直接使用这个函数。如果版本字符串是类似 my-app-1.2.3(456)-alpha-45dbbdf9ab 的格式,请继续阅读。

复杂格式的版本号

我们以一个简单的例子继续说明:1.2.3.production。由于 production 不是有效数字,之前的函数会在此处失效。

select arrayMap(x -> toUInt32(x), splitByChar('.', '1.2.3.production'));

Received exception from server (version 23.8.15):
Code: 6. DB::Exception: Received from localhost:9000. DB::Exception: Cannot parse string 'production' as UInt32: syntax error at begin of string. Note: there are toUInt32OrZero and toUInt32OrNull functions, which returns zero/NULL instead of throwing exception.: while executing 'FUNCTION toUInt32(x :: 0) -> toUInt32(x) UInt32 : 1': while executing 'FUNCTION arrayMap(__lambda :: 1, splitByChar('.', '1.2.3.production') :: 0) -> arrayMap(lambda(tuple(x), toUInt32(x)), splitByChar('.', '1.2.3.production')) Array(UInt32) : 2'. (CANNOT_PARSE_TEXT)

为了解决这个问题,可以用 toUInt32OrZero 替换 toUInt32,将非数字字符串默认转换为 0。这样,即使版本字符串完全不包含数字也能正常处理。

SELECT
    version,
    arrayMap(x -> toUInt32OrZero(x), splitByChar('.', version)) AS sem_ver_arr
FROM
(
    SELECT [
        '1.0', '2.0', '3.0.0', 
        '10.0', 'production', '1.2.3.production'
        ] AS version
)
ARRAY JOIN version
ORDER BY sem_ver_arr DESC

┌─version──────────┬─sem_ver_arr─┐
│ 10.0             │ [10,0]      │
│ 3.0.0            │ [3,0,0]     │
│ 2.0              │ [2,0]       │
│ 1.2.3.production │ [1,2,3,0]   │
│ 1.0              │ [1,0]       │
│ production       │ [0]         │
└──────────────────┴─────────────┘

如果版本号为 1.2.3-production,使用 . 分割会导致丢失补丁版本。我们可以利用正则表达式和 extract 函数来提取任何符合语义版本格式的内容,这样可以从字符串开头获取语义版本。

SELECT extract('1.2.3-production', '^\\d+\\.\\d+\\.\\d+')

┌─extract('1.2.3-production', '^\\d+\\.\\d+\\.\\d+')─┐
│ 1.2.3                                              │
└────────────────────────────────────────────────────┘

我们还可以进一步调整正则表达式,以支持字符串中其他位置的语义版本。

SELECT extract('my-app1.2.3-production', '\\d+\\.\\d+\\.\\d+')

┌─extract('my-app1.2.3-production', '\\d+\\.\\d+\\.\\d+')─┐
│ 1.2.3                                                   │
└─────────────────────────────────────────────────────────┘

再进一步修改,让正则表达式支持包含两个或更多子部分的语义版本。

SELECT extract('1.2.3.4.5.6.7-production', '(\\d+(\\.\\d+)+)')

┌─extract('1.2.3.4.5.6.7-production', '(\\d+(\\.\\d+)+)')─┐
│ 1.2.3.4.5.6.7                                           │
└─────────────────────────────────────────────────────────┘

我们将整个正则表达式用括号包裹,以捕获完整版本号而不是仅重复的某个部分,否则只能捕获正则表达式的最后一段。

SELECT extract('1.2.3.4.5.6.7-production', '\\d+(\\.\\d+)+')

┌─extract('1.2.3.4.5.6.7-production', '\\d+(\\.\\d+)+')─┐
│ .7                                                    │
└───────────────────────────────────────────────────────┘

^--- Where did the rest of it go?!?

让我们更新原有的 UDF,增加正则表达式支持!

--- Drop the previous definition
DROP FUNCTION IF EXISTS sortableSemVer;

--- Create the new definition
CREATE FUNCTION sortableSemVer AS version -> 
  arrayMap(
    x -> toUInt32OrZero(x), 
    splitByChar('.', extract(version, '(\\d+(\\.\\d+)+)'))
  );

添加更多版本字符串测试,以查看该函数的行为表现。

SELECT
    version,
    sortableSemVer(version) AS sem_ver_arr
FROM
(
    SELECT [
        '1.0', '2.0', '3.0.0', '10.0', 'production', '1.2.3.production', 
        'my-app-1.2.3-prod', '3.5.0(ac22da)-test', '1456', '1.2.3.45', ''
        ] AS version
)
ARRAY JOIN version
ORDER BY sem_ver_arr DESC

图片

当然,这种方法并非适用于所有情况。例如,以下格式的版本字符串无法被正确解析:

SELECT sortableSemVer('100.731a9bd8-5edbc015-SNAPSHOT') AS sem_ver_arr

┌─sem_ver_arr─┐
│ [100,731]   │
└─────────────┘

由于后缀被移除,以下版本也无法正确排序:

SELECT
    version,
    sortableSemVer(version) AS sem_ver_arr
FROM
(
    SELECT ['1.2.3-prod', '1.2.3', '1.2.3-stg'] AS version
)
ARRAY JOIN version
ORDER BY sem_ver_arr DESC

┌─version────┬─sem_ver_arr─┐
│ 1.2.3-prod │ [1,2,3]     │
│ 1.2.3      │ [1,2,3]     │
│ 1.2.3-stg  │ [1,2,3]     │
└────────────┴─────────────┘

此外,不同的版本控制方案可能会产生冲突:

SELECT
    version,
    sortableSemVer(version) AS sem_ver_arr
FROM
(
    SELECT [
        'my-app-1.2.3-prod', 
        '1.2.3', 
        '1.2.3(af012342)-ALPHA'
        ] AS version
)
ARRAY JOIN version
ORDER BY sem_ver_arr DESC

Query id: 5bce759d-8ddb-4327-8e84-6f682b71b022

┌─version───────────────┬─sem_ver_arr─┐
│ my-app-1.2.3-prod     │ [1,2,3]     │
│ 1.2.3                 │ [1,2,3]     │
│ 1.2.3(af012342)-ALPHA │ [1,2,3]     │
└───────────────────────┴─────────────┘

不过,这通常不成问题,因为用户往往会使用相同的版本控制方案。ClickHouse 的 UDF 为使用 lambda 处理数据提供了强大支持。根据本指南中的方法调整 UDF,以更好地满足您的需求。对于我们的使用场景来说,这种方法已经足够有效。

征稿启示

面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

 

​​联系我们

手机号:13910395701

邮箱:Tracy.Wang@clickhouse.com

满足您所有的在线分析列式数据库管理需求

ClickHouse使用Python自定义UDF 验证udf是否注册成功。2.将python脚本放在配置路径下,默认为/var/lib/clickhouse/user_scripts。ClickHouse原生支持很多种方式自定义UDF,但是按照官方给的示例操作时发现一些问题。1.先将xml文件放在ClickHouse安装目录,同config.xml同层级。注:本文为原创,如需转载请注明来源。如有侵权,保留法律追究权利。以下是根据官方介绍来操作并成功注册了Python方式的UDF。ClickHouse版本:22.8。3.验证UDF是否注册成功。 阅读详情

相关推荐

ClickHouse开发相关(UDAF)

ClickHouse介绍ClickHouse是一个开源、高性能的列式 OLAP 数据库管理系统,用于使用 SQL 进行实时分析。为什么需要ClickHouse UDAF?ClickHouse中已存在了许多聚合函数,绝大多数情况下已经覆盖我们的需求,但是有时候我们仍然需要自定义函数逻辑,去实现复杂的数据分析需求,因此就有了基于ClickHouse中实现自定义函数(UDF)或自定义聚合函数(UDAF)需求,这篇文章我们讲下如何基于ClickHouse实现UDAF。实现UDAF步骤。

dabai521的博客 1312

使用ClickHouse UDF与OpenAI模型集成

本文字数:14683;估计阅读时间:37 分钟作者:Dale McDiarmid审校:庄晓东(魏庄)本文在公众号【ClickHouseInc】首发。

ClickHouseDB的博客 1443

SparkSQL & ClickHouse RoaringBitmap使用实践

文章目录简介ClickHouse简介RoaringBitmap(RBM)原理ClickHouse中使用RBM存在的问题RoaringBitmap(RBM)定制序列化实现ClickHouse中RoaringBitmap的结构解析Spark中RoaringBitmap的实现定制RBM序列化方式以兼容ClickHouseByte(1) - 类型标识生成VarInt(SerializedSizeInBytes) - 序列化后的字节长度ByteArray(RoaringBitmap) - RBM序列化定制序列化的整体

qq_27639777的博客 1万+

Clickhouse自定义UDF函数

加载function,查询是否成功,这里查询的xx要跟xml文件保持一致。需要安装python3环境。

等闲之辈莫等闲的博客 2169

数据湖是什么?有什么优势?与数仓区别?未来的发展?

数据湖是什么?有什么优势?与数仓区别?未来的发展?一、什么是数据湖二、数据湖的发展三、数据湖有哪些优势四、数据湖应该具备哪些能力五、数据湖的实现遇到了哪些问题六、数据湖与数据仓库的区别七、为什么要做数据湖?区别在于?八、数据湖挑战九、湖仓一体十、目前有哪些开源数据湖组件 来源:大数据DT 一、什么是数据湖 数据湖是一种不断演进中、可扩展的大数据存储、处理、分析的基础设施;以数据为导向,实现任意来源、任意速度、任意规模、任意类型数据的全量获取、全量存储、多模式处理与全生命周期管理;并通过与各类外部异构数据

一个写湿的程序猿 9148

告别手动群发!用IDA Pro和CE搞定企业微信4.1.38.6011的HOOK开发(附完整代码)

本文详细介绍了如何利用IDA Pro和Cheat Engine进行企业微信4.1.38.6011的HOOK开发,实现自动化群发功能。从逆向工程环境配置、关键函数定位到HOOK框架设计,提供完整代码示例,帮助企业提升运营效率。

weixin_42533120的博客 478

ClickHouse UDF编写示例

Clickhouse 22版本的UDF编写示例

hongguo880的博客 2884

codesys多协议通信之OPC UA通信

测试不易,转载请注明出处!

weixin_44243068的博客 3637

记录一下 clickhouse的java udf 函数实现

主要参考了以下文章,找到的教程使用的是JSONEachRow格式传入数据,我使用的是 TabSeparated注,我的clickhouse是使用 curl https://clickhouse.com/ | sh 的方式下载,./clickhouse install 的方式安装的,目录是默认目录。

weixin_42180058的博客 1735

Rocky Linux 9.0国内yum源一键替换指南(上海交大镜像站实测)

本文详细介绍了如何将Rocky Linux 9.0的yum源替换为上海交大镜像站,以解决国内用户访问官方源速度慢的问题。通过实测验证,上海交大镜像站提供高速下载和稳定更新,并提供了完整的替换步骤、常见问题解决方案及高级优化配置,帮助用户提升软件包下载效率。

weixin_29304985的博客 359

2024年电气工程师最新面试题及答案

1. **基本电气工程原理**:包括电流、电压、电阻、功率等基本概念。2. **欧姆定律**:V = IR,描述电压、电流和电阻之间的关系。42. **风力发电系统组成**:包括风力涡轮机、发电机、控制系统等。44. **智能电网技术**:包括自动化控制、通信技术、数据分析等。10. **减少EMI**:使用屏蔽、滤波、合理布线等方法。40. **光伏系统组成**:包括光伏板、逆变器、控制器等。48. **能量存储技术**:包括电池、超级电容器、飞轮等。

guo162308的博客 6561

ClickHouse Java多参UDF

ClickHouse调用java语言编写的多参UDF例程

sleetdream的博客 1759

如何给K8S配置一个具有永久有效的kubeconfig

在 Amazon EKS 环境中,Kubernetes 的认证机制与 AWS IAM 深度集成,通过aws-iam-authenticator动态生成临时凭证。这种设计虽然增强了安全性,但给需要持久化凭证的工具链(如 CI/CD 系统中的 KubeVela)带来了挑战。具体表现为:临时凭证失效​​:默认 Token 有效期为 15 分钟至 1 小时;​​IAM 角色限制​​:直接使用aws eks get-token生成的凭证无法持久化

小杨同学的博客 660

ClickHouse官网 Python UDF 官方示例报错解决方式

ClickHouse官网示例报错 DB::Exception: Cannot write into pipe: , errno: 32, strerror: Broken pipe: While executing TabSeparatedRowOutputFormat: While executing ShellCommandSource 解决方案

qq_38331058的博客 354

鸿蒙开发之hdc命令行

hdc(HarmonyOS Device Connector)是HarmonyOS为开发人员提供的用于调试的命令行工具,通过该工具可以在windows/linux/mac系统上与真实设备进行交互。

xiangzhihong8的专栏 5828

rk3588 适配音频解码芯片 ALC5616

在 RK3588 的高性能方案中,选择 **ALC5616**(来自 Realtek 瑞昱)通常意味着项目更侧重于**音频性能的稳定性**以及**全球供应链的通用性**。

weixin_35723192的博客 142

终极指南:ClickHouse UDF开发与性能优化全攻略

ClickHouse作为一款高性能的开源大数据分析型数据库管理系统,提供了强大的用户自定义函数(UDF)功能,允许用户扩展其数据处理能力。本文将详细介绍如何开发ClickHouse UDF并进行性能优化,帮助新手和普通用户轻松掌握这一强大特性。 ## UDF类型概览:选择最适合你的扩展方式 ClickHouse支持三种主要UDF类型,各具特点和适用场景: ### SQL UDF:轻量级逻辑复

gitblog_00537的博客 1097

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

ClickHouse用户自定义函数(UDF)开发指南

ClickHouse用户自定义函数(UDF)开发指南 【免费下载链接】ClickHouse ClickHouse® 是一个免费的大数据分析型数据库管理系统。 项目地址: https://gitcode.com/GitHub_Tre...

gitblog_00283的博客 696

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

ClickHouse UDF 运行速度慢问题

ClickhHouse UDF 运行速度慢问题

sleetdream的博客 1646

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

hive的udf通过Waterdrop把hive的数据抽到ClickHouse

1,因业务需要把hive的数据通过WaterDrop抽取到clickhouse,但是每次都要写配置文件,故写一个配置文件自动生成配置信息. 1,版本信息: waterdrop版本 :1.5.0 spark版本:3.0.0 hive版本: 3.0.0 2,因为waterdrop抽取hive的分区表有点问题,所以目前只支持非分区表的情况,如果有需要支持分区表,可以修改udf完成支持 package com.xxx; import org.apache.hadoop.hive.ql.e..

wppwpp1的专栏 1232

自定义函数与UDF:扩展ClickHouse的查询能力

1.背景介绍 在大数据时代,数据处理和分析的需求日益增长。ClickHouse是一种高性能的列式数据库,它可以实时处理大量数据并提供快速的查询速度。为了满足不同的业务需求,ClickHouse提供了一系列内置函数,以及用户自定义函数(UDF)机制,使得开发者可以轻松地扩展ClickHouse的查询能力。 本文将从以下几个方面进行阐述: 背景介绍 核心概念与联系 核心算法原理和具体操作步骤以...

AI天才研究院 1143

插件与UDF:ClickHouse插件与自定义UDF的开发与应用

1.背景介绍 在大数据时代,数据处理和分析的需求日益增长。ClickHouse是一种高性能的列式数据库,它的设计目标是为实时数据处理和分析提供快速、高效的解决方案。ClickHouse支持插件和用户自定义函数(UDF),使得用户可以根据自己的需求扩展和定制数据处理功能。 本文将涵盖ClickHouse插件和自定义UDF的开发与应用,包括背景介绍、核心概念与联系、核心算法原理和具体操作步骤、数学...

AI天才研究院 389

自定义udf把mysql的表结构自动转换成clickhouse的表结构

1,因业务需求,需要把mysql的数据同步到clickhouse,但是clickhouse建表语法有比较繁琐,故写了一个udf来生成数据 package com.crgt; import com.crgecent.common.util.DateUtil; import org.apache.hadoop.hive.ql.exec.UDFArgumentException; import org.apache.hadoop.hive.ql.metadata.HiveException; import

wppwpp1的专栏 1625

ClickHouse版本管理实战:3种高效升级策略深度解析

ClickHouse作为高性能实时分析数据库,其版本管理是生产环境稳定运行的关键保障。面对快速迭代的ClickHouse版本发布节奏,数据库管理员需要掌握系统性的版本控制策略,确保升级过程平稳可靠。本文将深入探讨ClickHouse版本管理的核心挑战,提供三种实用的升级实施方案,并分享高级用户的最佳实践。 ## 问题场景:生产环境版本迭代的挑战 在实际运维场景中,ClickHouse版本管理面

gitblog_01091的博客 906

记录clickhouse的 外部自定义函数 udf 如何传入空值

修改函数配置文件 : 将 type 修改为 Nullable(String) ,这样就可以传入空值了。经过一番搜索,是因为没有在配置文件中设置可以传入空值,必须设置可以传入空值才可以。之前编写的udf函数报错了,因为有空值。之前编写的udf详见。

weixin_42180058的博客 305
上一篇: 基于 ClickHouse、Apache Arrow 和 Perspective 的流式实时可视化
下一篇: 超强实用技巧:使用 ClickHouse 构建实时单页应用程序
ClickHouseDB
博客等级 码龄3年 1707粉丝 320原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值