Apache Spark:使用SparkContext.textFile读取变音符号

时间:2016-06-10 08:15:04

标签: encoding apache-spark

我写了一个Spark应用程序,它从CSV文件中读取,过滤和打印数据,保存在HDFS中。当我将CSV下载到我的电脑并打开它时,一切正常,所有的变音符号都能正确显示。但是:当我运行我的应用程序时,变音符号显示不正确,它们都显示为�

是否有可能设置编码以通过Spark中的.textFile事务加载csv或“转换”输入?

这似乎是一个无法解决的问题: https://issues.apache.org/jira/browse/SPARK-1849

由于文件的UTF-8编码而出现问题。似乎,使用.hadoopFile有一种解决方法,但我不知道如何使用此方法。有人可以帮忙吗?

尝试了以下代码,但没有成功:

test.txt文件:

ÄPPLE
APPLE
ÖPPLE
ÜPPLE

Spark程序:

public static void main(String[] args) throws ClassNotFoundException {
    String inputFile = args[0];

    SparkConf sparkConf = new SparkConf().setAppName("EdekaOwgCheckUmlauts");
    sparkConf.registerKryoClasses(new Class<?>[]{
        Class.forName("org.apache.hadoop.io.LongWritable"),
        Class.forName("org.apache.hadoop.io.Text")
    });

    JavaSparkContext sc = new JavaSparkContext(sparkConf);

    JavaRDD<Text> input = sc.hadoopFile(inputFile, TextInputFormat.class, LongWritable.class, Text.class).map(new Function<Tuple2<LongWritable,Text>, Text>() {
        @Override
        public Text call(Tuple2<LongWritable, Text> v1) throws Exception {
            return v1._2();
        }
    });

    JavaRDD<Text> filtered = input.filter(new Function<Text, Boolean>() {
        @Override
        public Boolean call(Text v1) throws Exception {
            return v1.toString().toLowerCase().contains("pple");        // LOOK FOR ÄPPLE, APPLE etc.
        }
    });

    List<Text> collected = filtered.collect();
    System.out.println("=== PRINT ===");
    for(Text row : collected) {
        try {
            System.out.println(row.decode(row.getBytes()));
        } catch (CharacterCodingException e) {
            e.printStackTrace();
        }
    }
}

控制台输出:

�PPLE
APPLE
�PPLE
�PPLE

该文件使用charset iso-8859-1

进行编码

致电file -i myfile.csv会显示以下信息:

myfile.csv: text/plain; charset=iso-8859-1

我尝试使用以下代码将此charset转换为utf-8:

JavaRDD<String> inputRDD = sc.textFile(inputFile);
List<String> asList = inputRDD.collect();
for(String a : asList) {

    try {
        byte[] isoBytes = a.getBytes("ISO-8859-1");
        System.out.println(new String(isoBytes, "UTF-8"));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

没有成功,控制台会打印?而不是ä,ö,ü...

2 个答案:

答案 0 :(得分:2)

这是使用hadoopFile和从右字符集重新编码的最短版本(iso-8859-1到UTF-8):

import org.apache.hadoop.io.LongWritable
import org.apache.hadoop.io.Text
import org.apache.hadoop.mapred.TextInputFormat

val file=sc.hadoopFile[LongWritable, Text, TextInputFormat]("/file...").
 mapPartitions(
   _.map(line => new String(line._2.getBytes, 0, line._2.getLength, "iso-8859-1"))
)

希望有所帮助。

这只能在使用spark textFile读取文件后使用hadoop.io.Text而不是字符串。

或许有人理解为什么?

答案 1 :(得分:1)

您可以编写自己的自定义TextInputFormat并将其与newAPIHadoopFile一起使用。 TextInputFormat使用Text.class来处理以UTF-8存储数据的数据:主要思想是使用String.class(使用正确的编码)。

按照TextInputFormat类重新编写需要更改的内容。这包括重写您自己的RecordReader,LineRecordReader,SplitLineReader。这不应该太复杂,但不幸的是很长。

然后您应该可以使用这样的自定义文本输入格式:

// JavaSparkContext sc
//File path path
JavaPairRDD<String, BytesWritable> zip = sc.newAPIHadoopFile(path, 
         CustomTextInputFormat.class,
         LongWritable.class,
         String.class,
         sc.hadoopConfiguration());

希望这有帮助。