阿里云 SLS 数据加工中使用 Python 数据编码

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 数据编码在大数据处理的基础操作,本文讨论了 Python3 中的数据编码方案,以及在 SLS 数据加工中内置的数据编解码函数使用。

引文

数据编码是互联网上计算机之间交流的语言基础,如果计算机之间甲流使用的是哪种编码方式没有达成共识,就会出现“锟斤拷���”这样的魔幻字符。
在大数据系统中,这样的场景非常常见,主要原因在于数据的数据的生产与处理是隔离的,比如不同的业务系统各自独立运行,其产生的数据都汇集到大数据系统进行统一处理。
以下是一个数据样例,直观看上去这个数据非常复杂,看不出其中的具体内容。这里我们将讨论Python的数据编码方式(Python3),以及在阿里云 SLS 数据加工中如何应用Python的编码方案快速的实现数据编码处理。

{\x22time\x22:1644460630577,\x22type\x22:\x22track\x22,\x22distinct_id\x22:\x221111111\x22,\x22login_id\x22:\x221111111\x22,\x22anonymous_id\x22:\x22b13f22aca3faa599\x22,\x22lib\x22:{\x22$lib_method\x22:\x22autoTrack\x22,\x22$lib\x22:\x22Android\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$app_version\x22:\x221.1.23\x22,\x22$lib_detail\x22:\x22com.zeekrlife.second_hand.view.TestActivity######\x22},\x22event\x22:\x22$AppViewScreen\x22,\x22properties\x22:{\x22$os_version\x22:\x222.0.0\x22,\x22$model\x22:\x22XXX\x22,\x22$os\x22:\x22iOS\x22,\x22$screen_width\x22:1133,\x22$brand\x22:\x22TEST\x22,\x22$screen_height\x22:2453,\x22$app_version\x22:\x221.1.23\x22,\x22$lib\x22:\x22Android\x22,\x22$device_id\x22:\x22b13f22aca3faa599\x22,\x22$app_name\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$timezone_offset\x22:-480,\x22$app_id\x22:\x22com.zeekrlife.mobile\x22,\x22$manufacturer\x22:\x22TEST\x22,\x22platform_type\x22:\x22Android\x22,\x22$referrer_title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$wifi\x22:true,\x22$network_type\x22:\x22WIFI\x22,\x22$referrer\x22:\x22com.zeekrlife.main.MainActivity\x22,\x22$url\x22:\x22com.zeekrlife.second_hand.view.TestActivity\x22,\x22$screen_name\x22:\x22com.zeekrlife.second_hand.view.TestActivity\x22,\x22$title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_method\x22:\x22autoTrack\x22,\x22$is_first_day\x22:false,\x22$ip\x22:\x2210.200.88.32\x22,\x22$is_login_id\x22:false,\x22$city\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$province\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$country\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22},\x22_flush_time\x22:1644460631538,\x22map_id\x22:\x221111111\x22,\x22user_id\x22:1234567890,\x22recv_time\x22:1644460631756,\x22project\x22:\x22haha\x22}\xC2\xA0

Python 数据编码

字符编码基础

首先我们来看几个基础编码概念。

  1. ASCII 编码定义了最初计算机可识别的127个字符,包括英文大小写字母、数字、~!@等特殊符号,也就是常见的键盘按键所代表的字符。比如英文字母A的编号为65(16进制位0x41),* 的编号为42。
  2. Unicode编码 。随着互联网发展,127个字符是远远不够的,因为各种语言文字都需要在互联网传播,新的符号也不断的被创造出来,Unicode 字符集就是为此而设计的。其目标是将我们使用到的所有字符都列举出来,并将其编号。比如英文字母A的编号为U+0041,中文字“我”的编号为U+6211,Emoji表情符号👍 的编号为U+1F44D。
  3. UTF-8 编码。Unicode编码带来2个问题:一是字符非常多,如果所有字符都是用相同的二进制位存储,对与存储空间有很大的浪费;另一个是字符不断的扩展,无法定义出使用多少二进制位可以完全表达。考虑到这些问题,UTF-8编码方式设计为一种变长编码,也就是不同的字符,其二进制表达位数不一样,编号越大的字符其编码长度也就越长,其使用频率相对较低,所以加大成都的节省存储空间。比如,英文字母A的编码十六进制串位0x41(长度位1个字节,与其ASCII码一致),中文字“我”的编码为0xe68891(长度为3个字节),Emoji表情符号👍 的编码为0xf09f918d(长度为4个字节)。GBK、Latin-1等编码方式设计都与UTF-8类似。

Python 字符编码

我们先来总结下 Python 的字符串编码的基础。Python 2 由于官方已不再支持,所以本文的讨论只针对Python 3。
加入我在 Python 代码中定义一个变量 x="hello 地球",那么这里面其实有两个内在的编码设计点:

  1. 字符串类型其实是程序代码中的概念,用于代码的编写。以上x 这个Python变脸存储的是Unicode字符串。
  2. 这段代码本身使用的是 UFT-8 编码存储的,数据落盘存储时需要转为特定的编码方式

Python 对与数据编码的转换会涉及到两个方向:

  1. Unicode ==> UTF-8/GBK,从字符串类型转为二进制编码类型,可以使用 "string".encode() 方法。
  2. UTF-8/GBK ==> Unicode,从二进制编码类型转为字符串类型,可以使用 b"bytes".decode() 方法.

如果数据编码要做转换 UTF-8 ==> GBK,则需要做两次转换:UTF-8 ==> Unicode ==> GBK。

另外一个Python字符串处理中常见的概念时 raw string。转义字符设计初衷是将特殊字符(无法直接表示)通过普通字符组合的方式表达出来,这样就可以在程序代码中直接使用,比如代码中使用\n来表示换行,这里反斜杠就是转义字符。当我们需要确切的表示\+n这两个字符连接的字符串时,就需要在转义一次,表示为x="\\n"。如果代码中出现多个连续反斜杠时,可读性就变得极差,因为看到的反斜杠数目与真实逻辑所表达数目是不一致的。Python 中考虑到了这个问题,直接使用 r(raw的缩写)作为字符串定义的前缀,比如x=r"\n"就可以表示\+n这两个字符连接的字符串。

SLS 数据加工应用

SLS 数据加工中通过内置函数来实现编码的转换:str_encode/str_decode,其使用方式与Python中的 str.encode()/bytes.decode() 完全一致,以上中提到的复杂数据为例。
原始数据如下:

content: {\x22time\x22:1644460630577,\x22type\x22:\x22track\x22,\x22distinct_id\x22:\x221111111\x22,\x22login_id\x22:\x221111111\x22,\x22anonymous_id\x22:\x22b13f22aca3faa599\x22,\x22lib\x22:{\x22$lib_method\x22:\x22autoTrack\x22,\x22$lib\x22:\x22Android\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$app_version\x22:\x221.1.23\x22,\x22$lib_detail\x22:\x22com.haha.second_hand.view.TestActivity######\x22},\x22event\x22:\x22$AppViewScreen\x22,\x22properties\x22:{\x22$os_version\x22:\x222.0.0\x22,\x22$model\x22:\x22XXX\x22,\x22$os\x22:\x22iOS\x22,\x22$screen_width\x22:1133,\x22$brand\x22:\x22TEST\x22,\x22$screen_height\x22:2453,\x22$app_version\x22:\x221.1.23\x22,\x22$lib\x22:\x22Android\x22,\x22$device_id\x22:\x22b13f22aca3faa599\x22,\x22$app_name\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_version\x22:\x225.2.6\x22,\x22$timezone_offset\x22:-480,\x22$app_id\x22:\x22com.haha.mobile\x22,\x22$manufacturer\x22:\x22TEST\x22,\x22platform_type\x22:\x22Android\x22,\x22$referrer_title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$wifi\x22:true,\x22$network_type\x22:\x22WIFI\x22,\x22$referrer\x22:\x22com.haha.main.MainActivity\x22,\x22$url\x22:\x22com.haha.second_hand.view.TestActivity\x22,\x22$screen_name\x22:\x22com.haha.second_hand.view.TestActivity\x22,\x22$title\x22:\x22\xe6\x88\x91\xe6\x98\xaf\xe8\xb0\x81\x22,\x22$lib_method\x22:\x22autoTrack\x22,\x22$is_first_day\x22:false,\x22$ip\x22:\x2210.200.88.32\x22,\x22$is_login_id\x22:false,\x22$city\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$province\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22,\x22$country\x22:\x22\xE4\xBF\x9D\xE7\x95\x99IP\x22},\x22_flush_time\x22:1644460631538,\x22map_id\x22:\x221111111\x22,\x22user_id\x22:1234567890,\x22recv_time\x22:1644460631756,\x22project\x22:\x22haha\x22}\xC2\xA0

加工脚本:

e_set(
    "content",
    str_decode(
        str_encode(
            str_decode(str_encode(v("content"), "latin1"), "unicode_escape"), "latin1",
        ),
        "utf8",
    ),
)

结果如下,是一个JSON对象:

content: {"time":1644460630577,"type":"track","distinct_id":"1111111","login_id":"1111111","anonymous_id":"b13f22aca3faa599","lib":{"$lib_method":"autoTrack","$lib":"Android","$lib_version":"5.2.6","$app_version":"1.1.23","$lib_detail":"com.haha.second_hand.view.TestActivity######"},"event":"$AppViewScreen","properties":{"$os_version":"2.0.0","$model":"XXX","$os":"iOS","$screen_width":1133,"$brand":"TEST","$screen_height":2453,"$app_version":"1.1.23","$lib":"Android","$device_id":"b13f22aca3faa599","$app_name":"我是谁","$lib_version":"5.2.6","$timezone_offset":-480,"$app_id":"com.haha.mobile","$manufacturer":"TEST","platform_type":"Android","$referrer_title":"我是谁","$wifi":true,"$network_type":"WIFI","$referrer":"com.haha.main.MainActivity","$url":"com.haha.second_hand.view.TestActivity","$screen_name":"com.haha.second_hand.view.TestActivity","$title":"我是谁","$lib_method":"autoTrack","$is_first_day":false,"$ip":"10.200.88.32","$is_login_id":false,"$city":"保留IP","$province":"保留IP","$country":"保留IP"},"_flush_time":1644460631538,"map_id":"1111111","user_id":1234567890,"recv_time":1644460631756,"project":"haha"}  

编解码函数通过 errors 参数来处理编码错误,其可选值:

  1. ignore:忽略
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="ignore"))

结果为:
xxx: "test "

  1. strict:直接报错,丢弃此条数据
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="ignore"))

执行时直接报错。

  1. replace:使用?替换
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="replace"))

结果为:

xxx: "test ????"
  1. xmlcharrefreplace:使用 XML 字符引用替换
e_set("xxx", str_encode("test 测试数据", encoding="ascii", errors="xmlcharrefreplace"))

结果为:

xxx: "test 测试数据"

总结

数据编码在大数据处理的基础操作,本文讨论了 Python3 中的数据编码方案,以及在 SLS 数据加工中内置的数据编解码函数使用。
参考资料:

  1. 《Python and Unicode》PPT
  2. Python 文档 Unicode HOWTO

下图是 SLS 团队的技术博客,我们会不定期推出技术文章分享和产品更新介绍,欢迎大家订阅,有任何问题也欢迎与我们反馈。
SLS QR.png

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
8天前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
114 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
12天前
|
机器学习/深度学习 自然语言处理 API
如何使用阿里云的语音合成服务(TTS)将文本转换为语音?本文详细介绍了从注册账号、获取密钥到编写Python代码调用TTS服务的全过程
如何使用阿里云的语音合成服务(TTS)将文本转换为语音?本文详细介绍了从注册账号、获取密钥到编写Python代码调用TTS服务的全过程。通过简单的代码示例,展示如何将文本转换为自然流畅的语音,适用于有声阅读、智能客服等场景。
55 3
|
8天前
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle的联机重做日志文件与数据写入过程
在Oracle数据库中,联机重做日志文件记录了数据库的变化,用于实例恢复。每个数据库有多组联机重做日志,每组建议至少有两个成员。通过SQL语句可查看日志文件信息。视频讲解和示意图进一步解释了这一过程。
|
1月前
|
SQL 存储 人工智能
阿里云日志服务的傻瓜式极易预测模型
预测服务有助于提前规划,减少资源消耗和成本。阿里云日志服务的AI预测服务简化了数学建模,仅需SQL操作即可预测未来指标,具备高准确性,并能处理远期预测。此外,通过ScheduledSQL功能,可将预测任务自动化,定时执行并保存结果。
64 3
|
1月前
|
数据采集 机器学习/深度学习 存储
使用 Python 清洗日志数据
使用 Python 清洗日志数据
35 2
|
1月前
|
监控 网络协议 CDN
阿里云国际监控查询流量、用量查询流量与日志统计流量有差异?
阿里云国际监控查询流量、用量查询流量与日志统计流量有差异?
|
2月前
|
SQL 人工智能 运维
在阿里云日志服务轻松落地您的AI模型服务——让您的数据更容易产生洞见和实现价值
您有大量的数据,数据的存储和管理消耗您大量的成本,您知道这些数据隐藏着巨大的价值,但是您总觉得还没有把数据的价值变现出来,对吗?来吧,我们用一系列的案例帮您轻松落地AI模型服务,实现数据价值的变现......
194 3
|
13天前
|
XML 安全 Java
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
121 30
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
|
1月前
|
XML JSON Java
Logback 与 log4j2 性能对比:谁才是日志框架的性能王者?
【10月更文挑战第5天】在Java开发中,日志框架是不可或缺的工具,它们帮助我们记录系统运行时的信息、警告和错误,对于开发人员来说至关重要。在众多日志框架中,Logback和log4j2以其卓越的性能和丰富的功能脱颖而出,成为开发者们的首选。本文将深入探讨Logback与log4j2在性能方面的对比,通过详细的分析和实例,帮助大家理解两者之间的性能差异,以便在实际项目中做出更明智的选择。
225 3
|
1月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1630 14