Apache Druid摄入无根数组JSON时仅返回单行的解决方案问询
问题根因
- Druid的
json类型inputFormat下的flattenSpec仅支持单输入行内的字段提取,不会将jq表达式返回的多值数组按元素拆分多行,只会将数组作为单条记录的多值字段存储。 - 原配置中
.[].name、.[].lastseen这类字段级jq表达式,返回的是包含所有记录值的数组,最终被合并到单条记录里,仅默认展示数组第一个元素,因此仅返回单行数据。 - 原配置未保留根层级的服务端记录ID,也未处理嵌套的
state对象,字段覆盖不全。
实现方案
无需修改源服务、无需搭建中间代理,直接通过Druid原生摄入配置实现行级拆解。
Druid 0.20+ 适配(支持独立jq inputFormat)
直接用jq类型inputFormat做预处理,将原始根对象转为设备记录数组,由Druid自动拆分多行摄入,完整配置:
"inputFormat": { "type": "jq", "expr": "to_entries | map({device_id: .key} + .value + (.state | to_entries | from_entries))", "inputFormat": { "type": "json", "keepNulls": true } }
表达式逻辑
to_entries:将根对象的键值对(如"1": {设备对象})转为包含key(服务端记录ID)、value(设备对象)的条目数组- 逐条目构造标准化对象:
- 新增
device_id字段,值为原根键对应的服务端记录ID - 合并设备对象本身的
lastseen、name字段 - 展开嵌套的
state对象,将alert、level、on、reachable转为顶层字段
- 新增
- 内层
jsoninputFormat会自动将jq输出的数组每个元素解析为独立摄入行,无需额外拆分配置。
可选调整
如果需要保留state为嵌套对象,不做展开,可将expr简化为:
to_entries | map({device_id: .key} + .value)
后续如需提取嵌套内的字段,再通过flattenSpec的JSONPath配置即可。
低版本Druid适配(仅支持json inputFormat下的jq flattenSpec)
如果版本不支持独立jq inputFormat,可按以下步骤配置:
- 在
flattenSpec中通过jq表达式将整个根对象转为单字段数组:
"flattenSpec": { "fields": [ { "type": "jq", "expr": "to_entries | map({device_id: .key} + .value + (.state | to_entries | from_entries))", "name": "device_array" } ] }
- 通过Transform Spec的数组展开逻辑,将
device_array的每个元素拆为独立行,同时提取嵌套字段,无需调整拉取逻辑。
效果说明
- 每次周期性拉取的根对象中包含的所有有效记录(如ID=1、3、4)都会被拆为独立摄入行
- 已被服务端删除的ID不会出现在拉取结果中,不会生成冗余摄入行
- 最终摄入的字段包含
device_id、lastseen、name、alert、level、on、reachable,完全覆盖源数据结构
内容的提问来源于stack exchange,提问作者Tell
相关产品推荐
相关产品推荐

