【问题标题】:spark read wholeTextFiles with non UTF-8 encodingspark使用非UTF-8编码读取wholeTextFiles
【发布时间】:2017-08-29 06:49:56
【问题描述】:

我想通过非 UTF-8 编码读取整个文本文件

val df = spark.sparkContext.wholeTextFiles(path, 12).toDF

变成火花。如何更改编码? 我想阅读 ISO-8859 编码的文本,但它不是 CSV,它类似于 xml:SGML。

编辑

也许应该使用自定义的 Hadoop 文件输入格式?

【问题讨论】:

    标签: apache-spark character-encoding apache-spark-sql


    【解决方案1】:

    您可以改为使用SparkContext.binaryFiles() 读取文件,并为指定所需字符集的内容构建String。例如:

    val df = spark.sparkContext.binaryFiles(path, 12)
      .mapValues(content => new String(content.toArray(), StandardCharsets.ISO_8859_1))
      .toDF
    

    【讨论】:

    • 现在看,这很简单!
    【解决方案2】:

    这很简单。

    这里是源代码,

    import java.nio.charset.Charset
    
    import org.apache.hadoop.io.{Text, LongWritable}
    import org.apache.hadoop.mapred.TextInputFormat
    import org.apache.spark.SparkContext
    import org.apache.spark.rdd.RDD
    
    object TextFile {
      val DEFAULT_CHARSET = Charset.forName("UTF-8")
    
      def withCharset(context: SparkContext, location: String, charset: String): RDD[String] = {
        if (Charset.forName(charset) == DEFAULT_CHARSET) {
          context.textFile(location)
        } else {
          // can't pass a Charset object here cause its not serializable
          // TODO: maybe use mapPartitions instead?
          context.hadoopFile[LongWritable, Text, TextInputFormat](location).map(
            pair => new String(pair._2.getBytes, 0, pair._2.getLength, charset)
          )
        }
      }
    }
    

    从这里复制过来。

    https://github.com/databricks/spark-csv/blob/master/src/main/scala/com/databricks/spark/csv/util/TextFile.scala

    使用它。

    https://github.com/databricks/spark-csv/blob/master/src/test/scala/com/databricks/spark/csv/util/TextFileSuite.scala

    编辑:

    如果你需要全文文件,

    这是实现的实际来源。

    def wholeTextFiles(
          path: String,
          minPartitions: Int = defaultMinPartitions): RDD[(String, String)] = withScope {
        assertNotStopped()
        val job = NewHadoopJob.getInstance(hadoopConfiguration)
        // Use setInputPaths so that wholeTextFiles aligns with hadoopFile/textFile in taking
        // comma separated files as input. (see SPARK-7155)
        NewFileInputFormat.setInputPaths(job, path)
        val updateConf = job.getConfiguration
        new WholeTextFileRDD(
          this,
          classOf[WholeTextFileInputFormat],
          classOf[Text],
          classOf[Text],
          updateConf,
          minPartitions).map(record => (record._1.toString, record._2.toString)).setName(path)
      }
    

    尝试改变:

    .map(record => (record._1.toString, record._2.toString))
    

    到(可能):

    .map(record => (record._1.toString, new String(record._2.getBytes, 0, record._2.getLength, "myCustomCharset")))
    

    【讨论】:

    • 这似乎是一个好的开始。但是,我怎样才能实现 WholeTextFiles 的类似行为,其中文件路径作为键包含,并且每个文件将创建一行,这与上面的 spark-csv 变体不同,其中文件中的行将被标记为 RDD 中的行。
    • 我想这已经差不多了。但是.map(record => (record._1.toString, record._2.toString, "iso-8859-1")).setName(path)会因为found : org.apache.spark.rdd.RDD[(String, String, String)] [error] required: org.apache.spark.rdd.RDD[(String, String)] 而编译失败
    • 我不确定WholeTextFileInputFormat 是否不需要使用所需的编码重新定义?
    • 是否需要将RecordReader[Text, Text] 替换为未使用UTF-8 的自定义Textimplementation?
    猜你喜欢
    • 1970-01-01
    • 2019-01-03
    • 2019-12-27
    • 2016-08-14
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 2013-07-04
    • 1970-01-01
    相关资源
    最近更新 更多