关于 dt-dql-essentials
DQL Essentials 是面向 Dynatrace DQL 使用者的技能,帮助编写查询并查阅语法、函数和任务相关参考。内容涵盖查询模式、优化及常见语法陷阱。
主要功能
- 01按任务查找 DQL 参考
- 02涵盖命令与函数索引
- 03提供查询优化指导
- 04说明语法陷阱与正确写法
适用场景
- 01发现可查询的数据
- 02编写筛选与聚合查询
- 03优化查询效率
- 04处理数组和时间序列
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ dynatrace/ dynatrace-for-ai --skill dt-dql-essentials安装后在 Claude Code 中输入/dt-dql-essentials确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/discovery.mditerative-expressions.mdoperators.mdoptimization.mdsemantic-dictionary.mdsmartscape-topology-navigation.mdreferences/dql/dql-commands.mddql-data-types.mddql-functions-aggregation.mddql-functions-array.mddql-functions-bitwise.mddql-functions-boolean.mddql-functions-cast.mddql-functions-constant.mddql-functions-conversion.mddql-functions-create.mddql-functions-cryptographic.mddql-functions-entities.mddql-functions-expression-timeseries.mddql-functions-flow.mddql-functions-general.mddql-functions-get.mddql-functions-iterative.mddql-functions-mathematical.mddql-functions-network.mddql-functions-smartscape.mddql-functions-string.mddql-functions-time.mddql-functions-timeseries.mddql-parameter-value-types.md详细介绍
DQL 基础技能
DQL 是一种基于管道的查询语言。查询使用 | 将命令串联起来,以筛选、转换和聚合数据。DQL 的语法独特,与 SQL 不同——编写任何 DQL 查询前,请先加载此技能。
何时加载参考资料
开始处理特定任务前,请加载相关参考资料:
| 任务 | 必读内容 |
|---|---|
| 发现数据 | references/discovery.md |
| 字段名称、命名空间、数据模型、稳定性级别、查询模式 | references/semantic-dictionary.md |
| 查询优化——让查询更快、更高效或成本更低,减少消耗和扫描的数据(尽早筛选、分桶筛选、时间范围、字段选择、采样、基数) | references/optimization.md |
| 使用 Smartscape 拓扑导航发现实体之间的关系 | references/smartscape-topology-navigation.md |
summarize 和 makeTimeseries 模式(分桶、日历月) | references/summarization.md |
数组和时间序列操作(arrayFilter、collectArray、迭代) | references/iterative-expressions.md |
条件逻辑(if/else 链)、coalesce、字符串/日期辅助函数 | references/useful-expressions.md |
in 运算符(子查询)、完整的 @ 时间对齐单位表 | references/operators.md |
matchesValue、matchesPhrase、matchesPattern、in()——字符串模式匹配、正则表达式、数组匹配、通配符、大小写敏感性 | references/string-matching.md |
DQL 参考索引
使用此索引,从函数组(例如时间函数、转换)找到其详细规范,或从函数名称找到对应的规范文件。
| 描述 | 条目 |
|---|---|
| 数据类型 | array、binary、boolean、double、duration、long、record、string、timeframe、timestamp、uid |
| 参数值类型 | bucket、dataObject、dplPattern、entityAttribute、entitySelector、entityType、enum、executionBlock、expressionTimeseriesAggregation、expressionWithConstantValue、expressionWithFieldAccess、fieldPattern、filePattern、identifierForAnyField、identifierForEdgeType、identifierForFieldOnRootLevel、identifierForNodeType、joinCondition、jsonPath、metricKey、metricTimeseriesAggregation、namelessDplPattern、nonEmptyExecutionBlock、prefix、primitiveValue、simpleIdentifier、tabularFileExisting、tabularFileNew、url |
| 命令 | append、data、dedup、describe、expand、fetch、fields、fieldsAdd、fieldsFlatten、fieldsKeep、fieldsRemove、fieldsRename、fieldsSnapshot、fieldsSummary、filter、filterOut、join、joinNested、limit、load、lookup、makeTimeseries、metrics、parse、search、smartscapeEdges、smartscapeNodes、sort、summarize、timeseries、traverse |
| 函数 — 聚合 | avg、collectArray、collectDistinct、correlation、count、countDistinct、countDistinctApprox、countDistinctExact、countIf、max、median、min、percentRank、percentile、percentileFromSamples、percentiles、stddev、sum、takeAny、takeFirst、takeLast、takeMax、takeMin、variance |
| 函数 — 数组 | arrayAvg、arrayConcat、arrayCumulativeSum、arrayDelta、arrayDiff、arrayDistinct、arrayFirst、arrayFlatten、arrayIndexOf、arrayLast、arrayLastIndexOf、arrayMax、arrayMedian、arrayMin、arrayMovingAvg、arrayMovingMax、arrayMovingMin、arrayMovingSum、arrayPercentile、arrayRemoveNulls、arrayReverse、arraySize、arraySlice、arraySort、arraySum、arrayToString、vectorCosineDistance、vectorInnerProductDistance、vectorL1Distance、vectorL2Distance |
| 函数 — 位运算 | bitwiseAnd、bitwiseCountOnes、bitwiseNot、bitwiseOr、bitwiseShiftLeft、bitwiseShiftRight、bitwiseXor |
| 函数 — 布尔值 | exists、in、isFalseOrNull、isNotNull、isNull、isTrueOrNull、isUid128、isUid64、isUuid |
| 函数 — 类型转换 | asArray、asBinary、asBoolean、asDouble、asDuration、asIp、asLong、asNumber、asRecord、asSmartscapeId、asString、asTimeframe、asTimestamp、asUid |
| 函数 — 常量 | e、pi |
| 函数 — 转换 | toArray、toBoolean、toDouble、toDuration、toIp、toLong、toSmartscapeId、toString、toTimeframe、toTimestamp、toUid、toVariant |
| 函数 — 创建 | array、duration、ip、record、smartscapeId、timeframe、timestamp、timestampFromUnixMillis、timestampFromUnixNanos、timestampFromUnixSeconds、uid128、uid64、uuid |
| 函数 — 加密 | hashCrc32、hashMd5、hashSha1、hashSha256、hashSha512、hashXxHash32、hashXxHash64 |
| 函数 — 实体 | classicEntitySelector、entityAttr、entityName |
| 函数 — 表达式的时间序列聚合 | avg、count、countDistinct、countDistinctApprox、countDistinctExact、countIf、end、max、median、min、percentRank、percentile、percentileFromSamples、start、sum |
| 函数 — 流程控制 | coalesce、if |
| 函数 — 通用 | jsonField、jsonPath、lookup、parse、parseAll、type |
| 函数 — 获取 | arrayElement、getEnd、getHighBits、getLowBits、getStart |
| 函数 — 迭代 | iAny、iCollectArray、iIndex |
| 函数 — 数学 | abs、acos、asin、atan、atan2、bin、cbrt、ceil、cos、cosh、degreeToRadian、exp、floor、hexStringToNumber、hypotenuse、log、log10、log1p、numberToHexString、power、radianToDegree、random、range、round、signum、sin、sinh、sqrt、tan、tanh |
| 函数 — 网络 | ipIn、ipIsLinkLocal、ipIsLoopback、ipIsPrivate、ipIsPublic、ipMask、isIp、isIpV4、isIpV6 |
| 函数 — Smartscape | getNodeField、getNodeName |
| 函数 — 字符串 | concat、contains、decodeBase16ToBinary、decodeBase16ToString、decodeBase64ToBinary、decodeBase64ToString、decodeUrl、encodeBase16、encodeBase64、encodeUrl、endsWith、escape、getCharacter、indexOf、lastIndexOf、levenshteinDistance、like、lower、matchesPattern、matchesPhrase、matchesRegex、matchesValue、punctuation、replacePattern、replaceString、splitByPattern、splitString、startsWith、stringLength、substring、trim、unescape、unescapeHtml、upper |
| 函数 — 时间 | formatTimestamp、getDayOfMonth、getDayOfWeek、getDayOfYear、getHour、getMinute、getMonth、getSecond、getWeekOfYear、getYear、now、unixMillisFromTimestamp、unixNanosFromTimestamp、unixSecondsFromTimestamp |
| 函数 — 指标的时间序列聚合 | avg、count、countDistinct、end、max、median、min、percentRank、percentile、start、sum |
Syntax Pitfalls
| ❌ 错误 | ✅ 正确 | 问题 |
|---|---|---|
filter field in ["a", "b"] | filter in(field, {"a", "b"}) | 在 DQL 中,[ 和 ] 用于括起子查询,但不用于括起静态数组字面量。静态值请使用 {} 或 array()。 |
filter: { in(field, [sub-query]) }(例如在 timeseries filter: 中) | filter: { field in [sub-query] } | in() 不接受执行块作为参数。当右侧是子查询(执行块)时,请使用 in 运算符:field in [execution block]。 |
by: severity, status | by: {severity, status} | 在 by: 子句(summarize、makeTimeseries 等)中,字段列表必须用花括号括起。 |
contains(toLowercase(field), "err") | contains(field, "err", false) | 区分大小写匹配时,不要用 lower() 包裹。contains() 内置了第三个位置参数 caseSensitive(默认值为 true)。 |
filter name == "*serv*9*" | filter matchesValue(name, "*serv*") and matchesValue(name, "*9*") | == 不支持通配符。matchesValue() 支持 * 通配符,但只能放在模式的开头和/或结尾;若要表达字符串中间的通配符意图,请拆分为多个调用并用 and 连接。 |
在字符串字段上使用 matchesValue(field, "prod") | contains(field, "prod") | 不使用通配符时,matchesValue() 会执行精确(不区分大小写)匹配,因此无法找到 "production"。子字符串匹配请使用 contains()(通配符匹配则使用 matchesValue(field, "*prod*"))。 |
iAny(matchesValue(arr[], "x") OR matchesValue(arr[], "y")) | matchesValue(arr, {"x", "y"}) | matchesValue 的第一个参数可以是数组字段,第二个参数可以是数组字面量 {},无需使用 iAny 或 []。同样,若要合并同一字段上的多个 contains(f, x) OR contains(f, y),请使用 matchesValue(f, {"*x*", "*y*"})。 |
iAny(matchesPhrase(arr[], "phrase")) | matchesPhrase(arr, "phrase") | matchesPhrase 原生支持遍历数组字段,可去掉 iAny( 和 []。注意:第二个参数必须是静态字符串;matchesPhrase(f, array("a","b")[]) 会导致运行时错误。 |
在较短或常见词元上使用 contains(field, "pip") | matchesPhrase(field, "pip") | contains 只匹配子字符串,因此 "pip" 也会匹配 "pipenv"、"gripping"。matchesPhrase 会对字符串进行词元化,仅匹配完整单词,从而减少误报。 |
iAny(in(lower(arr[]), array("a", "b"))) | matchesValue(arr, {"a", "b"}, caseSensitive: false) | matchesValue 默认不区分大小写,无需使用 lower()、in() 或 iAny 包装。此处显式写出 caseSensitive: false,只是为了与被替换的 lower() 意图一致。 |
iAny(f1[] == "a" AND f2[] == "b"),遍历两个独立数组 | in(f1, "a") AND in(f2, "b") | 多数组 iAny 是成对匹配,而非笛卡尔积:会将 f1[] 的第 i 个元素与 f2[] 的第 i 个元素进行测试。如果数组长度不同,结果为 null。请改用独立的 in() 检查。参见 references/iterative-expressions.md。 |
toLowercase(field) | lower(field) | 函数名是 lower(),不是 toLowercase()。只有类型转换函数使用 to 前缀(toString()、toLong() 等)。 |
arrayAvg(field[]) 或 arraySum(field[]) | arrayAvg(field) 或 field[] | field[] = 逐元素迭代表达式(数组→数组);arrayAvg(field) = 折叠为标量(数组→单个值)。切勿混用;arrayAvg(field[]) 在语义上是错误的。 |
lookup 或 join 之后使用 my_field | lookup.my_field / right.my_field | lookup 默认会在新增字段前加上 lookup. 前缀(可通过 prefix: 配置)。join 会在右侧字段前加上 right. 前缀。 |
substring(field, 0, 200) | substring(field, from: 0, to: 200) | 第一个参数(表达式)是位置参数,但 from: 和 to: 是可选的命名参数,必须写出参数名。 |
filter host = "A" | filter host == "A" | DQL 使用 == 进行相等比较,而非 =。单个 = 用于赋值(例如在 fieldsAdd、summarize 别名中)。 |
fetch logs, from: toTimestamp('2026-01-01') | fetch logs, from: -24h | from:/to: 接受时长字面量(例如 -24h、-7d)或 now() 表达式,不接受 toTimestamp()。绝对时间范围请使用 timeframe: "start/end"(ISO 8601)。 |
filter log.level == "ERROR" | filter loglevel == "ERROR" | 日志严重性字段是 loglevel(没有点号);log.level 不存在。 |
sort count() desc | sort `count()` desc | 带特殊字符(如括号)的字段必须用反引号括起。 |
length(field) | stringLength(field) | DQL 的字符串长度函数是 stringLength,不存在 length()。 |
metrics dt.host.cpu.usage | timeseries avg(dt.host.cpu.usage) | metrics 加载的是指标元数据,而非指标值;请使用 timeseries 获取数据。 |
join [...], on:{left.a.b == right.a.b} | join [...], on:{left[`a.b`] == right[`a.b`]} | 在 join/lookup 条件中,带点号的字段名必须使用带反引号的方括号表示法。 |
fieldsSummary(不带参数) | fieldsSummary field1, field2 | fieldsSummary 至少需要一个字段参数。 |
timeseries 使用 percentile/median/percentRank,但没有结果 | 在 timeseries 命令中添加 rollup: avg(或 min/max/sum) | 对 gauge/count 指标使用这三个函数时,必须指定 rollup:;否则查询会静默返回空结果。 |
summarize p95 = percentile(duration, 95, rollup: avg) | summarize p95 = percentile(duration, 95) | rollup: 是**仅适用于 timeseries**的参数。在日志/spans/events 上对同名聚合使用 summarize 时会因 UNKNOWN_PARAMETER_DEFINED 被拒绝。只有在 timeseries 中聚合指标时才添加 rollup:。 |
filter array.contains(field, "v") 或 arrayContains(field, "v") | filter in(field, {"v"}) | DQL 中不存在这两个函数;它们是从 Python/Java/SQL 臆造出来的。in() 已原生支持匹配数组类型字段(例如 dt.davis.problems 上的 k8s.namespace.name):只要 needle 中的任一元素与 haystack 中的任一元素匹配,就会返回 true。参见 references/iterative-expressions.md。 |
字段为数组类型时使用 filter k8s.namespace.name == "ns" | filter in(k8s.namespace.name, {"ns"}) | 对数组类型字段使用 == 不会匹配任何内容;它会无报错地返回零行,看起来像是“没有数据”,而不是写法错误。dt.davis.problems 上的 k8s.* 字段是数组。精确匹配成员请使用 in() 或 matchesValue(field, {...})。 |
parseJson(field) 或 extractJsonField(field, jsonPath: "$.x") | parse field, "JSON:parsed",然后使用 parsed[x] | 这两个函数都不存在。字符串字段中嵌入的 JSON 应使用 parse 命令和 JSON DPL 匹配器解包,然后通过方括号表示法访问。 |
filter hour(timestamp) == 4/minute(timestamp) | filter getHour(timestamp) == 4/getMinute(timestamp) | 不存在 hour()/minute() 函数。get* 系列返回数字,因此可以进行数值比较和范围比较。不要替换为 formatTimestamp(timestamp, format: "HH");它返回的是字符串,因此 == 4 会静默地匹配不到任何内容。 |
在 dt.entity.* 上使用 fields fromRelationships, toRelationships, containerImageTag | 先使用 describe dt.entity.<type>,再选择实际字段 | 传统实体对象不会公开 Entities REST API 的属性名称。必须通过 describe <dataObject> 查找字段名,而不能根据 API 负载猜测。 |
by: {bin(timestamp, 1h)},然后使用 sort `bin(timestamp,1h)` | by: {t = bin(timestamp, 1h)},然后使用 sort t | DQL 会将自动生成的分组键名称规范化为 bin(timestamp, 1h),逗号后始终带空格,不受表达式原写法影响。省略空格的反引号引用会触发 FIELD_DOES_NOT_EXIST。请始终为分组键添加别名。 |
fetch spans | ... by: {bin(timestamp, 1h)} | fetch spans | ... by: {t = bin(start_time, 1h)} | spans 没有 timestamp 字段;其时间字段是 start_time 和 end_time。引用 timestamp 会根据所在位置报错或产生空值。 |
lookup [...], fields: {`dotted.name`} | lookup [...], fields: {dotted.name} | 在 lookup 的 fields: 参数中不要用反引号括起字段名,否则会导致 PARSE_ERROR。 |
data record(key: "val") | data record(key = "val") | record() 的命名字段使用 =,而非 :;: 用于 rollup: 之类的命令参数。 |
getNodeField(dt.smartscape.host, "tags")["tag.key"] | getNodeField(dt.smartscape.host, "tags")[tag.key] | 在此标签映射访问模式中,方括号键必须使用不带引号的标识符语法;带引号的键会导致解析错误。 |
by: {dt.entity.host} 或 dt.entity.* | by: {dt.smartscape.host} 或 dt.smartscape.* | dt.entity.* 已弃用;新查询一律使用 dt.smartscape.*。 |
Fetch 命令 → 数据模型
DQL 查询以 fetch <data_object> 或 timeseries 开头。没有 fetch dt.metric——指标使用 timeseries。
| Fetch 命令 | 数据模型 | 关键字段 / 备注 |
|---|---|---|
fetch spans | 分布式追踪 | span.*、service.*、http.*、db.*、code.*、exception.* |
fetch logs | 日志事件 | log.*、k8s.*、host.*——消息正文是 content,严重性是 loglevel(不是 log.level) |
fetch events | DAVIS / 基础设施事件 | event.*、dt.smartscape.* |
fetch bizevents | 业务事件 | event.*、自定义字段 |
fetch security.events | 安全事件 | vulnerability.*、event.* |
fetch user.sessions | RUM 会话 | dt.rum.*、browser.*、geo.* |
fetch user.events | RUM 单个事件 | 页面浏览、点击、请求、错误 |
fetch user.replays | 会话回放录制 | |
fetch application.snapshots | 应用程序快照 | |
fetch dt.davis.events | Davis 检测到的事件 | |
fetch dt.davis.problems | Davis 检测到的问题 | |
timeseries avg(metric.key) | 指标 | 不是 fetch——带连字符的键需要使用反引号:timeseries sum(`my.metric-name`) |
smartscapeNodes "HOST" | 拓扑 | 不是 fetch——类型包括:HOST、SERVICE、K8S_CLUSTER 等 |
dt.entity.* 已弃用——新查询请使用 dt.smartscape.* 和 smartscapeNodes。
发现所有可用的数据对象:fetch dt.system.data_objects | fields name, display_name, type
→ 完整字段命名空间请参阅 references/semantic-dictionary.md
samplingRatio 参数
fetch 支持 samplingRatio: 参数,可减少读取的数据量——这有助于提升大型数据集的查询性能。
fetch spans, samplingRatio:100 // reads ~1% of data
**允许的值:**取决于具体的数据对象,范围从 1、10、100、1000、10000 到 100000;最高级别仅适用于 logs 和 spans。
对于 spans、user.events 和 user.sessions,采样采用分层方式:在较高比例(例如 100)下纳入的记录,保证也会出现在较低比例(例如 10、1)中,反之则不成立。这意味着不同采样比例下的结果彼此是子集关系。其他所有非指标数据对象均按记录独立采样,因此不同采样比例下的结果不构成子集关系。
实际应用的比例可通过 dt.system.sampling_ratio 字段获取。使用此字段,可将采样计数外推为实际总数:
fetch logs, samplingRatio:10
| summarize count_extrapolated = sum(dt.system.sampling_ratio)
Timeseries 聚合函数
timeseries 命令仅支持以下聚合函数:
| 函数 | 描述 |
|---|---|
sum | 每个时间槽内指标数据点的总和 |
avg | 每个时间槽内指标数据点的平均值 |
min | 每个时间槽内指标数据点的最小值 |
max | 每个时间槽内指标数据点的最大值 |
count | 每个时间槽内指标数据点的数量 |
percentile(metric, N) | 每个时间槽内的第 N 百分位数。需要 rollup:——见下文。 |
median(metric) | 每个时间槽内的第 50 百分位数(= percentile(metric, 50))。需要 rollup:。 |
percentRank(metric, value) | 每个时间槽内某个值的百分位排名。需要 rollup:。 |
countDistinct(metric) | 每个时间槽内近似去重计数(仅限基数指标;不接受 rollup:)。 |
辅助函数(与聚合函数搭配使用):start()、end()。
timeseries 不支持:countIf、collectArray、stddev、variance、takeAny、takeFirst、takeLast——请使用 summarize 或 makeTimeseries。
rollup: 参数
指标会在写入时预聚合。rollup: 用于控制每个时间槽中如何合并原始数据点。percentile、median、percentRank 必须使用此参数,否则查询会静默返回空结果。avg/min/max/sum/count 无需 rollup:。
rollup: 是仅适用于 timeseries 的参数,只能用于指标聚合。在事件数据(日志、跨度、事件)的 summarize 中,同名的聚合函数不接受此参数:summarize p95 = percentile(duration, 95, rollup: avg) 会报错 UNKNOWN_PARAMETER_DEFINED。在 summarize 中,请使用不带 rollup: 的 percentile(field, N)。
单个聚合:在命令级别使用 rollup:。多个聚合(使用 {}):rollup: 必须放在每个函数调用内部(命令级别的 rollup: 会导致 UNKNOWN_PARAMETER_DEFINED):
timeseries p90 = percentile(dt.process.handles.file_descriptors_percent_used, 90), rollup: avg
timeseries {
p90 = percentile(dt.process.handles.file_descriptors_percent_used, 90, rollup: avg),
med = median(dt.process.handles.file_descriptors_percent_used, rollup: avg),
avg_val = avg(dt.process.handles.file_descriptors_percent_used)
}, by: {dt.smartscape.host}
取值:avg(仪表盘指标)、min、max、sum(计数器)、total。
时序数据转标量
将时序数据折叠为标量有两种方法。如果只需要单个聚合值,优先使用 scalar:true 参数,因为它效率更高,不会生成数组。只有在同一查询中既需要完整序列又需要派生标量时,才使用数组函数。
首选:在聚合函数中使用 scalar:true
将 scalar:true 传递给任意时序聚合函数。结果字段会包含单个值,而不是数组,并且不会分配中间数组:
timeseries avg_cpu = avg(dt.host.cpu.usage, scalar:true), by:{dt.smartscape.host}
timeseries {
avg_cpu = avg(dt.host.cpu.usage, scalar:true),
max_cpu = max(dt.host.cpu.usage, scalar:true)
}, by:{dt.smartscape.host}
备用方案:在 fieldsAdd 中使用数组函数
如果需要在派生标量的同时保留完整的时间序列数组,请在后续的 | fieldsAdd 中使用数组函数:
| 函数 | 说明 |
|---|---|
arrayAvg(arr) | 数组中所有值的平均值 |
arraySum(arr) | 所有值的总和 |
arrayMin(arr) | 最小值 |
arrayMax(arr) | 最大值 |
arrayMedian(arr) | 中位数 |
arrayPercentile(arr, N) | 第 N 百分位数(0–100) |
arrayLast(arr) | 最后一个非空值(最新的数据点) |
arrayFirst(arr) | 第一个非空值(最早的数据点) |
timeseries cpu = avg(dt.host.cpu.usage), by:{dt.smartscape.host}
| fieldsAdd avg_cpu = arrayAvg(cpu), max_cpu = arrayMax(cpu)
时间对齐(@ 运算符)
@ 运算符会将时间戳对齐到某个边界,Agent 经常会用错。
| 表达式 | 含义 |
|---|---|
now()@h | 当前时间,按小时边界对齐 |
now()@d | 今天午夜 |
now()@w1 | 本周星期一 |
now()-2h@h | 2 小时前,按小时对齐(先偏移,再对齐) |
规则:
- 顺序:先偏移,再对齐——
now()-2h@h,而不是now()@h-2h @和单位之间不能有空格——使用now()@h,而不是now() @hm表示分钟,M表示月——请勿混淆
→ 完整的 timeseries 聚合和 rollup: 规则,请参阅 references/dql/dql-functions-timeseries.md
→ arrayAvg / arrayMax / arrayPercentile / … 规范,请参阅 references/dql/dql-functions-array.md
实体与 Smartscape 模式
实体字段按类型划分作用域 — 不存在 entity.id。使用 smartscapeNodes 查询拓扑。
| 实体 | 数据中的 ID 字段 | smartscapeNodes 类型 |
|---|---|---|
| 主机 | dt.smartscape.host | "HOST" |
| 服务 | dt.smartscape.service | "SERVICE" |
| 进程 | dt.smartscape.process | "PROCESS" |
| K8s 集群 | dt.smartscape.k8s_cluster | "K8S_CLUSTER" |
使用 toSmartscapeId() 将字符串转换为 ID(必需!)。
→ references/smartscape-topology-navigation.md
makeTimeseries 命令
makeTimeseries 根据事件数据(日志、跨度、bizevents)构建按时间分桶的序列。与查询预先摄取指标的 timeseries 不同,makeTimeseries 会在管道中聚合数据。
不要将 timeseries 直接传入 makeTimeseries — 这会因 INVALID_IMPLICIT_TIME_DEFAULT 而失败。若要重新聚合指标数据,请使用 start() + expand(参见 references/summarization.md)。
fetch logs
| makeTimeseries
total = count(),
errors = countIf(loglevel == "ERROR"),
interval: 5m,
by: {k8s.cluster.name}
| fieldsAdd error_rate = errors[] * 100.0 / total[]
关键参数:interval:、by:{}、from:/to:、bins:、time:(时间戳字段)、spread:(仅适用于 count/countIf)、nonempty:。
→ references/summarization.md,了解完整的 makeTimeseries 模式和 summarize 分桶方式
→ references/iterative-expressions.md,了解时间序列数组操作
字符串匹配函数
DQL 有四个主要函数用于字符串和数组模式匹配。完整指南和快速参考表请参阅 references/string-matching.md。
matchesValue(field, {"pattern*", "*other*"})— 通配符匹配(开头/结尾的*)。第一个参数接受数组字段,第二个参数接受数组字面量{}— 无需iAny或[]。默认不区分大小写(使用caseSensitive: true可强制区分大小写)。可替代contains()+iAny链式调用和lower()变通方法。matchesPhrase(field, "token")— 将字符串拆分为词元并匹配完整单词,不同于只做子字符串匹配的contains()。第一个参数原生支持数组字段;第二个参数必须是静态字符串(数组展开会导致运行时错误)。in(field, array("a", "b"))— 集合成员判断。两个参数都接受数组,因此可用于检查重叠/交集。
链式 Lookup 模式
每个未设置 fields 参数的 lookup 命令,都会在添加新字段前移除所有以此前缀开头的现有字段(默认值:lookup.)。链式调用多个 lookup 时,请使用 fields 参数或自定义前缀来保留结果:
选项 1(默认):所需字段已知。
fetch bizevents
// Step 1: First lookup — enrich orders with product info
| lookup [fetch bizevents
| filter event.type == "product_catalog"
| fields product_id, category],
sourceField: product_id, lookupField: product_id, fields: {product_id, product_category = category}
// Step 2: Second lookup — specify fields with a different name
| lookup [fetch bizevents
| filter event.type == "warehouse_stock"
| fields category, warehouse_region],
sourceField: product_category, lookupField: category, fields: {warehouse_region, warehouse_category = category}
4 个 lookup 字段 product_id、product_category、warehouse_region 和 warehouse_category 均可用。
如果没有 fields:{...} 参数,这些字段会添加 lookup. 前缀,第二个 lookup 命令会删除第一个命令添加的字段。
选项 2:保留 lookup 中的所有字段。
fetch bizevents
// Step 1: First lookup — enrich orders with product info
| lookup [fetch bizevents
| filter event.type == "product_catalog"
| fields product_id, category],
sourceField: product_id, lookupField: product_id, prefix: "product."
// Step 2: Second lookup — specify fields with a different prefix
| lookup [fetch bizevents
| filter event.type == "warehouse_stock"
| fields category, warehouse_region],
sourceField: product_category, lookupField: category, prefix: "warehouse."
新字段为:product.product_id、product.category、warehouse.category、warehouse.warehouse_region。
原始来源中所有以 product. 或 warehouse. 开头的字段都会被移除。
如果没有专用的 prefix,两个 lookup 命令都会使用相同前缀(lookup.),第二个 lookup 会丢弃第一个 lookup 的结果 — 导致字段为空。
makeTimeseries 命令
makeTimeseries 可根据事件数据(日志、跨度、业务事件)生成按时间分桶的序列。与查询预先摄取的指标的 timeseries 不同,makeTimeseries 会在管道中聚合数据。
不要将 timeseries 直接传入 makeTimeseries——这样会因 INVALID_IMPLICIT_TIME_DEFAULT 而失败。若要重新聚合指标数据,请使用 start() + expand(参见 references/summarization.md)。
fetch logs
| makeTimeseries
{total = count(),
errors = countIf(loglevel == "ERROR")},
interval: 5m,
by: {k8s.cluster.name}
| fieldsAdd error_rate = errors[] * 100.0 / total[]
关键参数:interval:、by:{}、from:/to:、bins:、time:(时间戳字段)、spread:(仅适用于 count/countIf)、nonempty:。→ 完整规范请参见 references/dql/dql-commands.md。
使用 spread: 创建实体存在时间线:
smartscapeNodes "HOST"
| makeTimeseries concurrently_existing_hosts = count(), spread: lifetime
→ 时间序列数组操作请参见 references/iterative-expressions.md
时间范围规范
访问数据需要指定时间范围。
可在 UI 中指定,也可通过 REST API 参数指定,或在 DQL 查询中显式使用一对参数:from: 和 to:(若省略其中一个,默认值为 now());也可以改用单个 timeframe: 参数。
时间范围可以使用绝对值或相对于当前时间的表达式表示。时间对齐运算符(@)可用于将时间戳舍入到时间单位边界——完整详情请参见 references/operators.md。
示例
from:now()-1h@h, to:now()@h // last complete hour
from:now()-1d@d, to:now()@d // yesterday complete
from:now()@M // this month so far, till now
from:now()-2h@h // go back 2 hours, then align to hour boundary
完整的 @ 对齐单位表(包括 m 与 M 的区别、星期几变体 w1–w7,以及 @3h 等因子规则)请参见 references/operators.md。
绝对时间戳
使用 ISO 8601 格式:
from:"2024-01-15T08:00:00Z", to:"2024-01-15T09:00:00Z"
修改时间
关键概念
- DQL 有 3 种与时间相关的专用类型:
- timestamp — 内部以距纪元以来的纳秒数保存,但对外显示为特定时区的日期/时间
- timeframe — 一对时间戳(开始和结束)
- duration — 内部以纳秒数保存,但对外显示为缩放到合理单位的时长(例如 ms、分钟、天)
规则
- 时间戳相减会得到时长:
timestamp - timestamp → duration - 时长除以时长会得到 double:例如
2h / 1m=120.0 - 标量乘以时长会得到时长:例如
no_of_h * 1h → duration - 提取时间元素(小时、月中的日期等)时:
- ✅ 使用时间函数。它们能够正确处理日历和时区,包括夏令时。
- ❌ 避免使用
formatTimestamp提取时间组成部分。 - ❌ 避免将时间戳和时长转换为 double/long 后,再使用除法、取模运算以及表示纳秒时间单位的常量。
参考资料
- references/useful-expressions.md — DQL 中的实用表达式
- references/semantic-dictionary.md — Dynatrace 语义字典:字段命名空间、数据模型、稳定性级别、查询模式和最佳实践
- references/summarization.md — summarize 和 makeTimeseries 命令的各种应用
- references/iterative-expressions.md — 使用 DQL 操作数组和时间序列(创建、修改及在筛选器中使用)
- references/smartscape-topology-navigation.md — Smartscape 拓扑导航语法和模式
- references/optimization.md — DQL 查询优化:让查询运行得更快、更高效且成本更低(降低每次执行的消耗量/扫描数据量)——筛选器的位置、存储桶筛选器、时间范围、字段选择、采样、基数和性能最佳实践
- references/operators.md —
in运算符(子查询语法)和完整的@时间对齐单位参考 - references/discovery.md - 发现数据