【发布时间】:2019-12-16 05:20:10
【问题描述】:
我有一个类似下面的 python 代码来使用 pyspark 从 Oracle 读取数据。
tableDF = spark.read \
.format("jdbc") \
.option("driver", "oracle.jdbc.driver.OracleDriver") \
.option("url", "jdbc:oracle:thin:@" + hostid + ".dev.com:1521/" + databaseinstance) \
.option("dbtable", sqlstring) \
.option("numPartitions", 1) \
.option("fetchsize", fetchsize) \
.option("user", contextname) \
.option("password", contextname) \
.load() \
数据库源字符集是 US7ASCII,但由于没有验证将数据加载到 Oracle 中,它包含具有各种编码字符集的数据。 简而言之,即使 DB 字符集是 US7ASCII,它的列中也包含 UTF8、ISO-8859-1 混合编码的数据。
我能够成功地将数据从 Oracle 读取到数据帧中而没有任何问题,但是由于 pyspark 强制编码为 UTF-8 导致我的一些数据具有 UTF-8 替换字符,例如 EFBFA2EFBE80EFBE93 由于在包含源字符集为 US7ASCII 的列中存在 Unicode 字符 E2 80 93 而无法正确识别
该字段的类型是varchar。存储的值为–,即en dash character。返回的是字节 0xE2 0x80 0x93,而不是字符,这些字节被转换为 ???。
在NAME 值为的行上调用DUMP(NAME,'1016')
CLINIC – NORTH
返回:
Typ=1 Len=69 CharacterSet=US7ASCII: 43,4f,52,41,20,e2,80,93,20,4e,4f,52,54,48,
因此,我希望简单地从 Oracle 读取数据,而不对我的数据进行任何编码。基本上,我不希望对正在检索的数据进行任何强制编码。我只是想要它们在 Oracle 中的存储方式。
有没有办法通过 pyspark 关闭此默认编码为 UTF-8? 要么 如何使 JDBC 或 PYTHON 驱动程序以任何编码形式处理这些字符?
正如我已经提到的,因为我的数据库包含混合编码字符集,强制任何特定编码(如 UTF8/US-ASCII/ISO-8859-1)适用于某些数据,但不适用于其他数据,这就是为什么我需要一种根本不强制执行任何编码的方法。
任何帮助或指导将不胜感激。谢谢
【问题讨论】:
-
当您尝试使用错误的代码页读取 non-Unicode 文本时,会出现 Unicode 替换字符。关闭 UTF8 转换不会使问题消失,使用的代码页仍然是错误的。 Oracle 中的文本是如何存储的?什么是类型的列?除非它是 Unicode 类型之一,否则您必须使用正确的代码页来阅读它。
-
无论如何,Spark 是基于 JVM 构建的,其字符串是 Unicode,特别是 UTF16。问题出在 JDBC 驱动程序本身,而不是 Spark。
-
@PanagiotisKanavos 是的,没错。当存储在 Oracle 中的底层字符不兼容 UTF8 时,转换就会变得混乱。即使 Oracle 中的字符集是 US7ASCII,因为我们在将数据加载到 Oracle 时没有进行任何验证,我们不能保证所有底层数据都是 US7ASCII,因为 oracle 也可以在其列中存储扩展的 ASCII。所以,这里有两种方法,要么我需要正确识别底层编码,要么根本不编码。因为在我的情况下,底层数据可以有任何编码,最好完全不编码
-
那么,是否有任何配置可以通过 pyspark 传递给 JDBC 驱动程序以避免这种强制编码?
-
没有强制编码,或者更确切地说,每个 Java/JVM 应用程序,包括 Spark,都使用 Unicode。问题是不正确的字符集。否则,JDBC 驱动程序将正常工作。您必须找出错误发生的位置。检查存储的文本、列排序规则、实际内容。列类型有哪些?可能是文本已经在数据库中损坏了吗?如果 Oracle 驱动程序能够使用正确的代码页转换
varchar值,这表明文本可能使用错误的代码页存储,则不会有任何问题
标签: python encoding utf-8 pyspark pyspark-sql