详解 Spark 中的 Bucketing
什么是 Bucketing
Bucketing 就是利用 buckets(按列进行分桶)来决定数据分区(partition)的一种优化技术,它可以帮助在计算中避免数据交换(avoid data shuffle)。并行计算的时候shuffle常常会耗费非常多的时间和资源.
Bucketing 的基本原理比较好理解,它会根据你指定的列(可以是一个也可以是多个)计算哈希值,然后具有相同哈希值的数据将会被分到相同的分区。

Bucket和Partition的区别
Bucket的最终目的也是实现分区,但是和Partition的原理不同,当我们根据指定列进行Partition的时候,Spark会根据列的名字对数据进行分区(如果没有指定列名则会根据一个随机信息对数据进行分区)。Bucketing的最大不同在于它使用了指定列的哈希值,这样可以保证具有相同列值的数据被分到相同的分区。
怎么用 Bucket
按Bucket保存
目前在使用 bucketBy 的时候,必须和 sortBy,saveAsTable 一起使用,如下。这个操作其实是将数据保存到了文件中(如果不指定path,也会保存到一个临时目录中)。
df.write
.bucketBy(10, "name")
.sortBy("name")
.mode(SaveMode.Overwrite)
.option("path","/path/to")
.saveAsTable("bucketed")
数据分桶保存之后,我们才能使用它。
直接从table读取
在一个SparkSession内,保存之后你可以通过如下命令通过表名获取其对应的DataFrame.
val df = spark.table("bucketed")
其中spark是一个SparkSession对象。获取之后就可以使用DataFrame或者在SQL中使用表。
从已经保存的Parquet文件读取
如果你要使用历史保存的数据,那么就不能用上述方法了,也不能像读取常规文件一样使用 spark.read.parquet() ,这种方式读进来的数据是不带bucket信息的。正确的方法是利用CREATE TABLE 语句,详情可用参考 https://docs.databricks.com/spark/latest/spark-sql/language-manual/create-table.html
CREATE TABLE [IF NOT EXISTS] [db_name.]table_name
[(col_name1 col_type1 [COMMENT col_comment1], ...)]
USING data_source
[OPTIONS (key1=val1, key2=val2, ...)]
[PARTITIONED BY (col_name1, col_name2, ...)]
[CLUSTERED BY (col_name3, col_name4, ...) INTO num_buckets BUCKETS]
[LOCATION path]
[COMMENT table_comment]
[TBLPROPERTIES (key1=val1, key2=val2, ...)]
[AS select_statement]
示例如下:
spark.sql(
"""
|CREATE TABLE bucketed
| (name string)
| USING PARQUET
| CLUSTERED BY (name) INTO 10 BUCKETS
| LOCATION '/path/to'
|""".stripMargin)
用Buckets的好处
在我们join两个表的时候,如果两个表最好按照相同的列划分成相同的buckets,就可以完全避免shuffle。根据前面所述的hash值计算方法,两个表具有相同列值的数据会存放在相同的机器上,这样在进行join操作时就不需要再去和其他机器通讯,直接在本地完成计算即可。假设你有左右两个表,各有两个分区,那么join的时候实际计算就是下图的样子,两个机器进行计算,并且计算后分区还是2.

而当需要shuffle的时候,会是这样的,

细心的你可能发现了,上面两个分区对应两个Executor,下面shuffle之后对应的怎么成了三个Executor了?没错,当数据进行shuffle之后,分区数就不再保持和输入的数据相同了,实际上也没有必要保持相同。
本地测试
我们考虑的是大数据表的连接,本地测试的时候一般使用小的表,所以逆序需要将小表自动广播的配置关掉。如果开启小表广播,那么两个小表的join之后分区数是不会变的,例如:
| 左表分区数 | 右表分区数数 | Join之后的分区数 |
|---|---|---|
| 3 | 3 | 3 |
关闭配置的命令如下:
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
正常情况下join之后分区数会发生变化:
| 左表分区数 | 右表分区数数 | Join之后的分区数 |
|---|---|---|
| 3 | 3 | 200 |
这个200其实就是 "spark.sql.shuffle.partitions" 配置的值,默认就是200. 所以如果在Join过程中出现了shuffle,join之后的分区一定会变,并且变成spark.sql.shuffle.partitions的值。通常你需要根据自己的集群资源修改这个值,从而优化并行度,但是shuffle是不可避免的。
左右两个表Bucket数目不一致时
实际测试结果如下:
| 左表Bucket数 | 右表Bucekt数 | Join之后的分区数 |
|---|---|---|
| 8 | 4 | 8 |
| 4 | 4 | 4 |
Spark依然会利用一些Bucekt的信息,但具体怎么执行目前还不太清楚,还是保持一致的好。
另外,如果你spark job的可用计算核心数小于Bucket值,那么从文件中读取之后Bucekt值会变,就是说bucket的数目不会超过你能使用的最大计算核数。
不要使用的 <=> 符号!!!
在处理null值的时候,我们可能会用到一些特殊的函数或者符号,如下表所示。但是在使用bucket的时候这里有个坑,一定要躲过。join的时候千万不要使用 <=> 符号,使用之后spark就会忽略bucket信息,继续shuffle数据,原因可能和hash计算有关。

如果你喜欢我的文章,可以在任一平台搜索【黑客悟理】关注我,非常感谢!
详解 Spark 中的 Bucketing的更多相关文章
- Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕
Spark Streaming揭秘 Day28 在集成开发环境中详解Spark Streaming的运行日志内幕 今天会逐行解析一下SparkStreaming运行的日志,运行的是WordCountO ...
- jQuery:详解jQuery中的事件(二)
上一篇讲到jQuery中的事件,深入学习了加载DOM和事件绑定的相关知识,这篇主要深入讨论jQuery事件中的合成事件.事件冒泡和事件移除等内容. 接上篇jQuery:详解jQuery中的事件(一) ...
- 图文详解Unity3D中Material的Tiling和Offset是怎么回事
图文详解Unity3D中Material的Tiling和Offset是怎么回事 Tiling和Offset概述 Tiling表示UV坐标的缩放倍数,Offset表示UV坐标的起始位置. 这样说当然是隔 ...
- 【转】详解C#中的反射
原帖链接点这里:详解C#中的反射 反射(Reflection) 2008年01月02日 星期三 11:21 两个现实中的例子: 1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内 ...
- 详解Webwork中Action 调用的方法
详解Webwork中Action 调用的方法 从三方面介绍webwork action调用相关知识: 1.Webwork 获取和包装 web 参数 2.这部分框架类关系 3.DefaultAction ...
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
- 深入详解SQL中的Null
深入详解SQL中的Null NULL 在计算机和编程世界中表示的是未知,不确定.虽然中文翻译为 “空”, 但此空(null)非彼空(empty). Null表示的是一种未知状态,未来状态,比如小明兜里 ...
- java 乱码详解_jsp中pageEncoding、charset=UTF -8"、request.setCharacterEncoding("UTF-8")
http://blog.csdn.net/qinysong/article/details/1179480 java 乱码详解__jsp中pageEncoding.charset=UTF -8&quo ...
- 详解Objective-C中委托和协议
Objective-C委托和协议本没有任何关系,协议如前所述,就是起到C++中纯虚类的作用,对于“委托”则和协议没有关系,只是我们经常利用协议还实现委托的机制,其实不用协议也完全可以实现委托. AD: ...
随机推荐
- vue结合百度地图Api实现周边配置查询及根据筛选结果显示对应坐标详情
在我们平常写房地产相关项目的时候经常会用到百度地图,因为这一块客户会考虑到房源周围的配套或者地铁线路所以在这类项目中就不可以避免的会用到百度地图,当然这只是其中一种,其他地图工具也可以,因为我这个项目 ...
- 大数据hbase分布式安装及其部署。
大数据hbase分布式安装及其部署. 首先要启动Hadoop以及zookeeper,可以参考前面发布的文章. 将hbase的包上传至master节点 这里我使用的是1.3.6的版本,具体的根据自己的版 ...
- 20199310《Linux内核原理与分析》第十五周作业 Linux安全实验
1 补充知识 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据缓冲器和返回地址的暂时关闭, ...
- python学习24之异常
'''''''''1.低级错误:纯语法错误2.中级错误:代码存在隐性错误,逻辑缺陷3.高级错误:软件面对不确定性的异常错误''''''一.捕获异常1.基本异常捕获语句try: #异常捕捉语句的开始 代 ...
- qt tableview 选择模式
QAbstractItemView::SingleSelection QAbstractItemView::ContiguousSelection QAbstractItemView::Extende ...
- Docker 部署 halo 启动时,MySql 连接不上
原因 halo 是部署在 docker 容器内部的,而 MySql 是部署在"宿主机"上的,docker默认的网络模式是bridge,容器内127.0.0.1访问不到的,把网络模式 ...
- JDK14的新特性
文章目录 虽然JDK13在今年的9月17号才发布,但是丝毫不会影响到下一个版本JDK14的开发工作.听说官方定的新功能马上就要官宣了,我们这里不妨来提前推断一下. 在9月17号的发布中,Oracle提 ...
- 热门云服务超87GB电子邮箱和密码泄露,黑客已验证大部分数据
热门云存储服务Mega被曝发现超87GB电子邮件地址和密码泄露(源数据目前已被删除,但已流传到个别黑客网站),其中包含近7.73亿电子邮件地址和2200万密码. 近日,国外一名安全研究人员Troy H ...
- 算法竞赛进阶指南--在单调递增序列a中查找>=x的数中最小的一个(即x或x的后继)
while (l < r) { int mid = (l + r) / 2; if (a[mid] >= x) r = mid; else l = mid + 1; }
- 深度使用魅族16T后的评价(本人魅友,绝对客观公正,不要盲目的为手机厂商辩护,想想从当初到现在,魅族正在一步步背离自己的信仰,有问题,解决问题才能有更好的发展)
缺点: 电池电量问题 发布会上,那都是吹的,真是的体验效果掉电很快,大概只有描述的2/3的使用时间 屏幕触控失灵问题 我也看了很多评价,这个也挺多的,可能是魅族品控的问题,某宝到现在没给我退货换货 发 ...