第六章:鍵值對RDD的操作
- 鍵值對RDD的操作用途:
- 聚合,統計,分組
史上最簡單的spark教程
所有代碼示例地址:https://github.com/Mydreamandreality/sparkResearch
(提前聲明:文章由作者:張耀峯 結合自己生產中的使用經驗整理,最終形成簡單易懂的文章,寫作不易,轉載請註明)
(文章參考:Elasticsearch權威指南,Spark快速大數據分析文檔,Elasticsearch官方文檔,實際項目中的應用場景)
(幫到到您請點點關注,文章持續更新中!)
Git主頁 https://github.com/Mydreamandreality
- 鍵值對的數據一般需要經過ETL,最終轉換成我們需要的數據
- spark對鍵值對的RDD提供了一些新的接口,pairRDD
- 提供並行操作各個鍵或跨節點重新進行數據分組的操作接口
- 下面都是針對pairRDD的操作案例
現在這裏列舉一下pairRDD的常用函數,結合java案例代碼很好理解
操作數據:(以鍵值對集合{(1, 2), (3, 4), (3, 6)}爲例)
大概瞭解之後我們就可以直接看java代碼的案例了
pair RDD(鍵值對)的轉化操作
代碼示例:
public static void run(JavaSparkContext sparkContext) {
JavaRDD<String> rdd = sparkContext.parallelize(Arrays.asList("test", "java", "python"));
//把RDD的第一個字符當做Key
PairFunction<String, String, String> pairFunction = new PairFunction<String, String, String>() {
@Override
public Tuple2<String, String> call(String s) throws Exception {
return new Tuple2<>(s.split(" ")[0], s);
}
};
//此處創建好pairRDD
JavaPairRDD<String, String> pairRdd = rdd.mapToPair(pairFunction);
//下層都是對pairRDD的操作演示
/*合併含有相同鍵的值*/
pairRdd.reduceByKey(new Function2<String, String, String>() {
@Override
public String call(String v1, String v2) throws Exception {
return v1 + v2;
}
});
/*相同key的元素進行分組*/
pairRdd.groupByKey();
/*對pair中的每個值進行應用*/
pairRdd.mapValues(new Function<String, Object>() {
@Override
public Object call(String v1) throws Exception {
return v1 + "sirZ";
}
});
/*返回只包含鍵的RDD*/
pairRdd.keys();
/*返回只包含值的RDD*/
pairRdd.values();
/*返回根據鍵排序的RDD*/
pairRdd.sortByKey();
}
上面的案例是針對單個RDD元素進行操作
這裏就針對兩個RDD進行操作 (可以理解爲MySQL表連接?我不知道是否可以這麼理解)
代碼示例
/**
* Created by 張燿峯
* pairRDD入門案例
*
* @author 孤
* @date 2019/3/19
* @Varsion 1.0
*/
public class PairRdd {
public static void run(JavaSparkContext sparkContext) {
JavaRDD<String> rdd = sparkContext.parallelize(Arrays.asList("test", "java", "python"));
PairFunction<String, String, String> pairFunction = new PairFunction<String, String, String>() {
@Override
public Tuple2<String, String> call(String s) throws Exception {
return new Tuple2<>(s.split(" ")[0], s);
}
};
//此處創建好pairRDD
JavaPairRDD<String, String> pairRdd = rdd.mapToPair(pairFunction);
//下層都是對pairRDD的操作演示
/*合併含有相同鍵的值*/
pairRdd.reduceByKey(new Function2<String, String, String>() {
@Override
public String call(String v1, String v2) throws Exception {
return v1 + v2;
}
});
/*相同key的元素進行分組*/
pairRdd.groupByKey();
/*對pair中的每個值進行應用*/
pairRdd.mapValues(new Function<String, Object>() {
@Override
public Object call(String v1) throws Exception {
return v1 + "sirZ";
}
});
/*返回只包含鍵的RDD*/
pairRdd.keys();
/*返回只包含值的RDD*/
pairRdd.values();
/*返回根據鍵排序的RDD*/
pairRdd.sortByKey();
}
/*針對多個pairRDD元素的操作*/
public static void runPair(JavaSparkContext sparkContext) {
JavaRDD<String> rdd = sparkContext.parallelize(Arrays.asList("test", "java", "python"));
JavaRDD<String> otherRDD = sparkContext.parallelize(Arrays.asList("golang", "php", "hadoop"));
PairFunction<String, String, String> pairFunction = new PairFunction<String, String, String>() {
@Override
public Tuple2<String, String> call(String s) {
return new Tuple2<>(s.split(" ")[0], s);
}
};
JavaPairRDD<String, String> pairRDD = rdd.mapToPair(pairFunction);
JavaPairRDD<String, String> pairRDDOther = otherRDD.mapToPair(pairFunction);
//創建好兩個PairRDD之後開始操作
//刪除 ==pairRDD== 中鍵與pairRDDOther相同的元素
JavaPairRDD<String, String> subRDD = pairRDD.subtractByKey(pairRDDOther);
//內連接 inner join 查詢
JavaPairRDD<String, Tuple2<String, String>> jsonRDD = pairRDD.join(pairRDDOther);
//右連接 right join 查詢 //TODO 此處我理解是可以爲null的二元組
JavaPairRDD<String, Tuple2<Optional<String>, String>> rightRDD = pairRDD.rightOuterJoin(pairRDDOther);
//左連接 left join 查詢
JavaPairRDD<String, Tuple2<String, Optional<String>>> leftRDD = pairRDD.leftOuterJoin(pairRDDOther);
//將兩個RDD中有相同鍵的數據分組 //TODO 此處我理解是迭代器
JavaPairRDD<String, Tuple2<Iterable<String>, Iterable<String>>> groupRDD = pairRDD.cogroup(pairRDDOther);
}
以上就是spark鍵值對的操作簡單案例
首先創建pariRDD(鍵值對RDD),然後對創建好的PairRDD進行操作
具體的使用看代碼中註釋,後續還會有更深入的案例
此處需要注意一下: PairRDD也還是RDD組,同樣支持RDD所支持的函數
代碼案例:
//pairRDD也可以使用RDD的函數
//篩選length小於20的元素
Function<Tuple2<String,String>,Boolean> filterRDD = new Function<Tuple2<String, String>, Boolean>() {
@Override
public Boolean call(Tuple2<String, String> v1) {
return (v1._2.length()<20);
}
};
JavaPairRDD<String,String> filter = pairRDD.filter(filterRDD);
聚合操作
當數據集以鍵值對形式組織的時候,聚合具有相同鍵的元素進行一些統計是很常見的操作,之前說過基礎 RDD上的 fold(),combine(),reduce() 等行動操作,pair RDD 上則有相應的針對鍵的轉化操作.Spark 有一組類似的操作,可以組合具有相同鍵的值,這些操作返回 RDD,因此它們是轉化操作而不是行動操作
代碼案例
JavaRDD<String> wordCount = sparkContext.parallelize(Arrays.asList("1", "2", "3", "4", "5"));
//返回一個可以迭代的集合
JavaRDD<String> c = wordCount.flatMap(new FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String v1) throws Exception {
return Arrays.asList(v1.split(" ")).iterator();
}
});
//現在的數據是 1,2,3,4,5
JavaPairRDD<String, Integer> result = c.mapToPair(new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String s) throws Exception {
return new Tuple2<>(s, 1);
//此時的數據是 {1,1},{2,1},{3,1},{4,1}...
}
}).reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
}
});
/*還可以通過countByValue快速實現單詞計數*/
c.countByValue();
總結
pairRDD(鍵值對RDD)
有很多函數可以進行基於鍵的數據合併,它們中的大多數都是在 combineByKey() 的基礎上實現的,爲用戶提供了更簡單的接口
combineByKey()的工作原理如下:
本人純手工畫的,見諒 [狗頭]