Apache Calcite Druid Adapter:含时间运算的FLOOR无法识别有效原点
问题描述
我尝试使用Apache Calcite对Druid数据源执行以下查询:
SELECT FLOOR( ("__time" + INTERVAL '5' HOUR + INTERVAL '30' MINUTE) TO DAY ) AS "createtime.day", COUNT(*) AS "count" FROM "druid"."myevent_activated";
目标是将__time列调整为UTC+5:30时区后按天取整,但通过Calcite Druid适配器运行时出现错误:当在FLOOR函数内执行时间运算(如添加5.5小时)时,适配器无法确定取整操作的有效“原点”(起始时间)。
经排查:
- 正确行为:适配器应传入null作为原点,让Druid使用默认纪元时间
- 错误行为:适配器传入空字符串
''作为原点,导致执行失败
核心问题
- 有无办法在Apache Calcite与Druid中执行时间运算和FLOOR操作而不触发该错误?
- 有无替代方法(函数或原生查询)可实现相同的时区调整和按天取整效果?
- 这是否是Calcite Druid适配器的已知Bug,近期版本是否有修复?
注:已知原生Druid查询中的TIME_FLOOR可正常处理此场景,但需通过Calcite SQL实现。
解决方案与解答
1. 避免错误的临时修复方案
可以通过调整SQL结构,将时间偏移运算移到FLOOR函数外部,避免嵌套运算触发适配器的原点判断逻辑:
SELECT FLOOR("adjusted_time" TO DAY) AS "createtime.day", COUNT(*) AS "count" FROM ( SELECT "__time" + INTERVAL '5' HOUR + INTERVAL '30' MINUTE AS "adjusted_time" FROM "druid"."myevent_activated" ) t;
这种方式下,FLOOR函数的参数是子查询中已计算完成的时间列,适配器会正确识别并传入null作为原点。
如果有权限修改适配器代码,可直接调整DruidSqlConverter中处理FLOOR时间取整的逻辑,将默认原点从空字符串改为null。
2. 替代实现方法
- 使用时区转换函数:如果Calcite版本支持
AT TIME ZONE语法,可直接通过时区转换替代手动加减间隔,更简洁且不易出错:
SELECT FLOOR("__time" AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata' TO DAY) AS "createtime.day", COUNT(*) AS "count" FROM "druid"."myevent_activated";
Asia/Kolkata对应UTC+5:30时区,直接完成时区转换后再按天取整。
- 调用Druid原生TIME_FLOOR函数:通过Calcite映射Druid原生函数,直接传入时区参数:
SELECT TIME_FLOOR("__time", 'P1D', NULL, '+05:30') AS "createtime.day", COUNT(*) AS "count" FROM "druid"."myevent_activated";
需确保Calcite Druid适配器已配置支持原生函数调用,部分版本可能需要在配置文件中添加函数映射规则。
3. Bug状态与版本修复情况
这是Calcite Druid适配器的已知Bug,在Apache Calcite官方Issue跟踪系统中已有记录。Calcite 1.32.0及以后的版本已修复该问题,修复逻辑为:当无法自动推导FLOOR取整的原点时,默认传递null而非空字符串,适配Druid的默认行为。建议升级到最新稳定版Calcite来彻底解决此问题。
内容的提问来源于stack exchange,提问作者Sachithra Dilshan
相关产品推荐
相关产品推荐

