首页 > 解决方案 > Spark:日文字母在 HDFS 中创建的 Paquet 文件中出现乱码

问题描述

我有一个 Spark 作业,它在 S3 上读取一些 CSV 文件,处理并将结果保存为镶木地板文件。这些 CSV 包含日语文本。

当我在本地运行此作业,读取 S3 CSV 文件并将镶木地板文件写入本地文件夹时,日文字母看起来不错。

但是当我在我的 spark 集群上运行它,读取相同的 S3 CSV 文件并将 parquet 写入 HDFS 时,所有的日文字母都是乱码。

在 spark-cluster 上运行(数据乱码)

spark-submit --master spark://spark-master-stg:7077 \
--conf spark.sql.session.timeZone=UTC \
--conf spark.driver.extraJavaOptions="-Ddatabase=dev_mall -Dtable=table_base_TEST -DtimestampColumn=time_stamp -DpartitionColumns= -Dyear=-1 -Dmonth=-1 -DcolRenameMap=  -DpartitionByYearMonth=true -DaddSpdbCols=false -DconvertTimeDateCols=true -Ds3AccessKey=xxxxx -Ds3SecretKey=yyyy -Ds3BasePath=s3a://bucket/export/e2e-test -Ds3Endpoint=http://s3.url -DhdfsBasePath=hdfs://nameservice1/tmp/encoding-test -DaddSpdbCols=false" \
--name Teradata_export_test_ash \
--class com.mycompany.data.spark.job.TeradataNormalTableJob \
--deploy-mode client \
https://artifactory.maven-it.com/spdb-mvn-release/com.mycompany.data/teradata-spark_2.11/0.1/teradata-spark_2.11-0.1-assembly.jar

在本地运行(数据看起来不错)

spark-submit --master local \
--conf spark.sql.session.timeZone=UTC \
--conf spark.driver.extraJavaOptions="-Ddatabase=dev_mall -Dtable=table_base_TEST -DtimestampColumn=time_stamp -DpartitionColumns= -Dyear=-1 -Dmonth=-1 -DcolRenameMap=  -DpartitionByYearMonth=true -DaddSpdbCols=false -DconvertTimeDateCols=true -Ds3AccessKey=xxxxx -Ds3SecretKey=yyyy -Ds3BasePath=s3a://bucket/export/e2e-test -Ds3Endpoint=http://s3.url -DhdfsBasePath=/tmp/encoding-test -DaddSpdbCols=false" \
--name Teradata_export_test_ash \
--class com.mycompany.data.spark.job.TeradataNormalTableJob \
--deploy-mode client \
https://artifactory.maven-it.com/spdb-mvn-release/com.mycompany.data/teradata-spark_2.11/0.1/teradata-spark_2.11-0.1-assembly.jar

从上面可以看出,两个 spark-submit 作业都指向同一个 S3 文件,不同的是在 Spark 集群上运行时,结果是写入 HDFS。

读取 CSV:

def readTeradataCSV(schema: StructType, path: String) : DataFrame = {
        dataFrameReader.option("delimiter", "\u0001")
          .option("header", "false")
          .option("inferSchema", "false")
          .option("multiLine","true")
          .option("encoding", "UTF-8")
          .option("charset", "UTF-8")
          .schema(schema)
          .csv(path)

     }

这就是我写镶木地板的方式:

finalDf.write
      .format("parquet")
      .mode(SaveMode.Append)
      .option("path", hdfsTablePath)
      .option("encoding", "UTF-8")
      .option("charset", "UTF-8")
      .partitionBy(parCols: _*)
      .save()

HDFS 上的数据如下所示: 在此处输入图像描述

有关如何解决此问题的任何提示?

输入 CSV 文件是否必须采用 UTF-8 编码?

**更新** 发现它与 Parquet 无关,而是 CSV 加载。在这里问了一个单独的问题:

Spark CSV阅读器:日文文本乱码并处理多行

标签: apache-sparkhadoopcharacter-encodingparquetspark-csv

解决方案


Parquet 格式没有用于encodingcharsetcf的选项。https://github.com/apache/spark/blob/branch-2.4/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/parquet/ParquetOptions.scala

因此,您的代码无效:

finalDf.write
      .format("parquet")
      .option("encoding", "UTF-8")
      .option("charset", "UTF-8")
(...)

这些选项仅适用于 CSV,您应该在读取源文件时设置它们(或者更确切地说是其中之一,因为它们是同义词) 。 假设您使用 Spark 数据帧 API 来读取 CSV;否则你就靠自己了。


推荐阅读