ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Apache Druid groupBy 查询结果过滤:Having 子句(HavingSpec)完整实战指南

Apache Druid groupBy 查询结果过滤:Having 子句(HavingSpec)完整实战指南 数据库数据分析OLAP大数据实时分析数据仓库后端【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址https://gitcode.com/gh_mirrors/druid7/druid点击查看免费下载Having 子句是 Apache Druid 中用于对 groupBy 查询聚合结果做行级过滤的 JSON 对象其语义与 SQL 的HAVING子句等价常用来实现只返回满足聚合值条件的分组这类查询需求。本文以 docs/content/querying/having.md 为主体骨架完整覆盖其全部过滤类型与 JSON 语法并结合 processing 模块下的HavingSpec源码实现、GroupByQuery 查询解析逻辑及对应测试讲透每种过滤器的配置方式、底层比较规则与使用注意事项帮助你在实际查询中正确编写和调试 having 子句。一、Having 子句是什么在 SQL 中WHERE作用于原始行而HAVING作用于聚合后的分组结果。Druid 的 having 子句与之对应它也是一个 JSON 对象通过指定聚合值上的条件决定 groupBy 查询返回哪些行即哪些分组。以 GroupByQuery.java 中的定义为依据having 子句作为 groupBy 查询 JSON 的一个可选顶层属性存在JsonProperty(having) HavingSpec havingSpec,在查询执行阶段Druid 会先完成分组与聚合再对每个结果行调用HavingSpec.eval(Row)判断该行是否满足条件见 GroupByQuery.java只有eval返回true的行才会进入最终结果。也就是说having 过滤发生在聚合之后、limit 截断之前。Druid 通过JsonTypeInfo(use JsonTypeInfo.Id.NAME, property type)以type字段反序列化不同的 having 子句HavingSpec接口HavingSpec.java中注册的全部类型如下type取值对应实现类语义andAndHavingSpec逻辑与orOrHavingSpec逻辑或notNotHavingSpec逻辑非greaterThanGreaterThanHavingSpec聚合值大于给定值lessThanLessThanHavingSpec聚合值小于给定值equalToEqualToHavingSpec聚合值等于给定值dimSelectorDimensionSelectorHavingSpec维度值等于给定值alwaysAlwaysHavingSpec恒真主要用于测试组合filterDimFilterHavingSpec复用任意 Druid 查询过滤器其中always和not对应的NeverHavingSpec、AlwaysHavingSpec被作为组合单元暴露在HavingSpec接口中HavingSpec.NEVER/HavingSpec.ALWAYS见 HavingSpec.java主要用于逻辑组合与测试。下面按类别逐一介绍每种语法的 JSON 写法。二、查询过滤器Query Filter HavingSpectype 为 filter查询过滤器类型的 HavingSpec 允许把任意 Druid 查询过滤器直接用在 having 部分。其语法为{ type : filter, filter : any Druid query filter }例如使用一个 selector 过滤器{ type : filter, filter : { type: selector, dimension : dimension, value : dimension_value } }从源码实现看DimFilterHavingSpec.javafilter属性是必填的构造器通过Preconditions.checkNotNull(dimFilter, filter)校验它会把传入的DimFilter转成ValueMatcher后再对每一行做匹配因此凡是 filters.md 中列出的过滤器类型selector、regex、bound、javascript 等都可在此复用。特别注意__time字段的差异filter类型的 HavingSpec 作用于输出字段名为__time时行为与其他 HavingSpec 不同——它作用于每一行的时间戳而不是名为__time的输出字段。官方文档明确建议避免将输出字段命名为__time未来版本的 Druid 可能会强制执行这一约束。三、数值过滤器Numeric Filters数值过滤器是最简单的 having 子句直接对聚合指标与给定数值做比较同时也可作为更复杂的布尔表达式过滤器的底层基础。示例{ type: greaterThan, aggregation: myAggMetric, value: 100 }其中aggregation指定要比较的聚合指标名即 groupBy 查询中aggregations数组里定义的输出名value为数值。下面介绍三种数值过滤器。3.1 equalTo等于匹配聚合值等于给定值的行{ type: equalTo, aggregation: aggregate_metric, value: numeric_value }等价于 SQL 的HAVING aggregate value。3.2 greaterThan大于匹配聚合值大于给定值的行{ type: greaterThan, aggregation: aggregate_metric, value: numeric_value }等价于 SQL 的HAVING aggregate value。3.3 lessThan小于匹配聚合值小于给定值的行{ type: lessThan, aggregation: aggregate_metric, value: numeric_value }等价于 SQL 的HAVING aggregate value。3.4 数值比较的底层实现三种数值过滤器最终都通过同一个工具类HavingSpecMetricComparatorHavingSpecMetricComparator.java完成比较其规则如下若聚合结果以Long存储则用Longs.compare(long, value.longValue())做整型比较若聚合结果是字符串且完全匹配整型正则[-|]?\dLONG_PAT则按getLongMetric取出的长整型值比较其他情况浮点等统一回退为Floats.compare(float, value.floatValue())的浮点比较。因此当聚合指标值很大超出浮点精度或希望做精确整型比较时Druid 会优先走整型路径避免精度损失。对应的序列化/反序列化与组合行为在 HavingSpecTest.java 中有完整测试覆盖例如GreaterThanHavingSpec(agg, 1.3)、LessThanHavingSpec与NotHavingSpec组合的序列化验证。四、维度选择过滤器Dimension Selector FilterdimSelector类型的 having 子句匹配维度值等于给定值的行{ type: dimSelector, dimension: dimension, value: dimension_value }注意它与数值过滤器不同数值过滤器比较的是聚合指标而dimSelector比较的是分组维度本身。从实现看DimensionSelectorHavingSpec.javadimension为必填属性构造器通过checkNotNull校验可选属性extractionFn用于在比较前对维度值做提取转换未指定时默认使用IdentityExtractionFn恒等变换由于 Druid 支持多值维度eval会遍历该维度行的所有取值任一值经extractionFn提取后与value相等即命中若维度行值为空且value也为 null/空串同样视为命中。因此可以在 having 阶段结合 extraction functions 做大小写归一、正则提取等复杂匹配。五、逻辑表达式过滤器Logical Expression Filters与 SQL 的AND/OR/NOT对应Druid 提供三种逻辑组合器其内部havingSpecs/havingSpec可以嵌套任意本页介绍的其他 having 子句包括再嵌套逻辑组合。5.1 AND{ type: and, havingSpecs: [having clause, having clause, ...] }havingSpecs中的每个子句可以是本页定义的任意 having 子句。从 AndHavingSpec.java 的实现看它是短路求值的遍历子句一旦某个子句eval返回false立即返回false。5.2 OR{ type: or, havingSpecs: [having clause, having clause, ...] }同样支持任意嵌套。对应 OrHavingSpec.java 的实现也是短路求值任一子句eval返回true即整体为true。5.3 NOT{ type: not, havingSpec: having clause }对单个子句的结果取反见 NotHavingSpec.java。5.4 组合示例利用逻辑组合可以写出等价于复杂 SQL 的过滤条件。例如返回count大于 100 且avg_price小于 10 或category等于 book{ type: and, havingSpecs: [ { type: greaterThan, aggregation: count, value: 100 }, { type: or, havingSpecs: [ { type: lessThan, aggregation: avg_price, value: 10 }, { type: dimSelector, dimension: category, value: book } ] } ] }六、完整 groupBy 查询示例把 having 子句放入 groupBy 查询 JSON 的having顶层属性即可对聚合结果过滤。下面是一个完整的查询聚合定义参考 aggregations.mdgroupBy 查询整体结构参考 groupbyquery.md{ queryType: groupBy, dataSource: wikiticker, granularity: day, dimensions: [channel], aggregations: [ {type: count, name: edits}, {type: longSum, name: added, fieldName: added} ], having: { type: and, havingSpecs: [ {type: greaterThan, aggregation: edits, value: 50}, {type: lessThan, aggregation: added, value: 100000} ] }, intervals: [2015-09-12T00:00:00.000Z/2015-09-13T00:00:00.000Z] }该查询按channel分组统计每日编辑次数与新增字符数最终只返回编辑次数大于 50 且新增字符数小于 100000的频道分组效果等价于 SQL 的GROUP BY channel HAVING edits 50 AND added 100000。七、使用注意事项与性能提示线程安全HavingSpec对象本身不是线程安全的javadoc 与 GroupByQuery.java 的applyLimit注释均明确提示不应被多个线程同时使用也不要在两个不同线程中同时累积本方法返回的两个Sequence。DimFilterHavingSpec更是在eval内部通过evalCount自增检查检测并发调用一旦发现并发会抛出IllegalStateException(concurrent eval calls not permitted!)见 DimFilterHavingSpec.java。输出字段命名避免把输出字段命名为__time因为filter类型 HavingSpec 对它存在特殊语义作用于行时间戳而非字段值。比较精度数值比较优先走整型路径见第三节对长整型聚合结果更精确浮点场景则按 float 比较若对精度敏感需在设计聚合时留意。缓存每种 HavingSpec 都实现了getCacheKey()如equalTo为0x3、greaterThan为0x4、lessThan为0x5、dimSelector为0x8、filter为0x9参与查询缓存键的生成因此不同 having 条件会生成不同的缓存条目可放心使用。八、进一步阅读本文主体docs/content/querying/having.md可复用的查询过滤器清单docs/content/querying/filters.mdgroupBy 查询完整结构与其余属性docs/content/querying/groupbyquery.md聚合定义与输出名docs/content/querying/aggregations.mdHavingSpec 接口与类型注册processing/src/main/java/io/druid/query/groupby/having/HavingSpec.java查询解析与执行入口processing/src/main/java/io/druid/query/groupby/GroupByQuery.java序列化与组合行为测试processing/src/test/java/io/druid/query/groupby/having/HavingSpecTest.java赞分享数据库数据分析OLAP大数据实时分析数据仓库后端【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址https://gitcode.com/gh_mirrors/druid7/druid点击查看免费下载相关推荐Apache Druid groupBy 查询 Having 子句完全指南聚合后过滤的 JSON 语法与源码实现Apache Druid groupBy 查询 Having 子句完全指南聚合后过滤的 JSON 语法与源码实现 本篇技术指南聚焦 Apache Druid数据库OLAP大数据后端Apache Druid groupBy 查询的 LimitSpec 完全指南排序与结果限制Apache Druid groupBy 查询的 LimitSpec 完全指南排序与结果限制 limitSpec 是 Apache Druid 原生nati数据库OLAP大数据后端Apache Druid 查询指南使用 LimitSpec 对 groupBy 查询结果排序与限量Apache Druid 查询指南使用 LimitSpec 对 groupBy 查询结果排序与限量 limitSpec 是 Apache Druid grou数据库数据分析OLAP大数据实时分析数据仓库后端上一篇react-jsonschema-form中的表单数据处理完成回调下一篇Odyssey Theme如何用 Astro 打造完美 Lighthouse 评分的现代商业网站创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表