网站首页 > 技术文章 正文
作者:灵圣
概述
如前一篇《SLS 数据加工全面升级,集成 SPL 语法》所述,SLS 数据加工集成了 SLS 数据处理语法 SPL。与旧版本数据加工 DSL 相比,SPL 在处理非结构化数据的场景中,其语法简洁度上有很多提升,比如中间类型保持、字段引用、无缝兼容 SQL 函数等。
这里我们继续讨论在不同的数据处理需求中,新版数据加工 SPL 与旧版数据加工 DSL 的使用对照。对于数据同步的场景,即不需要做任何数据处理,新版 SPL 与旧版 DSL 均传入空逻辑即可,以下不再赘述。
场景一:数据过滤与清洗
在日常运维中,错误日志分析是发现、定位问题的关键步骤。这里我们就以服务日志为例,介绍如何应用数据加工完成数据清洗。
旧版数据加工中,使用 e_keep/e_drop 完成数据清洗,对应的新版数据加工 SPL 中则使用 where 指令。
精确匹配
需要筛选出错误日志,即级别 level 字段值为字符串 ERROR。
新版 SPL | 直接引用字段 level | where level='ERROR' |
旧版 DSL | 需使用函数引用字段v("level"),不同的实现方式: ? e_keep(v("level") == "ERROR") ? e_drop(v("level") != "ERROR") ? e_if(v("level") != "ERROR", e_drop()) ? e_keep(e_search("level==ERROR")) |
模糊匹配
由于不同服务模块的编码标准差异,如果 level 字段的值并非固定,可能是 ERROR、ERR 或者 E 等。这个场景下就需要进行字符串模糊匹配。
新版 SPL | 复用 SQL 的 like 表达式 | where level like '%E%' |
旧版 DSL | 不同的实现方式: ? e_keep(op_in(v("level"), "E")) ? e_keep(e_search("level: E") ? e_if(op_not_in(v("level"), "E"), e_drop()) |
数值范围
除了文本日志的筛选,我们还需要数值范围的比对。比如访问日志中,我们需要筛选出用户使用错误,以便分析哪些操作可能存在设计不合理,即筛选出状态码字段 status 值在 4xx 范围的数据。
新版 SPL | 保持 status 字段中间类型,无需多次转换 | extend cast(status as bigint) as status | where status>=400 and status<500 |
旧版 DSL | e_keep(ct_int(v("status"))>=400 and ct_int(v("status"))<500) |
存在性检查
另一个运维场景中,如果服务运行错误则会写出 error 字段,否则 error 字段不存在。我们需要筛选出包含 error 的数据条目。
新版 SPL | 使用 SQL 的 null 表达式判断字段存在性 | where error is not null |
旧版 DSL | 使用 e_has 函数判断字段存在性 e_keep(e_has("error")) |
场景二:字段管理
新字段构造
SPL 使用 extend 指令完成字段赋值操作,相当于数据加工 DSL 中的 e_set。
新版 SPL | 1. 设置固定值,并保留值类型,可直接使用 | extend kb=1024 | extend size=size/1024 2. 正则提取单个信息 | extend version=regexp_extract(data, '"version":\d+') 3. JSON 提取,并赋值给字段,SPL 中 JSON 对象路径引用 JsonPath?[1] | extend version=json_extract(data, '$.version') |
旧版 DSL | 1. 设置固定值,类型变为 str,使用时再次转换 e_set("kb", 1024) e_set("size", ct_int(v("size")) / ct_int(v("kb"))) 2. 正则提取,并赋值给字段 e_set("version", regex_select(v("data"), r'"version":\d+')) 3. JSON 提取,并赋值给字段,JSON 查询语言 JMES 语法?[2] e_set("version", json_select(v("data"), "version")) |
筛选、排除、重命名
SPL 提供原地处理指定字段的能力,即不需要给定完整的数据 Schema(包括字段列表、及其类型),可以直接操作给定字段,且不影响其他不相关的字段。
新版 SPL | 1. 精确选择字段 | project node="__tag__:node", path 2. 按模式选择字段,开启 wildcard 开关 | project -wildcard "__tag__:*" 3. 原地重命名部分字段 | project-rename node="__tag__:node" 4. 按模式排除字段,开启 wildcard 开关 | project-away -wildcard "__tag__:*" |
旧版 DSL | 1. 精确选择字段 e_keep_fields("__tag__:node", "path", regex=False) 2. 按模式选择字段 e_keep_fields("__tag__:.*", regex=True) 3. 原地重命名部分字段 e_rename("__tag__:node", node) 4. 按模式排除字段 e_drop_fields("__tag__:.*", regex=True) |
条件表达式
条件表达式对于处理混杂在一起的不同类型的数据是关键需求。SPL 通过 SQL 表达式完成条件判断。
新版 SPL | 1. SQL 表达式:IF 判断条件返回不同表达式的值 | extend valid=IF(type is not null, 'true', 'false') 2. SQL 表达式:COALESCE 取第一个值不为空的表达式的值,或添加默认值 | extend size=COALESCE(input, output, 0) 3. SQL 表达式:CASE-WHEN 通过条件判断,对数据进行归类、或选择 | extend size=CASE WHEN dir='I' THEN input WHEN dir='O' THEN output ELSE 0 END |
旧版 DSL | 1. op_if 判断条件返回不同表达式的值 e_set("valid", op_if(e_has("type"), "true", "false")) 2. op_coalesce 取第一个值不为空的表达式的值,或添加默认值 e_set("size", op_coalesce(v("input"), v("output"), "0")) 3. e_if_else 控制流程,构造字段 e_if_else( e_has("type"), e_set("valid", "true"), e_set("valid", "false"), ) |
场景三:时间信息解析与格式化
在 SPL 执行过程中,SLS 日志时间字段类型始终保持为数值类型 INTEGER 或者 BIGINT。SLS 日志字段包括数据时间时间戳字段 __time__ 和数据时间纳秒部分字段 __time_ns_part__。需要更新数据时间时,须使用 extend 指令操作。
新版 SPL | 1. 提取日志时间字段 __time__ | extend time=date_parse(time, '%Y/%m/%d %H-%i-%S') | extend __time__=cast(to_unixtime(time) as bigint) 2. 时间格式规范化 | extend time=date_parse(time, '%Y/%m/%d %H-%i-%S') | extend time=date_format(time, '%Y-%m-%d %H:%i:%S') |
旧版 DSL | 1. 提取日志时间字段 __time__ e_set( "__time__", dt_parsetimestamp( v("time"), fmt="%Y/%m/%d %H-%M-%S", ), ) 2. 时间格式规范化 e_set( "time", dt_strftime( dt_parse( v("time"), fmt="%Y/%m/%d %H-%M-%S", ), fmt="%Y-%m-%d %H:%M:%S", ), ) |
场景四:非结构或半结构化数据提取
在机器数据处理场景中,从非结构化或半结构化数据中提取关键信息,是一个繁琐的过程。因为数据没有固定的模式,需考虑太多处理细节,但处理的效率要求又极高。SPL 提供指令实现不同的数据提取,比如正则、JSON、CSV 等。
正则文本提取
新版 SPL | parse-regexp 指令 | parse-regexp data, '(\S+)\s+(\w+)' as time, level |
旧版 DSL | e_regex 函数 e_regex("data", r"(\S+)\s+(\w+)", ["time", "level"]) |
JSON 结构数据提取
新版 SPL | parse-json 指令,JSON 对象路径引用 JsonPath? | parse-json -path='$.x.y.z' data |
旧版 DSL | e_json 函数,JSON 查询语言 JMES 语法? e_json("data", depth=1, jmes="x.y.z") |
CSV 格式数据提取
新版 SPL | ? 单字符分隔符 CSV RFC 4180[3],支持指定分隔符、引用符 | parse-csv -delim='\0' -quote='"' data as time, addr, user ? 多字符分隔符 | parse-csv -delim='^_^' data AS time, addr, user |
旧版 DSL | e_csv 函数 e_csv("data", ["time", "addr", "user"], sep="\0", quote='"') |
相关链接:
[1] JsonPath
https://github.com/json-path/JsonPath
[2] JMES 语法
https://help.aliyun.com/zh/sls/user-guide/jmespath-syntax
[3] CSV RFC 4180
https://www.loc.gov/preservation/digital/formats/fdd/fdd000323.shtml
猜你喜欢
- 2024-10-19 Node-RED系列(六):Node-RED解析节点的使用
- 2024-10-19 越南指数行情数据API接口(越南指数股票最新行情)
- 2024-10-19 Pinot 架构分析(pod架构)
- 2024-10-19 大模型开发者实战揭秘:SFT指令微调数据构建的全方位指南
- 2024-10-19 27K star!这款开源可视利器帮你一眼看穿JSON
- 2024-10-19 linux-shell命令处理json数据(linux检查json格式)
- 2024-10-19 MongoDB常用特性一览(mongodb4.2新特性)
- 2024-10-19 轻量级的原生JavaScript的Excel插件——JExcel
- 2024-10-19 5万字长文!搞定Spark方方面面(五)
- 2024-10-19 越南指数清单列表数据API接口(越南指数清单列表数据api接口在哪)
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)