創建Pair RDD
很多存儲鍵值對的數據格式會在讀取時直接返回由其鍵值對數據組成的pair RDD
當需要把一個普通RDD轉化而pair RDD時,可以使用map函數
//使用第一個單詞作爲鍵創建pair RDD
val pairs = lines.map(x => (x.split(" "))(0), x)
Pair RDD的轉化操作
Pair RDD也還是RDD,同樣支持RDD所支持的函數
pair.filter(case (key,value) => value.length < 20)
轉化操作
聚合操作
計算每個鍵對應值的平均值
rdd.mapValues(x => (x,1)).reduceByKey((x,y) => (x._1 +y._1, x._2 + y._2))
對所有單詞進行計數
val input = sc.textFile("s3://...")
val words = input.flatMap( x => x.split(" "))
val result = words.map(x => (x,1)).reduceByKey((x,y) => x + y)
combineByKey() 是最常用的基於鍵進行聚合的函數,大多數基於鍵聚合的函數都是用它實現的
可以讓用戶返回與輸入數據的類型不同的返回值
如果在每個分區中遇到一個新元素,combineByKey() 會使用一個**createCombiner()的函數來創建那個鍵對應的累加器的初始值。如果遇到該分區之前已經遇到的值,它會使用mergeValue()**方法,將該鍵的累加器對應的當前值與這個新的值進行合併。
由於有多個分區,因此對應於同一個鍵有多個累加器,對多個累加器採用mergeCombiners()
在scala中使用combineByKey()求每個鍵對應的平均值
val result = imput.combineByKey(
(v) => (v,1)
(acc:(Int, Int), v) => (acc._1 + v, acc._2 + 1),
(acc1:(Int,Int), acc2:(Int, Int)) => (acc1._1 + acc2._1, acc1._2 + acc2._2)
).map{ case (key, value) => (key, value._1 / value._2.toFloat) }
result.collectAsMap().map(println(_))
並行度調優
大多數操作符都能接收第二個參數,這個參數用來指定分組結果和聚合結果的RDD分區數
用rdd.paritions.size可以查看分區數
在操作之外的分區方法:有repartition() coalesce()
數據分組
groupByKey()可以使用RDD中的鍵來對數據進行分組,得到的結果RDD類型是[key,Iterable[v]]
groupByKey(func)可以接受一個函數,對源RDD中的每個元素使用該函數,將返回結果作爲鍵再進行分組。
cogroup()的函數可以對多個共享同一個鍵的RDD進行分組
數據連接
普通的join操作表示內連接。只有在兩個pair RDD中都存在的鍵才叫輸出。
leftOuterJoin() 左外連接,源RDD的每一個鍵都有對應的記錄。當一個鍵有多條記錄時,可以得到兩個RDD中對應同一個鍵的兩組值的笛卡爾積
數據排序
sortByKey() 可以接收參數
以字符串順序對整數進行自定義排序
val input:RDD[(Int, Value)]=...
implicit val sortIntegerByString = new Ordering[Int]{
override def compare(a: Int, b:Int) = a.toString.compare(b.toString)
}
rdd.sortByKey()
行動操作
pair RDD的行動操作
countByKey()
collectAsMap()
lookup(key )
數據分區高級
基於鍵的連接操作時有用
獲取分區:RDD的partitioner屬性,返回一個scala.Option屬性
RDD.partitionBy(new HashPartitioner(100))