大数据学习笔记之Spark-RDD编程

RDD编程

Spark中的核心数据操作:

  1. 创建RDD
  2. 转换已有的RDD
  3. 调用RDD操作进行求值

Note:

RDD是Spark数据操作的核心,它的主要特点是操作链,惰性求值。

RDD创建

创建RDD主要有两种方法:

  • 读取外部数据集
JavaRDD<String> lines = sc.textFile("your file path")
  • 在驱动程序中对一个集合进行并行化
JavaRDD<String> lines = sc.parralelize(Arrays.asList("pandas","i like pandas"));
RDD的操作

RDD的操作可以分为两种操作:1. 转换操作,2. 行动操作。

  • 转换操作
            RDD的转换操作是在RDD的依赖操作链上新增一个操作,但是并不对RDD进行实际计算,而是直接返回一个新的RDD。(这个像函数式编程里面的惰性计算,能有效的提高性能。)。

Note:

        Spark里面主要通过谱系图(lineage graph)来记录RDD的操作依赖链关系。通
过这种方式,Spark可以实现按需计算转换操作,也可在持久化的RDD丢失部分数据的情况时恢复所丢失的数据。

常用的转换操作有:

filter() //过滤数据集
map()   //依次对数据集中每个数据进行操作
flatmap() //将函数应用于RDD的每个元素,将返回的迭代器的所有内容构成新的RDD,通常用来切分单词
distinct() //去重
sample()   //采样
union()    //求并集
intersection() //求交集
substract()  //求子集
cartesian()  //求笛卡尔子集

示例:

//filter
JavaRDD<String> errorsRDD = inputRDD.filter(
    new Function<String, Boolean>() {
        public Boolean call(String x) {
            return x.contains("error");
        }
    }
);
  • 行动操作

        RDD的行动操作会对数据集进行实际计算,它会根据RDD的依赖操作链进行优化,然后根据优化后的依赖操作链上的转换操作依次对数据进行转换操作,最后计算出结果返回到驱动器程序或者写入外部存储系统中。

常用的行动操作有:

count()     //返回结果总数
take(num)   //返回一部分结果
collect()   //返回所有结果
reduce()    //聚合
aggregate() //累加

示例:
1.求和

Integer sum = rdd.reduce(new Function2<Integer, Integer, Integer>() {
    public Integer call(Integer x, Integer y) { return x+y; }
});

2.计算平均值

class AvgCount implements Serializable {
    public AvgCount(int total, int num) {
        this.total = total;
        this.num   = num;
    }
    public int total;
    public int num;
    public double avg() {
        return total / (double) num;
   }
};
Function2<AvgCount, Integer, AvgCount> addAndCount = new Function2<AvgCount,Integer, AvgCount>() {
    public AvgCount call(AvgCount a, Integer x) {
        a.total +=x;
        a.num   += 1;
        return a;
    }
};
Function2<AvgCount, AvgCount, AvgCount> combine = new Function2<AvgCount,AvgCount,AvgCount>() {
    public AvgCount call(AvgCount a, AvgCount b) {
        a.total += b.total;
        a.num += b.num;
        return a;
    }
}
AvgCount initial = new AvgCount(0,0);
AvgCount result  = rdd.aggreate(initial, addAndCount, combine);

Note:

除非我们对RDD的中间结果进行了持久化操作,每当我们调用一个新的行动操作时,整个RDD都会从头计算。

  • 函数传递
            在Spark中很多操作都需要依赖用户传递的函数。用Java传递用户函数,主要实现Spark中的org.apache.api.java.function中任一函数接口的对象来进行传递的。该包中主要提供了三个接口。
函数名 实现方法 用途
Function R call(T) 接收一个输入值并返回一个输出值,用于类似map()和filter等操作中
Function2 R call(T1,T2) 接收两个输入值并返回一个输出值,用于类似aggregate()和fold()等操作中
FlatMapFunction Iterable call(T) 接收一个输入值并返回任意个输出,用于类似flatMap()这样的操作中

具体的实现主要有三种方法:

  1. 匿名内部类
RDD<String> errors = lines.filter(new Function<String,Boolean>() {
    public Boolean call(String x) {
        return x.contains("error");
    }
});
  1. 具名类
class ContainsError implements Function<String, Boolean>() {
    public Boolean call(String x) {
        return x.contains("error");
    }
}

RDD<String> errors = lines.filter(new ContainsError());

3.lambda表达式

RDD<String> errors = lines.filter(s -> s.contains("error"));
  • 示例

1.计算平方值

JavaRDD<Integer> rdd = sc.parrallelize(Arrays.asList(1,2,3,4));
JavaRDD<Integer> result = rdd.map(new Function<Integer, Integer>() {
    public Integer call(Integer x) { return x*x; }
});
System.out.println(StringUtils.join(result.collect(),","));

  1. 将行数据切分为单词
JavaRDD<String> lines = sc.parallelize(Arrays.asList("hello world", "hi"));
JavaRDD<String> words = llines.flatMap(new FlatMapFunction<String, String>() {
    public Iterable<String> call(String line) {
        return Arrays.asList(line.split(" ")));
    }
});
words.first();
集合操作

        RDD也支持一些集合操作,但是并不是严格意义上的集合操作,它并不符合集合的唯一性。因为有些操作RDD并不会对结果集合进行去重,需要手动进行distinct()操作进行去重。

操作名 作用 是否进行数据混洗(去重)
distinct 去重
union 求并集
intersection 求交集
substract 求差集
cartesian 求笛卡尔集

Note:

distinct(),intersection()substract()都需要进行数据混洗进行去重,开销会比较大。

不同RDD类型之间转换

        鉴于有些函数只能用于特定类型,比如 mean()variance() 只能用于数值,而 join() 只能用于键值对类型。Spark中除了提供通用的RDD,还提供了些特殊RDD,比如:DoubleRDD(java中的JavaDoubleRDD)和PairRDD(java中的JavaPairRDD)。在java中使用sparkscala不同的是,spark不会像在scala中一样对RDD进行隐性转换,我们需要在代码显性转换RDD的类型。

示例:
将上面的计算平均值改写成为一个JavaDoubleRDD版本的计算每个元素的平方值的示例。

   //将一个mapRDD类型转换为一个DoubleRDD类型
   JavaDoubleRDD result = rdd.mapToDouble(new DoubleFunction<Integer>() {
        public double call(Integer x) {
            return (double) x*x;
        }
   });
   System.out.println(result.mean());

其他相关类型之间的转换:

方法 用途
flatMapToDouble 将flatMap类型转换成DoubleRDD
mapToDouble 将一个map类型转换成DoubleRDD
flatMapToPair 将flatMap类型转换成PairRDD
mapToPair 将map类型转换成PairRDD
引用
  • 《Spark快速大数据分析》

你可能感兴趣的:(大数据)