PySpark - UnicodeEncodeError:'ascii'编解码器无法编码字符

时间:2016-09-23 13:44:46

标签: python python-2.7 apache-spark pyspark

使用spark.read.csv使用encoding='utf-8'将带有外来字符(åäö)的数据框加载到Spark中并尝试执行简单的show()。

>>> df.show()

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/spark/python/pyspark/sql/dataframe.py", line 287, in show
print(self._jdf.showString(n, truncate))
UnicodeEncodeError: 'ascii' codec can't encode character u'\ufffd' in position 579: ordinal not in range(128)

我认为这可能与Python本身有关,但我无法理解提及here for example的任何技巧如何在PySpark和show() - 函数的上下文中应用。

3 个答案:

答案 0 :(得分:15)

https://issues.apache.org/jira/browse/SPARK-11772讨论了这个问题并提供了一个解决方案:

export PYTHONIOENCODING=utf8

在运行pyspark之前。我想知道上面的原因是什么,因为即使没有它,sys.getdefaultencoding()也会为我返回utf-8

How to set sys.stdout encoding in Python 3?也谈到了这一点,并为Python 3提供了以下解决方案:

import sys
sys.stdout = open(sys.stdout.fileno(), mode='w', encoding='utf8', buffering=1)

答案 1 :(得分:0)

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

这对我有用,我预先设置了编码,并且在整个脚本中都有效。

答案 2 :(得分:0)

在以下版本的Spark和Python中,我遇到了相同的问题:

SPARK-2.4.0

Python-2.7.5

以上解决方案均不适合我。

对我来说,问题是在尝试将结果RDD保存到HDFS位置时发生的。我从HDFS位置获取输入并将其保存到HDFS位置。以下是出现此问题时用于读写操作的代码:

读取输入数据:

monthly_input = sc.textFile(monthly_input_location).map(lambda i: i.split("\x01"))
monthly_input_df = sqlContext.createDataFrame(monthly_input, monthly_input_schema)

写入HDFS:

result = output_df.rdd.map(tuple).map(lambda line: "\x01".join([str(i) for i in line]))
result.saveAsTextFile(output_location)

我将读写代码分别更改为以下代码:

阅读代码:

monthly_input = sqlContext.read.format("csv").option('encoding', 'UTF-8').option("header", "true").option("delimiter", "\x01").schema(monthly_input_schema).load(monthly_input_location)

书写代码:

output_df.write.format('csv').option("header", "false").option("delimiter", "\x01").save(output_location)

这不仅解决了问题,而且还大大提高了IO性能(近3倍)。

但是在使用上面的写逻辑时有一个已知的问题,我还没有找到合适的解决方案。如果输出中有空白字段,由于CSV编码,它将显示用双引号(“”)括起来的空白值。

对我来说,目前这个问题并不重要。无论如何,我都将输出加载到配置单元中,并且在导入自身时可以删除双引号。

PS:我仍在使用SQLContext。尚未升级到SparkSession。但是到目前为止,我尝试过的基于SparkSession的代码中的类似读写操作也将类似地工作。

相关问题