spark的RDDs很多操作都是基于键值对的。
Creating Pair RDDs:
例如scala :val pairs = lines.map(x => (x.split(" ")(0), x)) //创建一个以第一个单词为key的RDD
python和scala以内存中的集合创建:SparkContext.parallelize() 而java:SparkContext.parallelizePairs()
Pair RDDs的转换操作:
标准RDDs可用的转换操作Pair RDDs均可用。例如,若pair RDDs为{(1, 2), (3, 4), (3, 6)})
例如,两个pair RDDs,rdd = {(1, 2), (3, 4), (3, 6)} other = {(3, 9)}
其他RDDs能用的操作pair RDDs一样可用,例如scala:
pairs.filter{case (key, value) => value.length < 20},功能如下图所示,过滤掉value长度大于20的item。
当然若只想对value操作,则有其他一些操作函数可用。
下面是几个常用的转换:
1.聚合(如,对相同key的数据进行聚合)
主要讲了几个根据key聚合数据的操作:例如rdd.mapValues(x=> (x, 1)).reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2)),如下图:
经典的wordcount程序也可以用pair RDDs的聚合来做:
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(),相关内容请查阅资料。
2.分类数据 Grouping Data(如,把相同key的数据分类)
例如RDD中的数据已经按照key分类,[K,V],那么groupByKey()将返回[K, Iterable[V]]类型数据;cogroup()针对于多个RDDs,返回[(K, (Iterable[V], Iterable[W]))]型的RDD。具体函数操建议查阅官方文档。
3.Joins
join(),leftOuterJoin(),rightOuterJoin()(自行查阅)
4数据排序
sortByKey()可对数据进行升序或降序排序(key)。也可提供自定义的compare函数进行排序,例如把integer转为string进行排序:
scala:
val input: RDD[(Int, Venue)] = ...
implicit val sortIntegersByString = new Ordering[Int] {
override def compare(a: Int, b: Int) = a.toString.compare(b.toString)
}
rdd.sortByKey()
java:
class IntegerComparator implements Comparator<Integer> {
public int compare(Integer a, Integer b) {
return String.valueOf(a).compareTo(String.valueOf(b))
}
}
rdd.sortByKey(comp)
Pair RDDs的actions算子:
所有适用于普通RDDs的action算子都适用于pair RDDs。一些充分利用键值对数据结构的action如下,保存RDD的action第五章讲解:
数据分区:
集群中不同节点之间进行数据交流,为了减少它带来的性能问题,可通过数据分区来减少通信。适用于多次对RDD进行操作的场景(例如joins),若只对RDD进行一次操作则无需进行分区优化。
通过key来进行分区,spark会集中相同key的数据到相同的节点,尽管没有明确规定那个key集中在哪个节点。
分区带来的好处,例如:userData(userID,userInfo)和events(userID,LinkInfo)分别为相同key的RDD,userData.join(events)操作后转换为新的RDD(userID,(userInfo,LinkInfo)),下图所示:
而先对userData进行partitionBy(new HashPartitioner(100))操作(100是分区数,也就是控制有多少并行的task执行任务),再进行join,如下图:
可以看出,少了很多网络通信带来的负担。
spark的partitioner对象决定哪个key分区到哪个节点上,例如HashPartitioner和RangePartitioner,也可以自定义partitioner(继承org.apache.spark.Par
titioner,实现numPartitions,getPartition(key: Any),equals()等方法)。