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