简介

RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。RDD具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。RDD允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。

RDD的属性

(1)一组分片(Partition),即数据集的基本组成单位。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。用户可以在创建RDD时指定RDD的分片个数,如果没有指定,那么就会采用默认值。默认值就是程序所分配到的CPU Core的数目。

2)一个计算每个分区的函数。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。compute函数会对迭代器进行复合,不需要保存每次计算的结果。

(3)RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。在部分分区数据丢失时,Spark可以通过这个依赖关系重新计算丢失的分区数据,而不是对RDD的所有分区进行重新计算。

(4)一个Partitioner,即RDD的分片函数。当前Spark中实现了两种类型的分片函数,一个是基于哈希的HashPartitioner,另外一个是基于范围的RangePartitioner。只有对于于key-value的RDD,才会有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函数不但决定了RDD本身的分片数量,也决定了parent RDD Shuffle输出时的分片数量。

(5)一个列表,存储存取每个Partition的优先位置(preferred location)。对于一个HDFS文件来说,这个列表保存的就是每个Partition所在的块的位置。按照“移动数据不如移动计算”的理念,Spark在进行任务调度的时候,会尽可能地将计算任务分配到其所要处理数据块的存储位置。

WordCount粗图解RDD

Spark以其RDD模型的强大表现能力_scala

其中hello.txt

Spark以其RDD模型的强大表现能力_scala_02


编写代码

官网地址:https://spark.apache.org/docs/latest/rdd-programming-guide.html


引jar包

Spark以其RDD模型的强大表现能力_hadoop_03


提取数据文件 链接:https://pan.baidu.com/s/1uu7rI_0L0g1kI9v-h3uB0w 提取码:w4yc

记得将数据文件里面的标题给去掉


代码

package com.jbit.test

import org.apache.hadoop.io.{LongWritable, Text}
import org.apache.hadoop.mapred.TextInputFormat
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object TestRdd {

  def main(args: Array[String]): Unit = {
    var spark=new SparkContext(new SparkConf()
      .setMaster("local")
      .setAppName("a"))

    //Spark Scala读取GBK文件的方法
    var data=spark.hadoopFile("data/A.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"GBK"))

    var data2=spark.hadoopFile("data/address.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"UTF-8"))

    var data3=spark.hadoopFile("data/taobao_persona.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"UTF-8"))

    //var data=spark.textFile("data/A.csv")

    //transfer(spark,"data/A.csv").foreach(println(_))
    //f1(data)
    //f2(data)
    //f3(data)
    //f4(data,data2)
    f5(data3)

  }
  //每个饭圈内的数量
  def f1(data:RDD[String])={
    //根据,号拆分然后得到下标为4(商圈名称),数量
    val dataRDD=data
      //根据,号拆分出每一行的数据
      .map(line => {line.split(",")}
       //使用filter进行过滤(因为每一行的数量可能并不是那么完整)
    ).filter( x => x.length>14)
      //得到下标为4的标题的值做为键
      .map(x => (x(4),1))

    //打印出统计的饭圈键对值
    //dataRDD.take(100).foreach(println(_))

    //统计出每个饭圈内的饭店的数量
    var result=dataRDD.countByKey()
    //取前10条并且打印出来
    result.take(10).foreach(println(_))
    println("-----------------------------")
    //排序
    //第一个_代表this,也就是当前对象,然后.出它的第二个值
    //这里的意思就是将result转换为数组然后依次比较出它里面最大的数据并进行排序
    result.toArray.sortWith(_._2>_._2).take(10).foreach(println(_))
  }

  //人均消费前10名的商店
  def f2(data:RDD[String])={
    var dataRDD=data
      .map(line => line.split(","))
      .filter(x => x.length>14)
      .map(x => {
        //以商店名为键,然后因为人均价格里面带个元,所以以元拆分然后将数据转换成int类型
        (x(0),x(2).split("元")(0).toInt)
      }

      )

    //排序
    //false为降序,true为升序
     dataRDD.sortBy(_._2,false)
      .take(10).foreach(println(_))
  }

  //计算每种参观种类总消费
  def f3(data:RDD[String]): Unit ={
    val dataRDD=data
      .map(line => line.split(","))
      .filter(x => x.length>14)
      .map(
        x =>
          (x(3),x(2).replace("元","").toInt)
      )

    //根据key做出的处理(k1,v1)(k1,v2)
    //相同key下的v1放入a,v2放入b,然后把结果存入a,下一个值存入b
    //重复上面的操作,直到结束
    //总的就是说相同key的value加起来
    var result=dataRDD.reduceByKey(
      (a,b) => {
        println("a: "+a)
        println("b: "+b)
        a+b
      }
    )

    //result.take(10).foreach(println(_))

    //取商品的平均价格
    var dataRDD2=data
      .map(line => line.split(","))
      .filter(x => x.length>14)
      .map(
        x =>
          //将value换成一个集合
          // (自助餐,(140,1))
          (x(3),(x(2).replace("元","").toInt,1))
      )

    var result2=dataRDD2.reduceByKey(
      (a,b) => {
        //(价格,数量)
        //(140,1)
        //将价格和数量统计出来
        (a._1+b._1,a._2+b._2)
      }
    ).map(
      x =>
        //(键,(平均值,总价格,数量))
        // (自助餐,(平均值,总价格,数量))
        (x._1,x._2._1 / x._2._2,x._2._1,x._2._2)
    )

    //取10条结果出来且循环打印
    //result2.take(10).foreach(println(_))


    var dataRDD3=data
      .map(line => line.split(","))
      .filter(x => x.length>14)
      .map(
        x =>
          //将value换成一个集合
          // (自助餐,(140,1))
          (x(3),FoodTemp(x(2).replace("元","").toInt,1))
      )

    //使用模式匹配来自出平均价格及随机抽取数据
    var result3=dataRDD3.reduceByKey(
      (a,b) => {
        //(价格,数量)
        //(140,1)
        //将价格和数据都统计出来
        FoodTemp(a.price+b.price,a.num+b.num)
      }
    ).map(
      x =>
        //(键,(总价格,数量))
        // (自助餐,(总价格,数量))
        Food(x._1,x._2.price / x._2.num,x._2.price,x._2.num)
    )

    //result3.take(10).foreach(println(_))

    //随机抽取
    //false取出随机值后,不放入数据源
    //true取出随机值后,放入数据源(可能会重复)
    //0.1为比例
    result3.sample(false,0.1).foreach(println(_))

  }

  // 获取饭店名称,以及所在的行政区
  def f4(data: RDD[String],data2:RDD[String]): Unit ={
    val fRDD=data.map(
      line =>
        line.split(",")
    ).filter(
      x =>
        x.length>14
    ).map(
      x =>
        //(id,店铺名称)
        (x(13),x(0))
    )

    val addressRDD=data2.map(
      x => {
        var line=x.split(",")
        //(id,行政区名称)
        (line(0),line(4))
      }
    )

    //键一致
    fRDD.join(addressRDD)
      .take(10)
      .foreach(println(_))

  }

  //淘宝商品购买量占有查看量的百分比
  def f5(data:RDD[String])={
    var result=data.map(
      x => {
        val ts=x.split(",")
        (ts(0),ts(1),ts(2))
      }
    ).groupBy(
      //将上面存的值设置哪个为主键
      //得出来的数据例:(195233146,CompactBuffer((104742442,195233146,1)))
      x => x._2

      //判断哪个值是我们所需要的(1(浏览)和4(购买))
    ).mapValues(
      x => {
        //计算商品浏览次数
        val a=x.count(
          active => {
            active._3== "1"
          }
        )

        //计算商品购买次数
        val b = x.count(
          active => {
            active._3 == "4"
          }
        )

        (b.toDouble/a.toDouble)
        //保留四位小数
        //(b.toDouble/a.toDouble).formatted("%.4f")

      }
    )

    //result.take(100).foreach(println(_))
    //将数据保存到本地
    result.saveAsTextFile("D:\\tao")
  }

  //Spark Scala读取GBK文件的方法
  def transfer(sc: SparkContext,path:String):RDD[String]={
    sc.hadoopFile(path,classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"GBK"))
  }
}
package com.jbit.test

/**
 * 美食实体类
 * @param name  美食种类名称
 * @param avg   平均消费
 * @param sum   人均消息总额
 * @param num   餐饮数量
 */
case class Food(name:String,avg:Int,sum:Int,num:Int)

case class FoodTemp(price:Int,num:Int)

如果存储文件的时候报错

Caused by: java.io.IOException: (null) entry in command string: null chmod 0644 D:\tao\_temporary\0\_temporary\attempt_20200808162905_0010_m_000000_0\part-00000

可以去:https://github.com/steveloughran/winutils下载到

Spark以其RDD模型的强大表现能力_spark_04


然后将此文件放到C:\Windows\System32中即可


读取文件的代码

package com.jbit.test

import org.apache.hadoop.io.{LongWritable, Text}
import org.apache.hadoop.mapred.TextInputFormat
import org.apache.spark.{SparkConf, SparkContext}

object MyRead {

  def main(args: Array[String]): Unit = {
    val spark=new SparkContext(new SparkConf().setMaster("local").setAppName("a"))

    //指定文件
    /*var data=spark.hadoopFile("D:\\tao\\part-00000",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"UTF-8"))*/

    //指定目录下的所有文件
    var data=spark.hadoopFile("D:\\tao\\*",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"UTF-8"))

    data.take(10).foreach(println(_))
    }

}

如果觉得上面不够过瘾,可以再写写下面的

package com.jbit.test

import org.apache.hadoop.io.{LongWritable, Text}
import org.apache.hadoop.mapred.TextInputFormat
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object RDDJob2 {

  def main(args: Array[String]): Unit = {
    var spark=new SparkContext(new SparkConf().setMaster("local").setAppName("a"))

    var data=spark.hadoopFile("data/A.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"GBK"))

    f1(data)

    var data2=spark.hadoopFile("data/address.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"UTF-8"))

    f2(data,data2)

    //Spark Scala读取GBK文件的方法
    var data3=spark.hadoopFile("data/taobao_persona.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"GBK"))

    f3(data3)

    var data4=spark.hadoopFile("data/YYK.csv",classOf[TextInputFormat],classOf[LongWritable],classOf[Text],1)
      .map(p => new String(p._2.getBytes,0,p._2.getLength,"UTF-8"))

    f4(data4)


  }

  //广东美食中,食物类别人气前10名(人气是根据评论数量)
  def f1(data:RDD[String]): Unit ={

    println("--------------")
      var result=data.map(
        line =>
          line.split(",")
      ).filter(
        line =>
          line.length>13
      ).map(
        line =>
          (line(3),line(1).toInt)
      )


    var resultReduce=result.reduceByKey(
      (a,b) =>
        a+b
    )

    resultReduce.sortBy(_._2,false).take(10).foreach(println(_))
  }

  //行政区美食数量排名
  def f2(data:RDD[String],data2:RDD[String]): Unit ={

    var result=data.map(
      line =>
        line.split(",")
    ).filter(
      line =>
        line.length>13
    ).map(
      x =>
      (x(13),x(0))
    )

    var result2=data2.map(
      line =>
        line.split(",")
    ).filter(
      line =>
        line.length>3
    ).map(
      x =>
        (x(0),x(4))
    )

    var resultJoin=result.join(result2)

    resultJoin.map(
      x=>
        (x._2._2,1)
    ).reduceByKey(
      (a,b) =>
        a+b
    ).sortBy(_._2,false).foreach(println(_))


  }

  //淘宝数据集,每天用户访问数量,并得出前10名
  def f3(data:RDD[String]): Unit ={
    var result=data.map(
      line =>
        line.split(",")
    ).filter(
      line =>
        line.length>4
    ).map(
      x =>
        (x(5),x(1).toInt)
    )

    var resultReduce=result.reduceByKey(
      (a,b) =>
        a+b
    )

    resultReduce.sortBy(_._2,false).take(10).foreach(println(_))
  }

  //优依库数据集,购买种类前10名
  def f4(data:RDD[String]): Unit ={
    var result=data.map(
      line =>
        line.split(",")
    ).filter(
      line =>
        line.length>10
    ).map(
      x =>
        (x(6),x(9).toInt)
    )

    var resultReduce=result.reduceByKey(
      (a,b) =>
        a+b
    )
    resultReduce.sortBy(_._2,false).take(10).foreach(println(_))
  }


}