使用对比!SLS 数据加工 SPL 与旧版 DSL 场景对照

简介: 本文讨论在不同的数据处理需求中,新版数据加工 SPL 与旧版数据加工 DSL 的使用对照。

1. 概述


如前一篇《SLS 数据加工全面升级,集成 SPL 语法》所述,SLS 数据加工集成了 SLS 数据处理语法 SPL。与旧版本数据加工 DSL 相比,SPL 在处理非结构化数据的场景中,其语法简洁度上有很多提升,比如中间类型保持、字段引用、无缝兼容 SQL 函数等。


这里我们继续讨论在不同的数据处理需求中,新版数据加工 SPL 与旧版数据加工 DSL 的使用对照。对于数据同步的场景,即不需要做任何数据处理,新版 SPL 与旧版 DSL 均传入空逻辑即可,以下不再赘述。


2. 场景一:数据过滤与清洗


在日常运维中,错误日志分析是发现、定位问题的关键步骤。这里我们就以服务日志为例,介绍如何应用数据加工完成数据清洗。


旧版数据加工中,使用 e_keep/e_drop 完成数据清洗,对应的新版数据加工 SPL 中则使用 where 指令。


2.1 精确匹配

需要筛选出错误日志,即级别 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"))


2.2模糊匹配

由于不同服务模块的编码标准差异,如果 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())


2.3 数值范围

除了文本日志的筛选,我们还需要数值范围的比对。比如访问日志中,我们需要筛选出用户使用错误,以便分析哪些操作可能存在设计不合理,即筛选出状态码字段 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)


2.4 存在性检查

另一个运维场景中,如果服务运行错误则会写出 error 字段,否则 error 字段不存在。我们需要筛选出包含 error 的数据条目。


新版 SPL

使用 SQL 的 null 表达式判断字段存在性

| where error is not null

旧版 DSL

使用 e_has 函数判断字段存在性

e_keep(e_has("error"))


3. 场景二:字段管理


3.1 新字段构造

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"))


3.2 筛选、排除、重命名

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)


3.3 条件表达式

条件表达式对于处理混杂在一起的不同类型的数据是关键需求。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"),)


4. 场景三:时间信息解析与格式化


在 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",),)


5. 场景四:非结构或半结构化数据提取


在机器数据处理场景中,从非结构化或半结构化数据中提取关键信息,是一个繁琐的过程。因为数据没有固定的模式,需考虑太多处理细节,但处理的效率要求又极高。SPL 提供指令实现不同的数据提取,比如正则、JSON、CSV 等。


5.1 正则文本提取


新版 SPL

parse-regexp 指令

| parse-regexp data, '(\S+)\s+(\w+)' as time, level

旧版 DSL

e_regex 函数

e_regex("data", r"(\S+)\s+(\w+)", ["time", "level"])


5.2 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")


5.3 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

[2] JMES 语法

[3] CSV RFC 4180



作者:灵圣

作者介绍
目录