RDD的分区器

Spark目前支持Hash分区和Range分区,用户也可以自定义分区,Hash分区为当前的默认分区,Spark中分区器直接决定了RDD中分区的个数、RDD中每条数据经过Shuffle过程属于哪个分区和Reduce的个数。

注意:

(1)只有Key-Value类型的RDD才有分区器的,非Key-Value类型的RDD分区器的值是None
(2)每个RDD的分区ID范围:0~numPartitions-1,决定这个值是属于那个分区的。

Hash分区

HashPartitioner分区的原理:对于给定的key,计算其hashCode,并除以分区的个数取余,如果余数小于0,则用余数+分区的个数(否则加0),最后返回的值就是这个key所属的分区ID。

查看hash分区原码如下:

  1. */
  2. class HashPartitioner(partitions: Int) extends Partitioner {
  3. require(partitions >= 0, s"Number of partitions ($partitions) cannot be negative.")
  4.  
  5. def numPartitions: Int = partitions
  6.  
  7. def getPartition(key: Any): Int = key match {
  8. case null => 0//key为0则统统放入0号分区
  9. case _ => Utils.nonNegativeMod(key.hashCode, numPartitions)
  10. //否则调用这个方法,根据key的hashcode和分区数,得到分区号
  11. }
  1. def nonNegativeMod(x: Int, mod: Int): Int = {
    val rawMod = x % mod
    rawMod + (if (rawMod < 0) mod else 0)
    }

ranger分区

HashPartitioner分区弊端:可能导致每个分区中数据量的不均匀,极端情况下会导致某些分区拥有RDD的全部数据。

RangePartitioner作用:将一定范围内的数映射到某一个分区内,尽量保证每个分区中数据量的均匀,而且分区与分区之间是有序的,一个分区中的元素肯定都是比另一个分区内的元素小或者大,但是分区内的元素是不能保证顺序。简单的说就是将一定范围内的数映射到某一个分区内。实现过程为:

第一步:先从整个RDD中抽取出样本数据,将样本数据排序,计算出每个分区的最大key值,形成一个Array[KEY]类型的数组变量rangeBounds;

第二步:判断key在rangeBounds中所处的范围,给出该key值在RDD中的分区id下标;该分区器要求RDD中的KEY类型必须是可以排序的

自定义分区器

要实现自定义的分区器,你需要继承 org.apache.spark.Partitioner 类并实现下面两个个方法。

(1)numPartitions: Int:返回创建出来的分区数。

(2)getPartition(key: Any): Int:返回给定键的分区编号(0到numPartitions-1)。

示例代码如下:将key对分区数求余数,得到分区号。

  1. package partitioner
  2.  
  3. import org.apache.spark.Partitioner
  4.  
  5. class MyPartitioner(partitions:Int) extends Partitioner{
  6.  
  7. override def numPartitions: Int = {
  8. return partitions;
  9. }
  10.  
  11. override def getPartition(key: Any): Int = {
  12.  
  13. val mykey : Int = key.asInstanceOf;
  14. //val i: Int = key.asInstanceOf[Int]
  15. return mykey%partitions ;
  16. }
  17. }
  18.  
  19. def main(args: Array[String]): Unit = {
  20.  
  21. val sc: SparkContext = new SparkContext(new SparkConf()
  22. .setMaster("local[*]").setAppName("spark"))
  23.  
  24. val raw: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c"), (4, "d")))
  25. raw.saveAsTextFile("E:/idea/spark2/out/partitioner_before")
  26.  
  27. val partitionedRDD: RDD[(Int, String)] = raw.partitionBy(new MyPartitioner(2))
  28. println(partitionedRDD.partitioner)
  29. partitionedRDD.saveAsTextFile("E:/idea/spark2/out/partitioner_after")
  30. }

查看分区后数据的分布:

0号文件:(2,b)(4,d)

1号文件:(1,a)(3,c)

使用自定义的 Partitioner 是很容易的:只要把它传给 partitionBy() 方法即可。Spark 中有许多依赖于数据混洗的方法,比如 join() 和 groupByKey(),它们也可以接收一个可选的 Partitioner 对象来控制输出数据的分区方式。

RDD(六)——分区器的更多相关文章

  1. Spark分区器浅析

    分区器作用:决定该数据在哪个分区 概览: 仅仅只有pairRDD才可能持有分区器,普通RDD的分区器为None 在分区器为None时RDD分区一般继承至父RDD分区 初始RDD分区数: 由集合创建,R ...

  2. Spark(九)【RDD的分区和自定义Partitioner】

    目录 spark的分区 一. Hash分区 二. Ranger分区 三. 自定义Partitioner 案例 spark的分区 ​ Spark目前支持Hash分区和Range分区,用户也可以自定义分区 ...

  3. 大数据学习day19-----spark02-------0 零碎知识点(分区,分区和分区器的区别) 1. RDD的使用(RDD的概念,特点,创建rdd的方式以及常见rdd的算子) 2.Spark中的一些重要概念

    0. 零碎概念 (1) 这个有点疑惑,有可能是错误的. (2) 此处就算地址写错了也不会报错,因为此操作只是读取数据的操作(元数据),表示从此地址读取数据但并没有进行读取数据的操作 (3)分区(有时间 ...

  4. Spark源码分析之分区器的作用

    最近因为手抖,在Spark中给自己挖了一个数据倾斜的坑.为了解决这个问题,顺便研究了下Spark分区器的原理,趁着周末加班总结一下~ 先说说数据倾斜 数据倾斜是指Spark中的RDD在计算的时候,每个 ...

  5. RDD的分区相关

    分区是rdd的一个属性,每个分区是一个迭代器 分区器是决定数据数据如何分区 RDD划分成许多分区分布到集群的节点上,分区的多少涉及对这个RDD进行并行计算的粒度.用户可以获取分区数和设置分区数目,默认 ...

  6. 028 Partitioner:数据分区器

    Partitioner:数据分区器,决定数据到下一个RDD的时候在那一个分区 HashPartitioner:根据key的hashCode值来实现 RangePartitioner: 根据key所属范 ...

  7. spark自定义分区器实现

    在spark中,框架默认使用的事hashPartitioner分区器进行对rdd分区,但是实际生产中,往往使用spark自带的分区器会产生数据倾斜等原因,这个时候就需要我们自定义分区,按照我们指定的字 ...

  8. Cassandra1.2文档学习(4)——分区器

    参考文档:http://www.datastax.com/documentation/cassandra/1.2/webhelp/index.html#cassandra/architecture/a ...

  9. cassandra 3.x官方文档(4)---分区器

    写在前面 cassandra3.x官方文档的非官方翻译.翻译内容水平全依赖本人英文水平和对cassandra的理解.所以强烈建议阅读英文版cassandra 3.x 官方文档.此文档一半是翻译,一半是 ...

随机推荐

  1. linux忘记密码

    linux忘记密码 Linux进入救援模式的方法 视频 centos6.5测试通过 如下 1.开机按esc进入下面界面 2.按e 3.按e 4.DM后空格加上single再回车 5.会回到这里再按b ...

  2. CSS position定位属性

    css中的position属性是用于设置元素位置的定位方式 它有以下几种取值: static:默认定位方式,子容器在父容器中按照默认顺序进行摆放 absolute:绝对定位,元素不占据父容器空间,相当 ...

  3. Day 5 :ArrayList原理、LinkedList原理和方法和迭代器注意事项

    迭代器在变量元素的时候要注意事项: 在迭代器迭代元素 的过程中,不允许使用集合对象改变集合中的元素个数,如果需要添加或者删除只能使用迭代器的方法进行操作.   如果使用过了集合对象改变集合中元素个数那 ...

  4. 记校赛水题----AK爷兼职计

    Description AK爷最近收到一份兼职,是去幼儿园看小朋友,AK爷认为看孩子这件事情很简单,但是事实并非如此.幼儿园里的孩子们喜欢数学,不仅九九乘法口诀倒背如流而且精通各种算法.某天,AK爷上 ...

  5. python try catch 打印traceback

    1. import traceback try: print(AB) except Exception, e: traceback.print_exc()

  6. 18 11 24 简单的http服务器

    ---恢复内容开始--- import socket def service_client(new_socket): """为这个客户端返回数据""& ...

  7. QMainWindow的空间布局结构

    简单讲一下Qt的QMainWindow的结构,Qt的顶级窗口有三种类型,首先是万恶之源(...应该说是大部分控件的父类...)的QWidget,然后是QMainWidget和QDialog,后面两者也 ...

  8. clion之CMakeLists的学习

    什么是CMake CMake是一个跨平台的安装(编译)工具,可以用简单的语句来描述所有平台的安装(编译过程).他能够输出各种各样的makefile或者project文件,能测试编译器所支持的" ...

  9. share团队冲刺10

    团队冲刺第十天 昨天:完善代码,美化界面 今天:整合全部代码,基本完成作品 问题:无

  10. hdu1232 城镇间修路(并查集)

    问题是这样的: Problem Description 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇 ...