原文链接:

Spark RDD API扩展开发(1)

Spark RDD API扩展开发(2):自定义RDD

我们都知道,Apache Spark内置了很多操作数据的API。但是很多时候,当我们在现实中开发应用程序的时候,我们需要解决现实中遇到的问题,而这些问题可能在Spark中没有相应的API提供,这时候,我们就需要通过扩展Spark API来实现我们自己的方法。
我们可以通过两种方法来扩展Spark API,(1)、其中一种就是在现有的RDD中添加自定义的方法;(2)、第二种就是创建属于我们自己的RDD。在这篇文章中,我将对这两种方法进行阐述,并赋予代码 。下面我就开始介绍第一种方法。

  假如我们中有一些商品的销售数据,数据的格式是CSV的。为了简单起见,假如每行数据都是由id, customerId, itemId 以及itemValue四个字段组成,我们用SalesRecord来表示:

1 class SalesRecord(val id: String,
2                   val customerId: String,
3                   val itemId: String,
4                   val itemValue: Double) extends Comparable[SalesRecord]
5 with Serializable

  所以我们可以将商品的销售数据进行解析,并存储到RDD[SalesRecord]中:

01 /**
02  * User: 过往记忆
03  * Date: 15-03-31
04  * Time: 上午00:24
05  * bolg: http://www.iteblog.com
06  * 本文地址:http://www.iteblog.com/archives/1298
07  * 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货
08  * 过往记忆博客微信公共帐号:iteblog_hadoop
09  */
10  
11 val sc = new SparkContext(args(0), "iteblogRDDExtending")
12 val dataRDD = sc.textFile("file:///www/iteblog.csv")
13 val salesRecordRDD = dataRDD.map(row => {
14     val colValues = row.split(",")
15     new SalesRecord(colValues(0),colValues(1),
16     colValues(2),colValues(3).toDouble)
17 })

  如果我们想计算出这些商品的总销售额,我们会这么来写:

1 salesRecordRDD.map(_.itemValue).sum

  虽然这看起来很简洁,但是理解起来却有点困难。但是如果我们可以这么来写,可能会很好理解:

1 salesRecordRDD.totalSales

  在上面的代码片段中,totalSales方法让我们感觉就是Spark内置的操作一样,但是Spark是不提供这个方法的,我们需要在现有的RDD中实现我们自定义的操作。

  下面我就来介绍一些如何在现有的RDD中添加我们自定义的方法。

  一、定义一个工具类,来存放我们所有自定义的操作

  当然,你完全没必要自定义一个类类添加我们自定义的方法,但是为了管理,还是建议你这么做。下面我们来定义IteblogCustomFunctions类,它存储所有我们自定义的方法。它是专门用来处理RDD[SalesRecord],所以这个类中提供的操作全部是用来处理销售数据的:

1 class IteblogCustomFunctions(rdd:RDD[SalesRecord]) {
2   def totalSales =rdd.map(_.itemValue).sum 
3 }

  二、隐形转换来实现在RDD中添加方法

  我们定义了隐形的addIteblogCustomFunctions函数,这可以将所有操作销售数据的方法作用于RDD[SalesRecord]上:

01 /**
02  * User: 过往记忆
03  * Date: 15-03-31
04  * Time: 上午00:24
05  * bolg: http://www.iteblog.com
06  * 本文地址:http://www.iteblog.com/archives/1298
07  * 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货
08  * 过往记忆博客微信公共帐号:iteblog_hadoop
09  */
10  
11 object IteblogCustomFunctions {
12   implicit def addIteblogCustomFunctions(rdd: RDD[SalesRecord]) = new
13   IteblogCustomFunctions(rdd)
14 }

  三、使用自定义的方法

  下面方法通过导入IteblogCustomFunctions 中的相应方法来实现使用我们自定义的方法:

1 import IteblogCustomFunctions._
2 println(salesRecordRDD.totalSales)

  通过上面三步我们就可以在现有的RDD中添加我们自定义的方法。

自定义一个RDD类

在上文中我介绍了如何在现有的RDD中添加自定义的函数。本文将介绍如何自定义一个RDD类,假如我们想对没见商品进行打折,我们想用Action操作来实现这个操作,下面我将定义IteblogDiscountRDD类来计算商品的打折,步骤如下:

  一、创建IteblogDiscountRDD类

  自定义RDD类需要继承Spark中的RDD类,并实现其中的方法:

01 /**
02  * User: 过往记忆
03  * Date: 15-04-01
04  * Time: 上午00:59
05  * bolg: http://www.iteblog.com
06  * 本文地址:http://www.iteblog.com/archives/1299
07  * 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货
08  * 过往记忆博客微信公共帐号:iteblog_hadoop
09  */
10 classIteblogDiscountRDD(prev:RDD[SalesRecord],xxxxx:Double)
11     extends RDD[SalesRecord](prev){
12  
13 //继承compute方法
14 override def compute(split: Partition, context: TaskContext): Iterator[SalesRecord] =  {
15   firstParent[SalesRecord].iterator(split, context).map(salesRecord => {
16       val discount = salesRecord.itemValue*discountPercentage
17       new SalesRecord(salesRecord.id,
18       salesRecord.customerId,salesRecord.itemId,discount)
19 })}
20  
21 //继承getPartitions方法
22 override protected def getPartitions: Array[Partition] =
23       firstParent[SalesRecord].partitions
24 }

  上面代码中,我创建了一个IteblogDiscountRDD类,这个RDD只操纵销售数据,当我们继承RDD类时,我们必须重载两个方法:
  compute

  这个函数是用来计算RDD中每个的分区的数据,在我代码中,我们输入了销售数据,并对其中的数据计算打折计算。

  getPartitions
  
  getPartitions函数允许开发者为RDD定义新的分区,在我们的代码中,并没有改变RDD的分区,重用了父RDD的分区。

  定义IteblogDiscountRDD的时候将类型写死了(SalesRecord),它只能用来处理SalesRecord数据。如果我们想定义一个通用的RDD,只需要类似下面写即可

01 classIteblogRDD(prev:RDD[T],XXXX:C)
02     extends RDD[T](prev){
03  
04 //继承compute方法
05 override def compute(split: Partition, context: TaskContext): Iterator[T] =  {
06   ................................
07 }
08  
09 //继承getPartitions方法
10 override protected def getPartitions: Array[Partition] =
11       ................................
12 }

  二、自定义discount函数

  我们自定义discount函数,该函数可以创建一个IteblogDiscountRDD:

1 def discount(discountPercentage:Double) = new IteblogDiscountRDD(rdd,discountPercentage)

  三、使用IteblogDiscountRDD

  使用IteblogDiscountRDD也是非常简单的,我们可以像使用内置的RDD一样来使用:

1 import IteblogCustomFunctions._
2  
3 val discountRDD = salesRecordRDD.discount(0.1)
4 println(discountRDD.collect().toList)

  自此,我们已经学会了如何在现有的RDD中定义方法和自定义自己的RDD。

Spark RDD API扩展开发的更多相关文章

  1. Spark RDD API详解(一) Map和Reduce

    RDD是什么? RDD是Spark中的抽象数据结构类型,任何数据在Spark中都被表示为RDD.从编程的角度来看,RDD可以简单看成是一个数组.和普通数组的区别是,RDD中的数据是分区存储的,这样不同 ...

  2. Spark RDD API具体解释(一) Map和Reduce

    本文由cmd markdown编辑.原始链接:https://www.zybuluo.com/jewes/note/35032 RDD是什么? RDD是Spark中的抽象数据结构类型,不论什么数据在S ...

  3. Spark RDD API详解之:Map和Reduce

    RDD是什么? RDD是Spark中的抽象数据结构类型,任何数据在Spark中都被表示为RDD.从编程的角度来看, RDD可以简单看成是一个数组.和普通数组的区别是,RDD中的数据是分区存储的,这样不 ...

  4. Spark RDD API(scala)

    1.RDD RDD(Resilient Distributed Dataset弹性分布式数据集)是Spark中抽象的数据结构类型,任何数据在Spark中都被表示为RDD.从编程的角度来看,RDD可以简 ...

  5. spark (java API) 在Intellij IDEA中开发并运行

    概述:Spark 程序开发,调试和运行,intellij idea开发Spark java程序. 分两部分,第一部分基于intellij idea开发Spark实例程序并在intellij IDEA中 ...

  6. 且谈 Apache Spark 的 API 三剑客:RDD、DataFrame 和 Dataset

    作者:Jules S. Damji 译者:足下 本文翻译自 A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets ,翻译已 ...

  7. Spark RDD/Core 编程 API入门系列之动手实战和调试Spark文件操作、动手实战操作搜狗日志文件、搜狗日志文件深入实战(二)

    1.动手实战和调试Spark文件操作 这里,我以指定executor-memory参数的方式,启动spark-shell. 启动hadoop集群 spark@SparkSingleNode:/usr/ ...

  8. Spark RDD/Core 编程 API入门系列之map、filter、textFile、cache、对Job输出结果进行升和降序、union、groupByKey、join、reduce、lookup(一)

    1.以本地模式实战map和filter 2.以集群模式实战textFile和cache 3.对Job输出结果进行升和降序 4.union 5.groupByKey 6.join 7.reduce 8. ...

  9. Apache Spark 2.2.0 中文文档 - Spark RDD(Resilient Distributed Datasets)论文 | ApacheCN

    Spark RDD(Resilient Distributed Datasets)论文 概要 1: 介绍 2: Resilient Distributed Datasets(RDDs) 2.1 RDD ...

随机推荐

  1. 百度地图sdk定位和遇到的坑

    封装定位服务类: import android.content.Context; import com.baidu.location.BDAbstractLocationListener; impor ...

  2. Docker运行oracle12c注意事项

    title: docker运行oracle12c注意事项 date: 2019-03-27 13:42:34 categories: 数据库 author: mrzhou tags: docker 数 ...

  3. PBR Step by Step(一)立体角

    转载请注明出处:http://www.cnblogs.com/jerrycg/p/4924761.html  本系列从零起步,作为学习笔记与大家分享,从基础的数学和图形理论,一步一步实现基于物理的渲染 ...

  4. Vue 2.0学习(四)计算属性

    {{}}模板内的表达式常用于简单的运算,当运算过长或逻辑复杂时,会难以维护. <div> {{ text.split(',').reverse().join('') }} </div ...

  5. Codeforces 521 E cycling city

    cf的一道题,非常有意思,题目是问图中是否存在两个点,使得这两个点之间有三条路径,而且三条路径没有公共点. 其实就是判断一下是否为仙人掌就行了,如果不是仙人掌的话肯定就存在,题目难在输出路径上,改了半 ...

  6. BZOJ 4516: [Sdoi2016]生成魔咒 后缀自动机 性质

    http://www.lydsy.com/JudgeOnline/problem.php?id=4516 http://blog.csdn.net/doyouseeman/article/detail ...

  7. 【暴力】Gym - 100851A - Adjustment Office

    题意:给你一个n*n的矩阵,初始时,(x,y)的值为x+y.可能有两类操作,一类是对某一行求和,并将这一行置零:另一类是对某一列求和,并将这一列置零. 维护四个值:一个是列标号之和,一个是当前存在的列 ...

  8. 【8.19校内测试】【背包】【卡特兰数】【数位dp】

    早上随便搞搞t1t3就开始划水了,t2一看就是组合数学看着肚子疼...结果t1t3都a了??感天动地. 从小到大排序,从前到后枚举i,表示i是整个背包中不选的物品中代价最小的那个,即i不选,1到i-1 ...

  9. Jeeplus框架中问题解决

    1,文件上传后图片显示的问题 (1)问题:在这个组件的文档介绍里面写了这个组件是有预览功能的,但是我没有找到,就自己写了这个小功能. 在框架中下图中,这个文件上传组件只能将文件上传,然后将文件名显示出 ...

  10. SqlServer Base64解码中文

    最近在做一个和拥有TurboCRM相关的项目,其中需要取出客户信息的联系人字段,经过查看,这个字段在存入时用Base64加密过了 这个功能在应用层实现是很方便的,但是由于一些特殊原因,只能放到SqlS ...