首页/新闻资讯/正文详情

Apache Druid 迁移指南:从多值维度(MVD)平滑迁移到标准数组(ARRAY)类型

发布时间:2026/9/24 0:36:16 来源:云帆数科 栏目:资讯中心
Apache Druid 迁移指南:从多值维度(MVD)平滑迁移到标准数组(ARRAY)类型
数据库OLAP大数据后端【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址https://gitcode.com/gh_mirrors/druid6/druid点击查看免费下载Apache Druid 从较新版本起支持 SQL 标准兼容的ARRAY列类型可用于VARCHAR、BIGINT和DOUBLE数据原生类型ARRAYSTRING、ARRAYLONG、ARRAYDOUBLE。本指南以 docs/release-info/migr-mvd-array.md 为主体系统对比多值维度Multi-value Dimensions简称 MVD与数组类型在存储、摄取、过滤和分组上的本质差异并给出从 MVD 迁移到数组的完整方案包括逐条 SQL 示例对照、arrayIngestMode摄取模式的选择、ARRAY_TO_MV/MV_TO_ARRAY/MV_FILTER_ONLY等关键函数的使用以及迁移过程中的类型校验与安全开关。阅读本文后你将能根据业务场景正确选型并独立完成存量 MVD 数据的查询改写与摄取改造。为什么官方推荐优先使用数组Druid 官方在迁移指南中明确建议只要条件允许优先使用数组而不是多值维度MVD。对于全新项目以及涉及多种数据类型字符串、整型、浮点型的复杂场景应直接使用数组只有某些特定场景——例如需要像普通字符串那样直接对单个元素进行操作时——才继续使用 MVD。如果你的操作面向整组值包括值在行内的顺序应当使用数组而非 MVD。数组与 MVD 虽然在存储形态上都表现为一行多值但两者的语义差异巨大核心对比见下表详见 Arrays 与 Multi-value dimensions维度ArrayMVD数据类型支持 VARCHAR、BIGINT、DOUBLE 类型ARRAYSTRING、ARRAYLONG、ARRAYDOUBLE仅支持字符串数组VARCHARSQL 合规性行为与标准 SQL 数组一致符合 SQL 标准行为更像 SQL 的 VARCHAR而非标准 SQL 数组需要借助专门的 SQL 函数才能实现类数组行为摄取JSON 数组按 Druid 数组类型摄入SQL 摄取通过查询上下文参数arrayIngestMode控制支持array、mvd、none三种取值。设为none时尝试存储任何数组都会抛出异常JSON 数组默认按 MVD 摄入SQL 摄取需借助 ARRAY_TO_MV 等函数过滤与分组过滤和分组针对整个数组值匹配数组本身可作为 GROUP BY 键按整个数组值分组按单个元素分组需使用 UNNEST 运算符过滤匹配数组内任意一个值分组会为每个值各生成一个组行为类似于隐式 UNNEST相互转换使用 MV_TO_ARRAY 将 MVD 转为数组使用 ARRAY_TO_MV 将数组转为 MVD从源码结构看这种差异是刻意的设计在 ArrayIngestMode.java 中枚举值MVD的注释明确指出其作用仅是保留 Druid 的旧行为未来将被移除因为 MVD 不是真正的数组类型且行为不正确同时它会禁用数值数组的摄入而ARRAY模式则允许数值与字符串数组按数组摄入是推荐的摄取方式。这是迁移决策最重要的底层依据。查询语义差异数组是一个值MVD 是多个字符串在 SQL 查询中Druid 对数组列与 MVD 列的处理方式截然不同数组列中的值被视为一个整体SQL ARRAY是一个单一实体MVD 列中的值被视为独立的字符串SQL VARCHAR即使同一 MVD 内的多个字符串在物理上仍存储为单字段。这一点即便两者存入了相同内容也成立。例如将[a, b, c]分别摄入到数组列和 MVD 列当查询要用某个值与[a, b, c]比较过滤时数组列只有等值过滤匹配到整个数组时才返回该行。例如WHERE array_column ARRAY[a, b, c]。MVD 列等值过滤匹配 MVD 中任意一个值即返回该行。例如下面任一过滤条件都会命中该行WHERE mvd_column aWHERE mvd_column bWHERE mvd_column c在编写涉及过滤或分组的查询时务必留意这一差异。特别地当查询同时应用过滤与分组时MVD 可能返回看似与过滤条件不符的行——因为分组发生在 Druid 应用过滤之后详见下文 过滤与分组组合的陷阱。数组与 MVD 的 SQL 示例逐条对照以下示例基于相同数据集分别以数组列和 MVD 列存储的假设逐一展示两类写法。完整的函数签名与说明可参考 SQL 函数参考 与 SQL 数组函数更丰富的查询示例见 Querying arrays 与 Querying multi-value dimensions。按单个元素过滤过滤出数组/MVD 中含有某个值的行。数组写法——使用 ARRAY_CONTAINSSELECT label, tags FROM array_example WHERE ARRAY_CONTAINS(tags, t3)MVD 写法——直接等值比较MVD 语义为任一值匹配SELECT label, tags FROM mvd_example WHERE tags t3按一个或多个元素过滤过滤出数组/MVD 中含有至少一个目标元素的行。注意 ARRAY_OVERLAP 检查的是存在任意重叠元素而上一例的 ARRAY_CONTAINS 检查的是包含全部指定元素。数组写法SELECT * FROM array_example WHERE ARRAY_OVERLAP(tags, ARRAY[t1, t7])MVD 写法——用 OR 组合多个等值条件SELECT * FROM mvd_example WHERE tags t1 OR tags t7用数组等值过滤过滤出数组/MVD 与某个参考数组完全等价的行。数组写法——整体比较SELECT * FROM array_example WHERE tags ARRAY[t1, t2, t3]MVD 写法——先用 MV_TO_ARRAY 转成数组再比较该函数将多值字符串从VARCHAR转换为VARCHAR ARRAYSELECT * FROM mvd_example WHERE MV_TO_ARRAY(tags) ARRAY[t1, t2, t3]按整个数组分组数组写法——数组作为整体参与 GROUP BYSELECT label, tags FROM array_example GROUP BY 1, 2MVD 写法——需先转为数组再分组否则会触发隐式展开SELECT label, MV_TO_ARRAY(tags) FROM mvd_example GROUP BY 1, 2按数组元素分组数组写法——使用CROSS JOIN UNNEST显式展开后按元素分组SELECT label, strings FROM array_example CROSS JOIN UNNEST(tags) as u(strings) GROUP BY 1, 2UNNEST 的语义细节见 SQL 文档的 UNNEST 章节它直接作用于 Druid ARRAY 列如果源列是 MVD 类型的 VARCHAR则必须先写MV_TO_ARRAY(dimension)转成数组UNNEST 会保留被展开数组的顺序。在原生查询层面Druid 通过名为j0.unnest的虚拟列实现展开每多一层 UNNEST 会追加一个下划线如_j0.unnest。MVD 写法——无需显式 UNNEST分组自动按元素展开隐式 UNNESTSELECT label, tags FROM mvd_example GROUP BY 1, 2过滤与分组组合的陷阱先过滤出含某个值的行再按数组/MVD 元素分组。这个例子说明过滤结果的命中行在数组与 MVD 下可能一致但由于 MVD 会隐式展开值一旦再加上 GROUP BY最终结果就会不同。以上一节按单个元素过滤的查询为例两边的过滤阶段都返回以下两行{label:row1,tags:[t1,t2,t3]} {label:row2,tags:[t3,t4,t5]}但给两边都加上GROUP BY 1, 2后查询变为-- 数组 SELECT label, tags FROM array_example WHERE ARRAY_CONTAINS(tags, t3) GROUP BY 1, 2 -- MVD SELECT label, tags FROM mvd_example WHERE tags t3 GROUP BY 1, 2数组查询返回数组作为整体分组保持两行{label:row1,tags:[t1,t2,t3]} {label:row2,tags:[t3,t4,t5]}而 MVD 查询返回过滤后隐式展开每行每个元素一组{label:row1,tags:t1} {label:row1,tags:t2} {label:row1,tags:t3} {label:row2,tags:t3} {label:row2,tags:t4} {label:row2,tags:t5}MVD 结果看起来多出了 4 行tags不等于t3的记录但这正是 Druid 对 MVD 等值判断的语义过滤先命中整行分组阶段再对整行所有元素逐一展开因此非目标元素也进入了结果。如果只想保留匹配过滤条件的元素MVD 场景应改用 MV_FILTER_ONLY仅保留数组中包含在指定列表内的值其孪生函数 MV_FILTER_NONE 则保留不在列表中的值SELECT label, MV_FILTER_ONLY(tags, ARRAY[t3]) FROM mvd_example WHERE tags t3 GROUP BY 1, 2同样的问题在原生查询中也有对应解法对 MVD 使用 groupBy 时可用 filtered dimensionSpectype: listFiltered把过滤下推到查询处理管线的最底层比在结果最外层套 having spec 高效得多。此外groupBy 查询上下文 中还有安全开关groupByEnableMultiValueUnnesting默认true当它被设为false时groupBy 引擎遇到多值列会直接报错而不是静默展开适合用于确信所有维度都是单值、希望引擎拒绝意外混入的多值维度的场景。如何将数据摄取为数组把 MVD 迁移到数组的第一步是让新摄入的数据落为ARRAY列。Druid 提供两条摄取路径原生批量与流式摄取使用原生 批量摄取 或 Kafka 等流式摄取 时在 dimensionsSpec 中配置维度设置useSchemaDiscovery: true并用dimensions以type: auto列出数组输入。auto类型维度与类型感知的 schema 发现机制共享见 Schema 设计文档。对于 TSV/CSV 数据可在inputFormat中用listDelimiter字段指定数组分隔符JSON 数据必须写成 JSON 数组才能按数组类型摄入且无需额外配置inputFormat。示例dimensionsSpecdimensions: [ { type: auto, name: label }, { type: auto, name: arrayString }, { type: auto, name: arrayLong }, { type: auto, name: arrayDouble } ],完整的原生摄取示例见 Ingesting arrays: Native batch and streaming ingestion。需要强调的反向结论同样来自 arrays.md若想刻意摄入 MVD原生场景应使用type: string且不要开启useSchemaDiscovery。SQL 批量摄取多阶段查询引擎使用 SQL 批量摄取 时在查询上下文参数中加入arrayIngestMode: array并在 EXTEND 子句 中为列声明对应数组类型VARCHAR ARRAY、BIGINT ARRAY或DOUBLE ARRAY。完整示例见 Ingesting arrays: SQL-based ingestion。以下是一个可直接运行的完整摄取语句REPLACE INTO array_example OVERWRITE ALL WITH ext AS ( SELECT * FROM TABLE( EXTERN( {type:inline,data:{\timestamp\: \2023-01-01T00:00:00\, \label\: \row1\, \arrayString\: [\a\, \b\], \arrayLong\:[1, null,3], \arrayDouble\:[1.1, 2.2, null]}\n{\timestamp\: \2023-01-01T00:00:00\, \label\: \row2\, \arrayString\: [null, \b\], \arrayLong\:null, \arrayDouble\:[999, null, 5.5]}}, {type:json} ) ) EXTEND ( timestamp VARCHAR, label VARCHAR, arrayString VARCHAR ARRAY, arrayLong BIGINT ARRAY, arrayDouble DOUBLE ARRAY ) ) SELECT TIME_PARSE(timestamp) AS __time, label, arrayString, arrayLong, arrayDouble FROM ext PARTITIONED BY DAY最佳实践输入 schema 中始终使用 ARRAY 数据类型。如果确实想摄入 MVD显式用 ARRAY_TO_MV 包裹字符串数组即可见 Multi-value dimensions: SQL-based ingestion。arrayIngestMode上下文参数详解arrayIngestMode用于兼容 Druid 31 之前版本的旧行为是迁移期的关键开关。其取值与存储结果见 multi-stage-query 上下文参数参考SQL 类型arrayIngestMode: array推荐/默认时的存储类型arrayIngestMode: mvd旧模式时的存储类型VARCHAR ARRAYARRAYSTRING多值STRING即 MVDBIGINT ARRAYARRAYLONG不支持校验报错DOUBLE ARRAYARRAYDOUBLE不支持校验报错需要特别说明两点默认值差异arrayIngestMode在查询上下文参数参考表中标注的默认值为mvd为向后兼容而 arrays.md 明确指出array模式是新表推荐的配置也是 Druid 31 及更新版本的默认配置。迁移时请显式设置arrayIngestMode: array以确保行为符合预期。mvd 模式的局限在mvd模式下VARCHAR ARRAY会被隐式包进ARRAY_TO_MV落为与普通标量字符串相同的STRING列类型BIGINT ARRAY与DOUBLE ARRAY根本无法在mvd模式下加载。官方不推荐该模式未来版本将移除。none模式同样受支持一旦开启任何类型的数组写入都会被拒绝并抛异常可用来在迁移期间强制杜绝数组数据。迁移期的类型混用校验skipTypeVerification在两种模式下Druid 校验 INSERT/REPLACE 语句时都会检查同一列是否同时混入了字符串数组与多值字符串。一旦检测到该情况语句会校验失败除非该列被列入skipTypeVerification上下文参数见 multi-stage-query 参考文档。该参数可以是逗号分隔的列名列表也可以是 JSON 数组字符串形式。此校验正是为了防止迁移过程中数组与 MVD 意外混存于同一列。如果你正在有意从一种类型迁移到另一种就用这个参数临时关闭对指定列的校验例如skipTypeVerification: tags,labels或skipTypeVerification: [\tags\, \labels\]迁移后如何确认列类型迁移完成后可以通过 INFORMATION_SCHEMA.COLUMNS 元数据表确认各列的实际类型SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME mytable数组列的类型显示为ARRAY多值字符串列的类型显示为VARCHAR多值字符串与普通字符串共用STRING列类型因此从元数据上无法区分标量与多值但可以据此确认它不是数组列。迁移决策建议综合官方迁移指南、arrays.md 与 multi-value-dimensions.md 中的结论给出如下决策清单新项目、多数据类型、需要保留行内值顺序直接用数组摄取时显式设置arrayIngestMode: array原生场景用type: auto维度 useSchemaDiscovery。存量 MVD 查询改写按本文示例逐条替换——元素过滤改用ARRAY_CONTAINS/ARRAY_OVERLAP等值过滤改用数组整体比较分组改用 UNNEST 或先MV_TO_ARRAY再分组需要过滤后再按元素分组且只保留命中元素时使用MV_FILTER_ONLY。刻意保留 MVD 的场景如直接按单个元素以普通字符串方式操作原生场景用type: string且不开启useSchemaDiscoverySQL 场景显式用ARRAY_TO_MV包裹字符串数组。迁移安全网利用skipTypeVerification处理过渡期的类型混用列利用groupByEnableMultiValueUnnesting: false阻止 groupBy 隐式展开多值列。随时校验通过INFORMATION_SCHEMA.COLUMNS确认列最终落为ARRAY还是VARCHAR避免以为是数组、其实是 MVD的隐性回归。总而言之数组是 Druid 中更现代、能力更强且符合 SQL 标准的特性MVD 则是为兼容旧行为而保留的特殊字符串形态。理解两者在整体 vs 逐元素语义上的根本区别是完成迁移、避免查询结果看起来不对的关键。赞分享数据库OLAP大数据后端【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址https://gitcode.com/gh_mirrors/druid6/druid点击查看免费下载相关推荐Apache Druid 元数据迁移指南从 Derby 平滑迁移到 MySQL / PostgreSQLApache Druid 元数据迁移指南从 Derby 平滑迁移到 MySQL / PostgreSQL 导读 本指南面向正在使用 Apache Druid数据库OLAP大数据后端SvelteKit 迁移指南从 Sapper 应用平滑迁移到 SvelteKitSvelteKit 迁移指南从 Sapper 应用平滑迁移到 SvelteKit SvelteKit 是 Sapper 的继任者二者在设计上共享大量元素但Web框架后端前端downshift v9迁移指南从类组件到Hooks的平滑过渡downshift v9迁移指南从类组件到Hooks的平滑过渡 你是否正面临从downshift类组件迁移到Hooks的挑战是否担心迁移过程中出现兼容性问题前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

G6 事件系统完全指南:从 Graph/Canvas/Element 事件监听到底层分发机制
G6 事件系统完全指南:从 Graph/Canvas/Element 事件监听到底层分发机制

数据可视化前端图表库 【免费下载链接】G6 ♾ A Graph Visualization Framework in JavaScript. 项目地址: https://gitcode.com/gh_mirrors/g6/G6 点击查看 免费下载 G6(antv/g6)的事件系统是在底层图形渲染引擎 G 为主线,结合仓… · 2026/9/24 0:36:16

基于去噪扩散模型的概率时空图预测:DiffSTG源码解析与实战
基于去噪扩散模型的概率时空图预测:DiffSTG源码解析与实战

简介:本资源为基于去噪扩散模型的概率时空图预测算法设计源码,面向从事时空数据建模、时间序列分析与概率预测的研究者和开发者,可用于交通流量、疾病传播、金融时序等动态场景的预测实验。压缩包共22个文件,约72.35MB&#xff0c… · 2026/9/24 0:35:52

嵌入式人工智能实战:在MCU上部署轻量模型实现端侧智能判断
嵌入式人工智能实战:在MCU上部署轻量模型实现端侧智能判断

1. 从一颗传感器说起:为什么“嵌入式人工智能”突然成了热词如果你这两年一直在做硬件、做设备、做工业现场的项目,应该能明显感觉到一个变化:以前客户问的是“你这个传感器精度多少、采样率多高、接口是 I2C 还是 SPI”,现在越来… · 2026/9/24 0:35:52

agent科研方向前沿探索与应用实践研究
agent科研方向前沿探索与应用实践研究

每次找到心仪的外国文献,却被付费墙冷冷地挡在外面,是不是感觉科研的热情瞬间被浇灭?作为学生党,我太懂这种无力感了。但好消息是,通过几个合法且免费的“通道”和技巧,我们完全能实现“文献自由”。今天分… · 2026/9/24 1:24:58

AIC8800DC WiFi6模组Linux驱动移植实战:SDIO识别与休眠唤醒排错指南
AIC8800DC WiFi6模组Linux驱动移植实战:SDIO识别与休眠唤醒排错指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:24:58

node防范sql注入
node防范sql注入

node防范sql注入// 写法1:字符串拼接 util.format const sql util.format(SELECT * FROM someTable WHERE id %s and name %s, req.params.id, req.params.name); connection.query(sql, function (err, results) {})// 写法2:占位符 ? 参数数组&… · 2026/9/24 1:24:58

STM32定时器Encoder模式驱动EC11旋转编码器:从原理到工程实践
STM32定时器Encoder模式驱动EC11旋转编码器:从原理到工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:24:52

高速铁路静态验收全解析:从TB 10760-2013到现场检查实操
高速铁路静态验收全解析:从TB 10760-2013到现场检查实操

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:24:45

互金PRD写作指南:从支付网关到资金安全的状态机设计
互金PRD写作指南:从支付网关到资金安全的状态机设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 1:24:39

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码