连接
将有键的数据与另一组有键的数据一起使用是对键值对数据执行的最有用的操作之一。连接数据可能是pairRDD最常用的操作之一。连接方式多种多样:右外连接、左外连接、交叉连接以及内连接。
普通的join操作符表示内连接。只有在两个pairRDD中都存在的键才叫输出。当一个输入对应的某个键有多个值时,生成的pairRDD会包括来自两个输入RDD的每一组相对应的记录。
有时,我们不希望结果汇总的键必须在两个RDD中都存在。例如,在连接客户信息与推荐时,如果一些客户还没收到推荐,我们仍然不希望丢掉这些顾客。leftOuterJoin(other)和rightOuterJoin(other)都会根据键连接两个RDD,但是允许结果中存在其中的一个pairRDD所缺失的键。
在使用leftOuterJoin()产生的pairRDD中,源RDD的每一个键都有对应的记录。每个键相应的值是由一个源RDD中的值与一个包含第二个RDD的值的Optional对象组成的二元组。和join()一样,每个键可以得到多条记录;当这种情况发生时,我们会得到两个RDD中对应同一个键的两组值的笛卡尔积。
rightOuterJoin()几乎与leftOuterJoin()完全一样,只不过预期结果中的键必须出现在第二个RDD中,而二元组中的可缺失的部分则来自于源RDD而非第二个RDD。
数据排序
很多时候,让数据排好序是很有用的,尤其是在生成下游输出时。如果键有已定义的顺序,就可以对这种键值对RDD进行排序。当把数据排好序后,后续对数据进行collect()或save()等操作都会得到有序的数据。
我们经常要将RDD倒序排列,因此sortByKey()函数接收一个叫做ascending的参数,表示我们是否想要让结果按升序排序(默认值为true)。有时我们也可能想按完全不同的排序依据进行排序。要支持这种情况,我们可以提供自定义的比较函数。下面会实现一个将整数转为字符串,然后使用字符串比较函数来对RDD进行排序的操作。
public class SortByKeyTest {
public static void main(String[] args) {
SparkConf conf = new SparkConf().setMaster("local").setAppName("sortByKey");
JavaSparkContext sc = new JavaSparkContext(conf);
JavaRDD<String> lines = sc.textFile("README.md");
JavaPairRDD<String, Integer> wordMap = lines.mapToPair(
(PairFunction<String, String, Integer>) s -> new Tuple2<>(s, 1)
);
Comparator<String> comp = new IntegerComparator();
JavaPairRDD<String, Integer> sortByKey = wordMap.sortByKey(comp);
sortByKey.collect();
}
static class IntegerComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
}
}