一、背景介绍
在数据开发过程中任务要求将数据由数据湖将数据推送至MySQL数据库。数据类型大多是字符串类型。原本没有什么特别,属于常规任务。但是在推送是由于字符集的问题,无法正常推送。
1. 对应工具
数据湖 Hive
下游数据库 MySQL
传输工具 DataX
二、所遇问题
数据湖所支持的字符集为 udf8mb4,而下游mysql数据库所支持的 udf-8。由于 udf8mb4 是 udf-8 的扩展集。即 udf8mb4 范围大于 udf-8 ,且数据中包含emoji表情超出 udf-8 所支持范围。所以导致数据无法正常传输。
报错:
java.sql.BatchUpdateException: Conversion from collation utf8mb4_0900_ai_ci into utf8_general_ci impossible for parameter三、解决方案
1. 方案一(不适用):
最直接的方法也是网上大多的处理办法:改下游mysql的字符集。
但是首先需要判断mysql版本是否支持utf8mb4。如果您的 MySQL 版本太低,无法支持 utf8mb4_0900_ai_ci,那么您可以考虑升级 MySQL 版本到 8.0.0 或更高版本。
特别提示需要将MySQL配置中的字符集全部修改。
character_set_client utf8mb4
character_set_connection utf8mb4
character_set_database utf8mb4
character_set_filesystem binary
character_set_results utf8mb4
character_set_server utf8mb4
character_set_system utf8mb3即以上所示配置都需要修改。
踩坑:我的需求是将数据从数据湖hive推送至MySQL,所以必然会用到MySQL服务。但是在修改MySQL服务后会涉及服务重启,由于涉及到其他业务部门的调用,需要多方协调。太麻烦啦!故此方法不可取。
2. 方案二(采用):
经与业务同事沟通,由于utf8mb4大多为emoji表情包,且包含此内容的数据条数较少。故通过将脏数据(数据中包含utf8mb4集字符)过滤掉的方法解决问题。
判断是否为emoji字符
def is_emoji_character(char):
# 这是一个非常简化的检查,只涵盖了部分Emoji范围
# 实际的Emoji检测可能需要更复杂的逻辑或使用第三方库
code_point = ord(char)
# 检查是否在某个Emoji范围内(这里只是示例,不是完整的范围)
# 例如,U+1F600 到 U+1F64F 是常见的Emoji范围之一
return 0x1F600 <= code_point <= 0x1F64F or \
0x1F300 <= code_point <= 0x1F5FF or \
0x1F680 <= code_point <= 0x1F6FF or \
0x1F700 <= code_point <= 0x1F77F or \
0x1F780 <= code_point <= 0x1F7FF or \
0x1F800 <= code_point <= 0x1F8FF or \
0x1F900 <= code_point <= 0x1F9FF or \
0x1FA00 <= code_point <= 0x1FA6F or \
0x1FA70 <= code_point <= 0x1FAFF # ... 可以添加更多范围定位对应数据并输出到其他表中
def check_for_emoji():
cur = datalake_connect()
# 数据日期为前一天
etl_date='${biz.date,-1,yyyy-MM-dd}'
selectsql1 = "select id,title,source_id,text,text_nohtml from mytable1 where etl_date='%s' " % (etl_date)
print(selectsql1)
news = cur.sql(selectsql1).collect()
if news:
# 获得行数据
for value in news:
# print(value)
contains_emoji = False
# 获得字段字段数据
for check_string in value:
if check_string is None:
continue
for check_char in check_string:
try:
if is_emoji_character(check_char):
contains_emoji = True
break # 如果只需要知道是否存在Emoji,找到后就可以退出循环
except Exception as e:
print(check_char)
print(e)
if contains_emoji:
break
if contains_emoji:
print("是一个包含emoji的字符串"+value[0])
insertsql2 = "insert into mytable2 values('%s','%s','%s','%s')"%(value[0],value[1],value[2],etl_date)
print(insertsql2)
news = cur.sql(insertsql2)
else:
print("是一个不包含emoji的字符串"+value[0])
else:
print("数据日期没有数据;结束!")注:内涵特殊数据库执行方法可忽略
通过以上方法可以将包含emoji的数据输出到其他的表2中,后续根据表2所存id过滤数据。则可以将非emoji数据推送至下游数据库了。
评论