扩展Spark API

介绍

Apache Spark有许多内建方法进行数据处理,但是在实际应用中,可能需要domain specific operators来解决实际问题,我们需要扩展Spark API来添加自定义方法。

扩展Spark API有两种方法:

  • 在存在的RDD上添加自定义方法
  • 创建新的RDD

动力

我们有一份销售数据,以CSV格式进行存储,包含transactionid, customerid, itemid, itemvalue列。

class SalesRecord(val transactionId: String,
                  val customerId: String,
                  val itemId: String,
                  val itemValue: Double) extends Comparable[SalesRecord]
with Serializable {

  override def compareTo(o: SalesRecord): Int = {
    return this.transactionId.compareTo(o.transactionId)
  }

  override def toString: String = {
    transactionId + "," + customerId + "," + itemId + "," + itemValue
  }
}

转换数据为RDD[SalesRecord]

object Main {

  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("fengfengzai").setMaster("local")
    val sc = new SparkContext(conf)
    
    val dataRDD = sc.textFile("/to/path/sample.csv")
    
    val salesRecordRDD = dataRDD.map(row => {
      val colValues = row.split(",")
      new SalesRecord(colValues(0), colValues(1), colValues(2), colValues(3).toDouble)
    })

    print(salesRecordRDD.map(_.itemValue).sum())
  }

}

输出为:

100

尽管 salesRecordRDD.map(_.itemValue).sum() 是简洁的,但是不具有可读性,使用下面的方法进行求和会更好,这个方法需要我们自己实现。

salesRecordRDD.totalSales

添加自定义方法到RDD

  1. 定义帮助类(拥有自定方法)
    class CustomFunctions(rdd: RDD[SalesRecord]) {
    
      def totalSales = rdd.map(_.itemValue).sum()
    
    }
    
  2. 隐式转换(添加方法到RDD上)
    object CustomFunctions {
      implicit def addCustomFunctions(rdd: RDD[SalesRecord]) = new
      CustomFunctions(rdd) 
    }
    
  3. 使用自定义方法
    import CustomFunctions._
    println(salesRecordRDD.totalSales)
    

创建自定义RDD

  1. 创建DiscountRDD
    例如,想要懒计算每个销售的折扣,可以建立一个DiscountRDD。
    class DiscountRDD(prev: RDD[SalesRecord], discountPercentage: Double) extends RDD[SalesRecord](prev){
    
      override def compute(split: Partition, context: TaskContext): Iterator[SalesRecord] = {
        firstParent[SalesRecord].iterator(split, context).map(salesRecord => {
          val discount = salesRecord.itemValue * discountPercentage
          new SalesRecord(salesRecord.transactionId, salesRecord.customerId, salesRecord.itemId, discount)
        })
      }
    
      override protected def getPartitions: Array[Partition] = {
        firstParent[SalesRecord].partitions
      }
    }
    
    当创建RDD时,必须覆盖compute, getPartitions方法。
  2. 添加自定义操作
    def discount(discountPercentage: Double) = new DiscountRDD(rdd, discountPercentage)
    
    使用上面类似方法,添加自定义方法来创建DiscountRDD。
  3. 使用隐式转换进行操作
    val discountRDD = salesRecordRDD.discount(0.1)
    
    println(discountRDD.collect().toList)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值