news 2026/9/23 23:17:40

Apache Druid 查询指南:REST 协议、查询类型、取消与错误处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Apache Druid 查询指南:REST 协议、查询类型、取消与错误处理
  • 数据库
  • 数据分析
  • OLAP
  • 大数据
  • 实时分析
  • 数据仓库
  • 后端

【免费下载链接】druid

Apache Druid: a high performance real-time analytics database.

项目地址:https://gitcode.com/gh_mirrors/druid7/druid
点击查看免费下载

Druid 的原生查询语言是"基于 HTTP 的 JSON",所有查询都通过 HTTP REST 风格的请求发送到可查询节点(Broker、Historical 或 Realtime)。本文是 Druid 查询的总览手册:你将掌握查询的 HTTP 协议格式、九种原生查询类型的适用场景、查询 ID 的生成与取消机制,以及查询失败时的错误响应结构——这些知识是后续深入阅读各类查询文档、编写客户端或排查线上问题的基础。

Apache Druid 数据流架构示意图

查询的 HTTP 协议:JSON over HTTP

Druid 查询使用 HTTP REST 风格请求,发送到可查询节点(Broker、Historical 或 Realtime)。查询体以 JSON 表达,且这三种节点暴露的是同一个 REST 查询接口

在正常运维场景下,查询应统一发往 Broker 节点;只有在排查特定节点行为或做内部调试时才直接查询 Historical / Realtime。发起查询的标准方式是使用curl向查询接口 POST 一个 JSON 文件:

curl -X POST '<queryable_host>:<port>/druid/v2/?pretty' -H 'Content-Type:application/json' -d @<query_json_file>

几个关键点:

  • 端口差异:Broker 与 Router 的默认 HTTP 端口是8082,Historical 是8083,Realtime(实时索引任务)是8084。实际端口以各自节点的runtime.properties配置为准,例如 examples/conf/druid/broker/runtime.properties 中 Broker 的druid.port=8082
  • ?pretty参数:可选,加上后返回的 JSON 会以缩进格式输出,便于阅读调试。
  • Content-Type:请求头必须设置为application/json。Druid 同样支持 Smile 的@Produces/@Consumes声明中有明确体现。

从源码角度印证:io.druid.server.QueryResource类以@Path("/druid/v2/")注解暴露查询端点(见 QueryResource.java),其doPost方法接收输入流、用 JSON/Smile 对应的ObjectMapper反序列化为Query对象,再交给QuerySegmentWalker执行,最终以流式(StreamingOutput)方式把结果写回客户端。Historical 与 Peon 注册的是基础版QueryResource,而 Broker 注册的是其子类BrokerQueryResource(见 CliBroker.java 与 CliHistorical.java),后者额外提供了/druid/v2/candidates调试端点,用于查看某查询会被路由到哪些服务器(BrokerQueryResource.java)。

Druid 的原生查询是相对底层的,它与 Druid 内部的执行模型紧密对应,设计目标就是轻量、快速完成。这意味着对于更复杂的分析或更复杂的可视化,往往需要把多个 Druid 查询组合起来使用,而不是在一个查询里塞进全部逻辑。

说明:由于原生查询语言是 JSON over HTTP,社区已经为其他语言贡献了大量客户端库(Java、Python、JavaScript 等),方便以编程方式查询 Druid。

原生查询类型总览

Druid 针对不同使用场景提供了多种查询类型,每种类型由一组 JSON 属性构成,属性含义在各查询类型的专项文档中详细描述。所有查询类型共享queryTypedataSourceintervals等公共字段,其中queryType是 Druid 判断如何解释查询的第一依据。

分类查询类型核心用途专项文档
聚合查询Timeseries按时间粒度做聚合,不按维度分组timeseriesquery.md
聚合查询TopN对单个维度按指标排序取前 N 名topnquery.md
聚合查询GroupBy最灵活的聚合查询,支持多维度分组与排序groupbyquery.md
元数据查询Time Boundary返回数据源中数据的时间边界timeboundaryquery.md
元数据查询Segment Metadata返回某个时间段内的 Segment 元数据segmentmetadataquery.md
元数据查询Datasource Metadata返回数据源的元数据(如更新时间戳)datasourcemetadataquery.md
搜索查询Search返回匹配搜索规范的维度值searchquery.md

所有查询都共享一组上下文参数(query context),用于配置超时、优先级、缓存、调试行为等,详见下文"查询上下文"一节;dataSourcegranularityfilterintervals等公共概念则分别由 datasource.md、granularities.md、filters.md 等文档定义。

下面通过三个示例快速感受查询 JSON 的形态。

Timeseries 查询——按小时聚合page_views数据源中的added指标:

{ "queryType": "timeseries", "dataSource": "page_views", "granularity": "hour", "aggregations": [ { "type": "count", "name": "rows" }, { "type": "longSum", "name": "added", "fieldName": "added" } ], "intervals": [ "2015-09-12T00:00:00.000Z/2015-09-13T00:00:00.000Z" ] }

TopN 查询——按维度page分组、以added求和降序取前 10:

{ "queryType": "topN", "dataSource": "page_views", "granularity": "all", "dimension": "page", "metric": "added", "threshold": 10, "aggregations": [ { "type": "longSum", "name": "added", "fieldName": "added" } ], "intervals": [ "2015-09-12T00:00:00.000Z/2015-09-13T00:00:00.000Z" ] }

Search 查询——在dim1dim2上查找包含子串Ke的维度值(不区分大小写),完整字段说明见 searchquery.md:

{ "queryType": "search", "dataSource": "sample_datasource", "granularity": "day", "searchDimensions": [ "dim1", "dim2" ], "query": { "type": "insensitive_contains", "value": "Ke" }, "sort": { "type": "lexicographic" }, "intervals": [ "2013-01-01T00:00:00.000/2013-01-03T00:00:00.000" ] }

如何选择查询类型

在可能的情况下,官方推荐优先使用TimeseriesTopN,而不是 GroupBy。三者的定位差异非常明确:

场景推荐查询原因
只需要按时间聚合、不需要按维度分组Timeseries远快于 GroupBy
需要按单个维度分组并排序取前 NTopN针对单维度做了大量优化,明显优于 GroupBy
需要多维度分组、复杂排序、过滤后的深度分析GroupBy最灵活,但性能也最差

简而言之:GroupBy 是 Druid 最灵活的查询,但也是性能最差的。如果查询不需要维度分组,请选择 Timeseries;如果只需要单个维度上的排序取 topN,请选择 TopN。

需要指出,上述"灵活性最高、性能最差"是相对同仓库内 Timeseries / TopN 实现而言的官方建议(原文出处见 querying.md),并非与其他数据库产品的横向对比。TopN 的实现之所以高效,是因为它采用了"分段局部 topN + 全局归并"的策略:每个数据段先各自算出局部 topN(段内结果数由上下文参数minTopNThreshold控制,默认 1000),再把局部结果归并得到全局 topN——这与 GroupBy 需要维护全量分组哈希表的开销形成鲜明对比。

查询上下文(Query Context)

查询 JSON 中可以携带一个context对象,用于配置各项运行参数。以下参数适用于所有查询类型(完整定义见 query-context.md):

属性默认值说明
timeout0(无超时)查询超时时间(毫秒),超过后未完成的查询将被取消。
priority0查询优先级,高优先级查询在计算资源竞争中获得优先处理。
queryId自动生成查询的唯一标识;若已设置或已知,可用于取消查询(见下文)。
useCachetrue是否使用查询缓存,可在 Broker / Historical 节点配置中覆盖。
populateCachetrue是否将查询结果写入查询缓存,主要用于调试;可在节点配置中覆盖。
bySegmentfalse是否按数据段(segment)返回结果,主要用于调试,开启后返回结果会附带来源段信息。
finalizetrue是否"终结"聚合结果,主要用于调试。例如置为falsehyperUnique聚合器返回完整的 HyperLogLog sketch 而非预估基数。
chunkPeriodP0D(关闭)仅 Broker 有效:长区间查询会被拆分为较短区间的子查询并行归并。使用 ISO 8601 周期,例如设为P1M时覆盖一年的查询会被拆成 12 个小查询。拆分后的查询会占用更多集群资源,但可能显著更快。注意 Broker 使用查询处理线程池发起分块,因此需保证 Broker 的druid.processing.numThreads配置充足。GroupBy 默认不支持chunkPeriod(使用旧的 v1 引擎时除外)。

各查询类型还有专属上下文参数:TopN 有minTopNThreshold(默认1000,控制每个段返回参与全局归并的局部结果数);Timeseries 有skipEmptyBuckets(默认false,置为true可关闭零填充,只返回有结果的桶);GroupBy 的上下文参数见 groupbyquery.md。

从源码实现看,timeoutqueryId的处理在 QueryResource.java 中:请求到达后,若查询未携带queryId,服务端会为其生成一个 UUID;若未携带timeout,则默认使用ServerConfig.getMaxIdleTime()对应的毫秒数作为超时。这也解释了为什么即使客户端不设置上下文,服务端也能对查询做超时控制与后续取消。

查询取消(Query Cancellation)

Druid 支持通过查询的唯一标识显式取消查询。只要在发起查询时设置了queryId(或该 ID 已知),就可以在Broker 或 Router上调用如下端点取消:

DELETE /druid/v2/{queryId}

例如,假设查询 ID 为abc123

curl -X DELETE "http://host:port/druid/v2/abc123"

底层的取消链路非常清晰:

  1. QueryResourcegetServer方法映射@DELETE @Path("{id}")(QueryResource.java),调用QueryManager.cancelQuery(queryId),成功后返回 HTTP 202(ACCEPTED);
  2. QueryManager.java 内部以SetMultimap<String, ListenableFuture>维护queryId → 查询 Future的映射,cancelQuery取出该 ID 关联的所有ListenableFuture并逐个执行future.cancel(true)(以中断方式取消),同时在查询完成监听器中自动清理映射条目;
  3. 查询真正被取消时,执行端会抛出CancellationException,最终被包装为error: "Query cancelled"的错误响应(见下文)。

安全说明:从 QueryResource.java 的实现可以看到,若集群开启了鉴权(AuthConfig.isEnabled()),取消请求需要携带有效的授权信息,且调用者必须对查询涉及的每个数据源拥有WRITE权限(授权机制见 AuthConfig 相关实现 以及 docs/content/design/coordinator.md 中的安全配置指引),否则会返回 403FORBIDDEN

查询错误与响应结构

如果查询执行失败,节点会返回HTTP 500响应,响应体是一个 JSON 对象,结构如下:

{ "error" : "Query timeout", "errorMessage" : "Timeout waiting for task.", "errorClass" : "java.util.concurrent.TimeoutException", "host" : "druid1.example.com:8083" }

各字段含义:

字段说明
error定义良好的错误码(取值见下表)。
errorMessage关于错误的自由格式信息,可能为 null。
errorClass引发错误的异常类,可能为 null。
host错误发生的节点主机名,可能为 null。

error字段可能的取值:

错误码说明
Query timeout查询超时。
Query interrupted查询被中断,可能由 JVM 关闭等原因导致。
Query cancelled查询通过取消 API 被取消。
Resource limit exceeded查询超过了配置的资源限制(例如 groupBy 的maxResults)。
Unknown exception其他异常。请查看errorMessageerrorClass获取详情,但注意这两个字段是自由格式的,内容可能随版本变化。

源码级印证:错误响应的 JSON 序列化由io.druid.query.QueryInterruptedException完成(QueryInterruptedException.java)。这个类虽然名字叫"Interrupted",但实际上是客户端侧所有查询失败的统一表示:它通过@JsonProperty注解把errorerrorMessageerrorClasshost四个字段序列化为上述 JSON 结构。其错误码推导逻辑(getErrorCodeFromThrowable)正是按异常类型映射到上表:

  • TimeoutExceptionQuery timeout
  • InterruptedExceptionQuery interrupted
  • CancellationExceptionQuery cancelled
  • ResourceLimitExceededExceptionResource limit exceeded
  • 其余所有异常 →Unknown exception

在服务端,QueryResource.java 的gotError方法通过QueryInterruptedException.wrapIfNeeded(e)把任意异常包装成统一格式并返回Response.serverError()(即 HTTP 500)。客户端侧,Broker 的DirectDruidClient会反序列化并包装这些错误对象(见 DirectDruidClient.java 对druid/v2的请求处理),从而把集群内部的错误逐层传递回调用方。此外,QueryResource.java 会在错误发生时向监控系统发射query/time(success=false)指标并写入请求日志,便于事后排查。

进阶指引

本文覆盖了 Druid 查询的公共协议与通用机制。当你需要编写具体查询时,建议按以下路径深入:

  1. 公共概念:datasource.md(数据源定义)、granularities.md(时间粒度)、filters.md(过滤)、dimensionspecs.md(维度规范)、aggregations.md(聚合器)、post-aggregations.md(后聚合)、limitspec.md(排序与截断)。
  2. 各查询类型:分别阅读 timeseriesquery.md、topnquery.md、groupbyquery.md、searchquery.md 以及三个元数据查询文档。
  3. 高级能力:joins.md(查询时关联)、multitenancy.md(多租户)、caching.md(缓存行为)、query-context.md(上下文参数全集)。
  4. 其他访问方式:Druid 还提供了 SQL 查询层;如果你需要了解各服务节点的职责与配置,可阅读 Broker 设计文档 与 Historical 设计文档。
  • 数据库
  • 数据分析
  • OLAP
  • 大数据
  • 实时分析
  • 数据仓库
  • 后端

【免费下载链接】druid

Apache Druid: a high performance real-time analytics database.

项目地址:https://gitcode.com/gh_mirrors/druid7/druid
点击查看免费下载
上一篇:告别样式混乱:用Style Dictionary打造统一的设计语言系统
下一篇:CI/CD集成:Klavis AI自动化部署最佳实践

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 23:12:16

基于Jupyter Notebook的Python用户画像构建:RFM实战指南

简介&#xff1a;这套基于Jupyter Notebook的Python用户画像构建源码&#xff0c;面向希望系统性学习用户画像的数据分析师、产品运营及Python开发者&#xff0c;可帮助读者从原始用户行为数据出发&#xff0c;完成多维度画像标签的快速构建。资源包共20个文件&#xff0c;含13…

作者头像 李华
网站建设 2026/9/23 23:09:42

PHPStan function.duplicate 错误详解:同名函数重复声明检测与修复

开发工具代码质量静态分析 【免费下载链接】phpstan PHP Static Analysis Tool - discover bugs in your code without running it! 项目地址&#xff1a; https://gitcode.com/gh_mirrors/ph/phpstan 点击查看 免费下载 function.duplicate 是 PHPStan 静态分析工具在分析过程…

作者头像 李华
网站建设 2026/9/23 23:09:39

Python酒店评论情感分析:从数据清洗到模型调优完整攻略

简介&#xff1a;面向高校Python课程期末大作业与自然语言处理入门实践&#xff0c;该项目以酒店评论为具体数据对象&#xff0c;完整覆盖评论文本清洗、情感词典构建、分词处理、情感得分计算、词云展示与结论汇报等主要环节&#xff0c;能够帮助学习者系统理解中文情感分析的…

作者头像 李华
网站建设 2026/9/23 23:09:27

Flutter与鸿蒙开发环境搭建指南

1. 环境搭建前的认知准备鸿蒙操作系统作为新一代智能终端操作系统&#xff0c;其分布式能力和全场景特性为开发者带来了全新机遇。而Flutter作为跨平台开发框架&#xff0c;其高效的渲染引擎和丰富的组件库使其成为移动开发的热门选择。将两者结合&#xff0c;可以充分发挥Flut…

作者头像 李华
网站建设 2026/9/23 23:03:36

辗转相减法:GCD计算原理与优化实践

1. 算法背景与数学原理辗转相减法&#xff08;又称更相减损术&#xff09;是计算两个正整数最大公约数(GCD)的经典算法&#xff0c;其历史可追溯至中国古代的《九章算术》。与辗转相除法相比&#xff0c;这种方法仅使用减法运算&#xff0c;更适合在计算资源有限的环境下实现。…

作者头像 李华