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數據了。

 

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