Spark每日半小时(18)——JSON

JSON是一种使用较广的半结构化数据格式。读取JSON数据的最简单的方式是将数据作为文本文件读取,然后使用JSON解析器来对RDD中的值进行映射操作。类似地,也可以使用我们喜欢的JSON序列化库来将数据转为字符串,然后将其写出去。在Java和Scala中也可以使用一个自定义Hadoop格式来操作JSON数据。

读取JSON

将数据作为文本文件读取,然后对JSON数据进行解析,这样的方法可以在所有支持的编程语言中使用。这种方法假设文件中的每一行都是一条JSON记录。如果你有跨行的JSON数据,你就只能读入整个文件,然后对每个文件进行解析。如果在你使用的语言中构建一个JSON解析器的开销较大,你可以使用mapPartitions()来重用解析器。

我们使用的这三种编程语言中有大量可用的JSON库,在Java中会使用Jackson。使用简单,性能还不错

/**
 * @author DKing
 * @description
 * @date 2019/6/16
 */
public class JsonProcessor {
    public static void main(String[] args) {
        class ParseJson implements FlatMapFunction<Iterator<String>, Person> {

            @Override
            public Iterator<Person> call(Iterator<String> stringIterator) throws Exception {
                ArrayList<Person> people = new ArrayList<>();
                ObjectMapper mapper = new ObjectMapper();
                while (stringIterator.hasNext()) {
                    String line = stringIterator.next();
                    try {
                        people.add(mapper.readValue(line, Person.class));
                    } catch (Exception e) {
                        // 跳过失败的数据
                    }
                }
                return people.iterator();
            }
        }
        SparkConf conf = new SparkConf().setMaster("local").setAppName("TextFile");
        JavaSparkContext sc = new JavaSparkContext(conf);
        JavaRDD<String> input = sc.textFile("file.json");
        JavaRDD<Person> result = input.mapPartitions(new ParseJson());
    }
}

处理格式不正确的记录有可能会引起很严重的问题,尤其对于像JSON这样的半结构化数据来说。对于小数据集来说,可以接受在遇到错误的输入时停止程序,但是对于大规模数据集来说,格式错误是家常便饭。如果选择跳过格式不正确的数据,你应该尝试使用累加器来跟踪错误的个数。

保存JSON

写出JSON文件比读取它要简单得多,因为不需要考虑格式错误的数据,并且也知道要写出的数据的类型。可以使用之前将字符串RDD转为解析好的JSON数据的库,将由结构化数据组成的RDD转为字符串RDD,然后使用Spark的文本文件API写出去。

假设我们要选出喜爱熊猫的人,就可以从第一步中获取输入数据,然后筛选出喜爱熊猫的人。

/**
 * @author DKing
 * @description
 * @date 2019/6/16
 */
public class JsonProcessor {
    public static void main(String[] args) {
        class WriteJson implements FlatMapFunction<Iterator<Person>, String> {
            @Override
            public Iterator<String> call(Iterator<Person> personIterator) throws Exception {
                ArrayList<String> text = new ArrayList<>();
                ObjectMapper mapper = new ObjectMapper();
                while (personIterator.hasNext()) {
                    Person person = personIterator.next();
                    text.add(mapper.writeValueAsString(person));
                }
                return text.iterator();
            }
        }
        class ParseJson implements FlatMapFunction<Iterator<String>, Person> {
            @Override
            public Iterator<Person> call(Iterator<String> stringIterator) throws Exception {
                ArrayList<Person> people = new ArrayList<>();
                ObjectMapper mapper = new ObjectMapper();
                while (stringIterator.hasNext()) {
                    String line = stringIterator.next();
                    try {
                        people.add(mapper.readValue(line, Person.class));
                    } catch (Exception e) {
                        // 跳过失败的数据
                    }
                }
                return people.iterator();
            }
        }
        SparkConf conf = new SparkConf().setMaster("local").setAppName("TextFile");
        JavaSparkContext sc = new JavaSparkContext(conf);
        JavaRDD<String> input = sc.textFile("file.json");

        JavaRDD<Person> result = input.mapPartitions(new ParseJson()).filter(
                new LikesPandas());
        JavaRDD<String> formatted = result.mapPartitions(new WriteJson());
        String outfile = "/opt/getPandasLiker";
        formatted.saveAsTextFile(outfile);
    }
}

这样一来,就可以通过已有的操作文本数据的机制和JSON库,使用Spark轻易地读取和保存JSON数据了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章