05-SparkRDD原理和编程接口

1.弹性分布式数据集RDD

1.1.RDD概述

1.1.1.什么是RDD

RDD(Resilient Distributed DataSet)弹性分布式数据集。是spark中最基本的数据抽象,是一个不可变的、可分区的、可并行计算的集合。

Resilient:数据可以选择性的存储在内存中,或者磁盘中

Distributed:分布式存储、分布式计算

DataSet:用于存放数据的数据集合

1.1.2.RDD的属性

  • A list of partitions:分区列表,数据集基本组成单位

    说明:每个分区对应一个计算任务,决定并行计算的粒度。比如:读取hdfs上数据文件产生的RDD分区数,与数据存储block的个数相等

  • A function for computing each split:计算每个分区的函数

    比如:在单词计数任务中的textFile、flatMap、map等函数

  • A list of dependencies on other RDDs:一个RDD会依赖于其他的RDD

    说明:依赖关系

  • Optionally, a Partitioner for key-value RDDs:可选的,一个Partitioner

    说明:只有key/value的RDD才会有Partitioner。当前在spark中提供了两种类型的Partitioner:一个是基于哈希的HashPartitioner;一个是基于范围的RangePartitioner

  • Optionally, a list of preferred locations to compute each split on:可选的,一个列表,存储每个Partition的优先位置

    说明:数据本地性(移动数据不如移动计算划算

1.1.3.为什么会产生RDD

  • 传统的MapReduce虽然具有自动容错、平衡负载和可拓展性的优点,但是其最大缺点是采用非循环式的数据流模型,使得在迭代计算中要进行大量的磁盘IO操作,RDD正是解决这一缺点的抽象方法。
  • RDD是spark提供的最重要的抽象概念,它是一种具有容错机制的特殊集合,分布在集群的节点上,以函数式编程来操作集合,进行各种并行操作。可以把RDD的结果数据进行缓存,方便进行多次重用,避免重复计算

1.1.4.RDD在spark中的地位和作用

  • 为什么会有spark:

    因为传统的并行计算模型无法有效的解决迭代计算(iterative)和交互式计算(interactive)。spark的使命便是解决这两个问题(迭代计算交互式计算),这也是它存在的价值和理由。

  • spark如何解决迭代计算:

    迭代计算的主要实现思想,就是通过RDD,把所有计算的数据保存在分布式的内存中。迭代计算通常情况下都是对同一个数据集做反复的迭代计算。数据在内存中将大大提升IO操作效率。这也是spark的核心:内存计算

  • spark如何实现交互式计算:

    spark是用scala语言实现的,spark和scala能够紧密的集成,spark可以完美的运用scala的解释器,使得其中的scala可以像操作本地集合对象一样轻松操作分布式数据集

  • spark和RDD的关系:

    RDD是一种具有容错性、基于内存计算的抽象方法,RDD是spark Core的底层核心spark则是这个抽象方法的实现

1.2.创建RDD

#进入spark shell(node03)
cd /export/servers/spark-2.0.2-bin-hadoop2.7/bin
spark-shell --master local[2]
  • 根据scala集合创建

    sc.parallelize(Array(1,2,3,4,5,6))
    

    在这里插入图片描述

  • 读取外部文件创建

    sc.textFile("/export/servers/testdata/words.txt")
    

在这里插入图片描述

  • 根据已经存在的RDD,经过算子转换生成新的RDD

    val rdd1=sc.textFile("/export/servers/testdata/words.txt")
    
    rdd1.flatMap(_.split(" "))
    
    

1.3.RDD编程API

1.3.1.RDD算子分类

  • Transformation:转换

    根据数据集创建一个新的数据集,计算后返回一个新RDD

  • Action:动作

    对rdd结果计算后,返回一个数值value给驱动程序

1.3.2.Transformation

RDD中的所有转换都是延迟加载的,它们并不会直接计算结果。相反的,它们只是记住这些应用到基础数据集(例如一个文件)上的转换操作只有当发生一个要求返回结果给Driver的动作时,这些转换才会真正运行。这种设计让spark更加有效率地运行。

常用的Transformation:

序号 转换 含义
1 map(func) 返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成
2 filter(func) 返回一个新的RDD,该RDD由经过func函数计算,后返回值为true的输入元素组成
3 flatMap(func) 类似于map,每一个输入元素可以被映射为0或多个输出元素(func返回一个序列,而不是单一元素)
4 mapPartitions(func) 类似于map,独立地在RDD的每一个分片上运行,在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U]
5 mapPartitionsWithIndex(func) 类似于mapPartitions,func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是 (Int, Interator[T]) => Iterator[U]
6 union(othersDataSet) 对源RDD和参数RDD求并集后返回一个新的RDD
7 intersection(otherDataSet) 对源RDD和参数RDD求交集后返回一个新的RDD
8 distinct([numTasks]) 对源RDD进行去重后返回一个新的RDD
9 groupByKey([numTasks]) 在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD
10 reduceByKey(func,[numTasks]) 在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置
11 sortByKey([ascending],[numTasks]) 在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD
12 sortBy(func,[ascending],[numTasks]) 与sortByKey类似,但是更灵活
13 join(otherDataSet,[numTasks]) 在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD
14 cogroup(otherDataSet,[numTasks]) 在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD
15 coalesce(numPartitions) 减少 RDD 的分区数到指定值
16 repartition(numPartitions) 重新给 RDD 分区
17 repartitionAndSort\ 重新给 RDD 分区,并且每个分区内以记录的 key 排序
18 WithinPartitions(partitioner)

1.3.3.Action

序号 动作 含义
1 reduce(func) reduce将RDD中元素前两个传给输入函数,产生一个新的return值,新产生的return值与RDD中下一个元素(第三个元素)组成两个元素,再被传给输入函数,直到最后只有一个值为止
2 collect() 在驱动程序中,以数组的形式返回数据集的所有元素生
3 count() 返回RDD的元素个数
4 first() 返回RDD的第一个元素(类似于take(1))
5 take(n) 返回一个由数据集的前n个元素组成的数组
6 takeOrdered(n,[ordering]) 返回自然顺序或者自定义顺序的前 n 个元素
7 saveAsTextFile(path) 将数据集的元素以textfile的形式保存到hdfs文件系统或者其他支持的文件系统,对于每个元素,spark将会调用toString方法,将它装换为文件中的文本
8 saveAsSequenceFile(path) 将数据集中的元素以hadoop sequencefile的格式保存到指定的目录下,可以使hdfs或者其他hadoop支持的文件系统
9 saveAsObjectFile(path) 将数据集的元素,以 Java 序列化的方式保存到指定的目录下
10 countByKey() 针对(K,V)类型的RDD,返回一个(K,Int)的map,表示每一个key对应的元素个数
11 foreach(func) 在数据集的每一个元素上,运行函数func
12 foreachPartition(func) 在数据集的每一个分区上,运行函数func

1.4.RDD常用算子操作

启动spark-shell:

#进入spark shell(node03)
cd /export/servers/spark-2.0.2-bin-hadoop2.7/bin
spark-shell --master spark://node01:7077

1.4.1.map、filter

# 通过并行化生成rdd
val rdd1=sc.parallelize(List(5, 6, 4, 7, 3, 8, 2, 9, 1, 10))
#对rdd1里的每一个元素乘2然后排序
 val rdd2=rdd1.map(_*2).sortBy(x=>x,true)
# 过滤出大于等于5的元素
 val rdd3=rdd2.filter(_>=5)
# 将元素以数组的方式在客户端显示
 rdd3.collect

在这里插入图片描述

1.4.2.flatMap

# 通过并行化生成rdd
val rdd1 = sc.parallelize(Array("a b c", "d e f", "h i j"))
# 将rdd1里面的每一个元素先切分再压平
val rdd2=rdd1.flatMap(_.split(" "))
#将元素以数组的方式在客户端显示
rdd2.collect

在这里插入图片描述

1.4.3.union、intersection

#并行化生成两个rdd
val rdd1 = sc.parallelize(List(5, 6, 4, 3))
val rdd2 = sc.parallelize(List(1, 2, 3, 4))
# 求并集
val unionRdd=rdd1.union(rdd2)
# 求交集
val intersectRdd=rdd1.intersection(rdd2)
# 并集去重
val distinctRdd=unionRdd.distinct
# 在客户端显示结果集
unionRdd.collect
intersectRdd.collect
distinctRdd.collect

在这里插入图片描述

1.4.4.join、groupByKey

# 并行化生成两个rdd
val rdd1 = sc.parallelize(List(("tom", 1), ("jerry", 3), ("kitty", 2)))
val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 1), ("shuke", 2)))
# 联合操作求join
val rdd3=rdd1.join(rdd2)
rdd3.collect
# 求并集
val rdd4=rdd1.union(rdd2)
rdd4.collect
# 按key进行分组
val rdd5=rdd4.groupByKey
rdd5.collect

在这里插入图片描述

1.4.5.cogroup

# 并行化生成两个rdd
val rdd1 = sc.parallelize(List(("tom", 1), ("tom", 2), ("jerry", 3), ("kitty", 2)))
val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 1), ("jim", 2)))
# cogroup操作
val rdd3=rdd1.cogroup(rdd2)
# 在客户端显示结果集
rdd3.collect

在这里插入图片描述

1.4.6.reduce

# 并行化生成一个rdd
val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5))
# reduce操作
val rdd2=rdd1.reduce(_+_)

在这里插入图片描述

1.4.7.reduceByKey、sortByKey

# 并行化生成两个rdd
val rdd1 = sc.parallelize(List(("tom", 1), ("jerry", 3), ("kitty", 2),  ("shuke", 1)))
val rdd2 = sc.parallelize(List(("jerry", 2), ("tom", 3), ("shuke", 2), ("kitty", 5)))
# 求并集union
val rdd3=rdd1.union(rdd2)
rdd3.collect
# 按key进行聚合
val rdd4=rdd3.reduceByKey(_+_)
rdd4.collect
#按value的降序排序
val rdd5=rdd4.map(t=>(t._2,t._1)).sortByKey(false).map(t=>(t._2,t._1))
rdd5.collect

在这里插入图片描述

1.4.8.repartition、coalesce

# 并行化生成一个rdd(指定三个分区)
val rdd1 = sc.parallelize(1 to 10,3)
rdd1.getNumPartitions
# 利用repartition改变rdd1分区数
  ## 减少分区
  rdd1.repartition(2).partitions.size
  ## 增加分区
  rdd1.repartition(4).partitions.size
#利用coalesce改变rdd1分区数(只能减少分区)
  ##减少分区
  rdd1.coalesce(2).partitions.size

在这里插入图片描述

1.5.RDD编程实战

1.5.1.通过spark实现点击流日志分析案例

1.5.1.1.点击流介绍

点击流数据是由网站日志中整理得到的,它可以比网站日志本身包含更多的信息 。更注重用户浏览网站的整个流程,网站日志中记录的用户点击就像是图上的“”,而点击流更像是将这些“”串起来形成的“线” 。可以把“点”认为是网站的Page(单个操作),而“线”则是访问网站的Session (一次会话完整操作)。

点(Page)的信息:URL、点击时间(Hit Time)、页面停留时间(Time on Page)、位于Session的第几步(Step),Sessionid(在关系数据库中可以用于跟Session表的外键关联)……

**线(Session)的信息:**Sessionid(唯一标识符)、访问来源(Referrers)、进入页面(Entrance)、离开页面(Exit)、开始时间(Begin Time)、结束时间(End Time)、访问时长(Time on Site)、访问页面数(Depth of Visit)、访问用户(Cookie)……

1.5.1.2.案例日志格式介绍

在这里插入图片描述

日志组成:

ip地址 用户Id cookieId 访问时间 请求方式 请求协议 响应状态码 流量 请求的url 客户端信息

1.5.1.3.创建项目

在这里插入图片描述

1.5.1.3.导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>project_djl</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <properties>
        <scala.version>2.11.8</scala.version>
        <hadoop.version>2.7.4</hadoop.version>
        <spark.version>2.0.2</spark.version>
        <mysql.version>5.1.38</mysql.version>


    </properties>

    <dependencies>
        <!--scala依赖-->
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>${scala.version}</version>
        </dependency>
        <!--spark依赖-->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>${spark.version}</version>
        </dependency>
        <!--hadoop依赖-->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
        <!--依赖mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
    </dependencies>

    <!--配置插件-->
    <build>
        <plugins>
            <!--scala编译插件-->
            <plugin>
                <groupId>org.scala-tools</groupId>
                <artifactId>maven-scala-plugin</artifactId>
                <version>2.15.2</version>
                <executions>
                    <execution>
       
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值