ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Apache Druid 数据查询实战:使用 Druid SQL 从 Web 控制台到 HTTP API

Apache Druid 数据查询实战:使用 Druid SQL 从 Web 控制台到 HTTP API Apache Druid 数据查询实战使用 Druid SQL 从 Web 控制台到 HTTP API【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid本篇技术指南以 Apache Druid 的官方查询教程docs/tutorials/tutorial-query.md为核心系统讲解如何在 Druid 中通过 Druid SQL 查询已导入的数据。你将掌握三种主流查询方式——Web 控制台可视化查询、命令行与 HTTP POST 提交查询、以及通过 EXPLAIN PLAN 深入理解 SQL 到原生查询native query的转换机制并学会使用时间区间过滤、聚合与分组等高频 SQL 技巧最终能够独立完成从写出一条查询到在生产环境排查查询性能的完整链路。前置条件先加载一份数据本教程演示如何在 Apache Druid 中使用 SQL 查询数据前提是你已经按照 本地 Quickstart 教程 完成了集群启动与数据导入或完成了以下任一数据加载教程因为我们要查询的wikipedia数据源正是由它们创建的使用原生批量导入加载文件从 Kafka 加载流式数据使用 Hadoop 加载文件以 Quickstart 为例它使用bin/start-druid启动单机集群包含 ZooKeeper、Broker、Router、Coordinator-Overlord、Historical、MiddleManager 等服务随后在 Web 控制台的Query视图中通过 MSQ 任务引擎执行REPLACE INTO ... OVERWRITE ALL语句将quickstart/tutorial/目录下的wikiticker-2015-09-12-sampled.json.gz示例数据2015-09-12 当天的维基百科页面编辑记录导入到名为wikipedia的数据源。导入完成后数据服务器的段segment会被加载此时即可开始查询。Druid 支持两种查询语言Druid SQL与原生查询native query。本教程聚焦 Druid SQL它基于 Apache Calcite 将 SQL 解析并翻译为原生 JSON 查询后在数据节点上执行。查询可以通过三种方式发起Web 控制台、命令行工具、HTTP POST 请求下面逐一展开。从 Web 控制台执行 SQL 查询Web 控制台内置了Query视图它既能让你直接编写并运行 SQL也提供了丰富的查询构建辅助功能数据源/列/函数自动补全、可视化筛选、执行计划查看等非常适合交互式地搭建和验证查询。如果 Druid 集群尚未启动先执行./bin/start-druid启动然后在浏览器中打开 Web 控制台默认地址http://localhost:8888。点击顶部导航栏的Query打开查询视图Druid Web 控制台 Query 视图你可以随时在编辑区直接编写查询但 Query 视图同时提供了辅助构建 SQL 的功能下面我们用它来生成一条起始查询。展开左侧面板中的wikipedia数据源树可以看到该数据源下的所有列如page、countryName、channel、__time等。我们将针对page维度创建查询。点击page列从弹出的菜单中选择Show:page从数据源树选择 page 列生成 SELECT 查询编辑区会立即生成一条SELECT查询并自动运行。不过此时查询通常返回空结果——因为默认情况下控制台生成的查询会带有最近一天的时间过滤条件__time限定在CURRENT_TIMESTAMP - INTERVAL 1 DAY区间而示例数据的时间是 2015 年远早于当前时间。接下来移除这个过滤条件。点击Run运行查询。此时应能看到两列数据page页面名与Count计数查询结果展示 page 与 Count 两列注意控制台默认会将结果限制在约 100 行以内这是Smart query limit特性在起作用。该特性用于避免用户无意中运行返回海量数据的查询、从而压垮系统。现在直接在编辑区修改查询体验更多编辑器特性在第一列page之后新增一行输入新列名countryName。注意输入时会弹出自动补全菜单提示可用的列名、函数、关键字等选择 countryName。同时将该列加入GROUP BY子句——既可按名称countryName也可按其在 SELECT 列表中的位置2引用。为了可读性把Count列改名为Edits因为COUNT()函数实际返回的是该页面的编辑次数ORDER BY子句中的列名也要同步修改。COUNT()只是 Druid SQL 众多聚合函数中的一员。将鼠标悬停在自动补全菜单中的函数名上可以查看简要说明完整的聚合函数清单与语义见 SQL 聚合函数文档。例如COUNT(DISTINCT expr)默认作为APPROX_COUNT_DISTINCT的别名受useApproximateCountDistinct上下文参数控制只有COUNT、ARRAY_AGG、STRING_AGG支持DISTINCT关键字当没有任何行被选中时COUNT返回初始值0。修改后的查询应为SELECT page, countryName, COUNT(*) AS Edits FROM wikipedia GROUP BY 1, 2 ORDER BY Edits DESC再次运行查询会发现新增了countryName维度但大多数行的该列值为 null。我们只保留有countryName值的行。点击左侧面板中的countryName维度选择第一个过滤选项生成的 WHERE 子句不一定精确符合需求稍后手工修改。将 WHERE 子句修改为排除没有 countryName 值的行WHERE countryName IS NOT NULL再次运行查询即可看到按国家/地区统计的编辑次数排行带 countryName 过滤的最终查询结果深入了解执行计划每一条 Druid SQL 查询在真正运行前都会被翻译成基于 JSON 的Druid 原生查询格式。点击查询编辑器右上角的...菜单选择Explain SQL Query即可查看当前查询翻译后的原生查询查看 SQL 查询对应的原生查询执行计划虽然 Druid SQL 能满足大多数场景但熟悉原生查询对编写复杂查询以及排查性能问题都很有帮助详见 原生查询文档。:::info 另一种查看执行计划的方式 在 SQL 前加上EXPLAIN PLAN FOR即可获得同样的执行计划这在命令行或通过 HTTP 提交查询时尤其有用EXPLAIN PLAN FOR SELECT page, countryName, COUNT(*) AS Edits FROM wikipedia WHERE countryName IS NOT NULL GROUP BY 1, 2 ORDER BY Edits DESC:::最后点击...菜单中的Edit context可以查看如何为查询添加额外的执行控制参数。在弹出的字段中以 JSON 键值对形式输入查询上下文选项例如{timeout: 30000}、{useCache: false}等完整参数说明见 查询上下文Context flags文档。查询上下文是 Druid 中传递各类查询配置参数的通用机制对于 Druid SQL上下文参数既可以通过 HTTP POST API 请求体中的contextJSON 对象提供也可以通过 JDBC 连接的属性提供对于原生查询则放在请求体的context对象中。上下文设置会覆盖默认值以及druid.query.default.context.{property_key}格式的运行时属性。常用参数包括参数默认值说明timeoutdruid.server.http.defaultQueryTimeout查询超时毫秒数超时后未完成的查询会被取消0表示不超时上限由druid.server.http.maxQueryTimeout控制priority0查询优先级高优先级查询优先获得计算资源useCachetrue是否读取查询缓存populateCachetrue是否将查询结果写入缓存maxScatterGatherBytesdruid.server.http.maxScatterGatherBytes执行查询时从 Historical 等数据进程收集数据的最大字节数上限vectorizetrue是否启用向量化查询执行false/true/forcesqlQueryId自动生成SQL 查询 ID可用于取消查询到这里我们已经用 Web 控制台的内置查询构建功能完成了一条简单查询。接下来的小节提供更多可尝试的示例查询。更多 Druid SQL 示例以下查询可以帮助你掌握更多 Druid SQL 技巧。按时间分桶查询Query over timeFLOOR(__time TO HOUR)将时间戳向下取整到小时粒度配合SUM(deleted)统计每个小时被删除的行数TIME_IN_INTERVAL(__time, 2016-06-27/2016-06-28)则是 Druid SQL 中典型的时间区间过滤写法——TIME_IN_INTERVAL(TIMESTAMP, CHARACTER)返回布尔值判断时间戳是否落在给定的 ISO-8601 区间字符串内详见 SQL 函数文档 中的日期时间函数一节SELECT FLOOR(__time to HOUR) AS HourTime, SUM(deleted) AS LinesDeleted FROM wikipedia WHERE TIME_IN_INTERVAL(__time, 2016-06-27/2016-06-28) GROUP BY 1按小时聚合的查询示例通用分组查询General group by按channel与page两个维度分组统计每个渠道页面的新增行数SUM(added)并按总量降序排列SELECT channel, page, SUM(added) FROM wikipedia WHERE TIME_IN_INTERVAL(__time, 2016-06-27/2016-06-28) GROUP BY channel, page ORDER BY SUM(added) DESC按 channel 与 page 分组的查询示例值得留意的是Druid SQL 的时间过滤会自动参与段剪枝segment pruningBroker 会根据时间区间过滤条件排除无关的段只扫描必要的数据这是 Druid 高性能时间查询的关键机制之一。通过 HTTP 提交 SQL 查询你可以将 SQL 查询直接 POST 到 Druid Broker或 Router的 SQL 端点/druid/v2/sql上完整接口说明见 Druid SQL API 文档。请求体是一个 JSON 对象其中query键的值即为 SQL 查询文本{ query: SELECT page, COUNT(*) AS Edits FROM wikipedia WHERE TIME_IN_INTERVAL(\__time\, 2016-06-27/2016-06-28) GROUP BY page ORDER BY Edits DESC LIMIT 10 }教程包中已包含一个存放上述查询的示例文件 examples/quickstart/tutorial/wikipedia-top-pages-sql.json。把它提交给 Druid Brokercurl -X POST -H Content-Type:application/json -d quickstart/tutorial/wikipedia-top-pages-sql.json http://localhost:8888/druid/v2/sql应返回如下结果按编辑次数排名的 Top 10 页面[ { page: Copa América Centenario, Edits: 29 }, { page: User:Cyde/List of candidates for speedy deletion/Subpage, Edits: 16 }, { page: Wikipedia:Administrators noticeboard/Incidents, Edits: 16 }, { page: 2016 Wimbledon Championships – Mens Singles, Edits: 15 }, { page: Wikipedia:Administrator intervention against vandalism, Edits: 15 }, { page: Wikipedia:Vandalismusmeldung, Edits: 15 }, { page: The Winds of Winter (Game of Thrones), Edits: 12 }, { page: ولاية الجزائر, Edits: 12 }, { page: Copa América, Edits: 10 }, { page: Lionel Messi, Edits: 10 } ]SQL HTTP API 的关键请求体字段在query之外/druid/v2/sql端点还支持以下常用字段详见 SQL API 文档字段说明resultFormat结果返回格式objectJSON 对象数组、arrayJSON 数组的数组、objectLines/arrayLines换行分隔的 JSON便于流式解析每条完整响应以末尾换行符结尾以检测截断、csv逗号分隔双引号转义header布尔值为true时首行返回列名可与typesHeader、sqlTypesHeader配合返回 Druid 运行时类型或 SQL 类型信息context查询上下文 JSON 对象例如设置sqlQueryId、时区、是否使用近似 distinct count 算法等parameters参数化查询的参数列表每个参数为包含 SQL 数据类型的 JSON 对象如{type: VARCHAR, value: bar}每个 SQL 查询都会关联一个查询 IDsqlQueryId可以手动通过上下文参数设置未设置时 Druid 自动生成并通过响应头X-Druid-SQL-Query-Id返回。拿到sqlQueryId后可通过DELETE /druid/v2/sql/{sqlQueryId}以尽力而为best-effort的方式取消查询。对于数据仅存在于深层存储deep storage、尚未加载到 Historical 进程的段还可以使用/druid/v2/sql/statements端点以异步模式查询context中设置executionMode: ASYNC提交后通过GET /druid/v2/sql/statements/{queryId}轮询查询状态并分页拉取结果详见 从深层存储查询。一次带类型的完整请求示例结合以上字段一条返回带类型信息结果的完整请求如下该示例来自 SQL API 文档curl http://localhost:8888/druid/v2/sql \ --header Content-Type: application/json \ --data { query: SELECT * FROM wikipedia WHERE userBlueMoon2662, context : {sqlQueryId : request01}, header : true, typesHeader : true, sqlTypesHeader : true }响应首行会包含每列的 Druid 运行时类型LONG、STRING等与 SQL 类型TIMESTAMP、VARCHAR、BIGINT等信息例如__time对应{type: LONG, sqlType: TIMESTAMP}page对应{type: STRING, sqlType: VARCHAR}。进阶从 SQL 到原生查询的转换理解 SQL 与原生查询的对应关系是排查复杂查询性能问题的关键。以EXPLAIN PLAN FOR或控制台的Explain SQL Query功能生成的执行计划为例一条SELECT ... WHERE user BlueMoon2662的简单查询会被翻译为包含以下要素的原生查询结构数据源dataSource{type: table, dataSource: wikipedia}并携带经段剪枝后的查询区间intervals过滤器filter如{type: equals, column: user, matchValue: BlueMoon2662}对应 SQL 的 WHERE 条件处理器processor / queryType如scan对应 Druid 的扫描式原生查询虚拟列virtualColumnsSQL 表达式在原生层会被物化为expression类型的虚拟列上下文context携带queryId、sqlQueryId、sqlOuterLimit对应 Smart query limit 等外层限制等原生执行参数。从源码结构看这一翻译过程由 Druid SQL 模块的 Calcite 规划器完成SQL 查询先被解析为关系代数计划再通过规则引擎转换如将聚合下推为原生groupBy/timeseries聚合器、将过滤条件转换为位图索引友好的过滤结构最终生成可在数据节点上执行的 JSON 查询。对于 GroupBy 类聚合原生查询还会在段内预聚合后由 Broker 归并因此COUNT(*)、SUM、MIN/MAX这类可交换的聚合函数天然适合分布式归并执行。掌握了这条转换链路当你遇到SQL 写得没问题但查询很慢的情况时就可以通过执行计划检查过滤条件是否被正确下推、时间区间是否触发段剪枝、聚合是否走了向量化路径vectorize参数等从而精准定位瓶颈。延伸阅读Druid SQL 完整文档深入理解 Druid SQL 的语法、数据类型与方言差异。原生查询文档了解 Druid 原生 JSON 查询格式。SQL 聚合函数COUNT、SUM、APPROX_COUNT_DISTINCT等聚合函数的完整清单与语义。查询上下文全部查询上下文参数及其默认值。SQL API 参考/druid/v2/sql与/druid/v2/sql/statements端点的完整请求/响应规范。本地 Quickstart从零开始安装、启动 Druid 并加载wikipedia示例数据。【免费下载链接】druidApache Druid: a high performance real-time analytics database.项目地址: https://gitcode.com/gh_mirrors/druid6/druid创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表