spark生成大宽表的parquet性能优化
1. 背景介绍
2. 第一版实现过程
private def CTRL_A = '\001'
private def CTRL_B = '\002'
private def CTRL_C = '\003'
def main(args: Array[String]): Unit = {
val resourcePath = this.getClass.getResource("/resource.txt").getFile
val sourcePath = this.getClass.getResource("/*.gz").getFile
val output = "/home/dev/output"
val conf = new SparkConf().setAppName("user test").setMaster("local")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
sqlContext.setConf("spark.sql.parquet.binaryAsString", "true")
sqlContext.setConf("spark.sql.inMemoryColumnarStorage.compressed", "true")
sqlContext.setConf("spark.sql.parquet.compression.codec", "snappy")
val map: Map[String, String] = buildResource(resourcePath)
val schema = buildSchema(map)
val bd = sc.broadcast(map)
val bdSchema = sc.broadcast(schema)
val start=System.currentTimeMillis()
val rdd = sc.textFile(sourcePath)
.map(line => {
val map = buildUser(line, bd.value)
buildRow(map._3, map._1, map._2)
})
// rdd.foreach(_=>())
// sqlContext.createDataFrame(rdd, bdSchema.value).write.mode(SaveMode.Overwrite).json(output)
sqlContext.createDataFrame(rdd, bdSchema.value).write.mode(SaveMode.Overwrite).parquet(output)
val end = System.currentTimeMillis()
System.out.print(end - start)
}
/**
* 读取资源文件
* @param file
* @return
*/
def buildResource(file: String): Map[String, String] = {
val reader = Source.fromFile(file)
val map = new mutable.HashMap[String, String]()
for (line <- reader.getLines() if !Strings.isNullOrEmpty(line)) {
val arr = StringUtils.splitPreserveAllTokens(line, '\t')
map.+=((arr(0), "0"))
}
map.toMap
}
/**
* 生成用户属性
* @param line
* @param map
* @return
*/
def buildUser(line: String, map: Map[String, String]): (String, Int, Map[String, String]) = {
if (Strings.isNullOrEmpty(line)) {
return ("", 0, Map.empty)
}
val array = StringUtils.splitPreserveAllTokens(line, CTRL_A)
val cookie = if (Strings.isNullOrEmpty(array(0))) "-" else array(0)
val platform = array(1).toInt
val base = buildFeature(array(2))
val interest = buildFeature(array(3))
val buy = buildFeature(array(4))
val features = base ++ interest ++ buy
val result = new mutable.HashMap[String, String]()
for (pair <- map) {
val value = if (features.contains(pair._1)) "1" else "0"
result.+=((pair._1, value))
}
(cookie, platform, result.toMap)
}
/**
* 抽取用户标签
* @param expr
* @return
*/
def buildFeature(expr: String): Array[String] = {
if (Strings.isNullOrEmpty(expr)) {
return Array.empty
}
val arr = StringUtils.splitPreserveAllTokens(expr, CTRL_B)
val buffer = new ArrayBuffer[String]()
for (key <- arr) {
val pair = StringUtils.splitPreserveAllTokens(key, CTRL_C)
buffer += (s"_${pair(0)}")
}
buffer.toArray
}
/**
* 动态生成DataFrame的Schema
* @param map
* @return
*/
def buildSchema(map: Map[String, String]): StructType = {
val buffer = new ArrayBuffer[StructField]()
buffer += (StructField("user", StringType, false))
buffer += (StructField("platform", IntegerType, false))
for (pair <- map) {
buffer += (StructField(s"_${pair._1}", IntegerType, true))
}
return StructType(List(buffer: _*))
}
/**
* 将用户属性构造成Spark SQL的Row
* @param map
* @param user
* @param platform
* @return
*/
def buildRow(map: Map[String, String], user: String, platform: Int): Row = {
val buffer = new ArrayBuffer[Any]()
buffer += (user)
buffer += (platform)
for (pair <- map) {
buffer += (pair._2.toInt)
}
return Row(buffer: _*)
}
3. 第二版实现过程
在第一版中初步怀疑是DataFrame在生成parquet时进行了一些特殊逻辑的处理,所以决定自己实现ParquetWriter方法来测试下性能,采用了avro来向parquet中写入数据。方法大概包含定义好avro资源文件,然后使用AvroParquetWriter类来向parquet中写入内容,具体的写入方法类似于https://blog.csdn.net/gg584741/article/details/51614752。通过这种方式来写入parquet,相同数据量的情况下,性能提升了一倍多。至于为什么性能有这么大的提升,有待后续研究。到此优化就告一段落了。
val Schema = (new Schema.Parser()).parse(new File(file))
来动态生成Schema来供后续AvroParquetWriter使用。
spark生成大宽表的parquet性能优化的更多相关文章
- Spark Tungsten揭秘 Day1 jvm下的性能优化
Spark Tungsten揭秘 Day1 jvm下的性能优化 今天开始谈下Tungsten,首先我们需要了解下其背后是符合了什么样的规律. jvm对分布式天生支持 整个Spark分布式系统是建立在分 ...
- Hadoop如何将TB级大文件的上传性能优化上百倍?
这篇文章,我们来看看,Hadoop的HDFS分布式文件系统的文件上传的性能优化. 首先,我们还是通过一张图来回顾一下文件上传的大概的原理. 由上图所示,文件上传的原理,其实说出来也简单. 比如有个TB ...
- android app性能优化大汇总(UI渲染性能优化)
UI性能测试 性能优化都需要有一个目标,UI的性能优化也是一样.你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望,是否可以去量化这些期望呢?我们可以从人机交互心理学的角度来考虑 ...
- 一次EF批量插入多表数据的性能优化经历
距离上次的博客已经有15个多月了,感慨有些事情还是需要坚持,一旦停下来很有可能就会停很久或者从此再也不会坚持.但我个人一直还坚持认为属于技术狂热份子,且喜欢精益求精的那种.最近遇到两个和数据迁移相关的 ...
- kettle大数据量读写mysql性能优化
修改kettleDB连接设置 1. 增加批量写的速度:useServerPrepStmts=false rewriteBatchedStatements=true useCompressio ...
- Sql Server RowNumber和表变量分页性能优化小计
直接让代码了,对比看看就了解了 当然,这种情况比较适合提取字段较多的情况,要酌情而定 性能较差的: WITH #temp AS ( ...
- android app性能优化大汇总
这里根据网络上各位大神已经总结的知识内容做一个大汇总,作为记录,方便后续“温故知新”. 性能指标: (1)使用流畅度: 图片处理器每秒刷新的帧数(FPS),可用来指示页面是否平滑的渲染.高的帧率可以 ...
- Oracle12c 性能优化攻略:攻略1-3: 匹配表类型与业务需求
注:目录表 <Oracle12c 性能优化攻略:攻略目录表> 问题描述 你刚开始使用oracle数据库,并且学习了一些关于可用的各种表类型的知识.例如:可以在堆组织表.索引组织表等之间支出 ...
- Elasticsearch 通关教程(七): Elasticsearch 的性能优化
硬件选择 Elasticsearch(后文简称 ES)的基础是 Lucene,所有的索引和文档数据是存储在本地的磁盘中,具体的路径可在 ES 的配置文件../config/elasticsearch. ...
随机推荐
- js中typeof与instanceof用法
今天写JS代码,遇到动态生成多个名称相同的input复选按钮 需要判断其是否是数组,用到了if (typeof(document.MapCheckMgr.checkid)!="undefin ...
- rails 杂记 - erb 中的 form_helper
原文 1. form_tag 1) 基础 Form <%= form_tag do %> Form contents <% end %> 生成 html <form ac ...
- transform的兼容性写法浏览器 和 transition
transform:rotate(7deg); -ms-transform:rotate(7deg); /* IE 9 */ -moz-transform:rotate(7deg); /* Firef ...
- 360自带--JS开发工具箱
360自带–JS开发工具箱 360自带–JS开发工具箱 360自带–JS开发工具箱
- GC垃圾回收器
java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”.jvm解决的两个问题:给对象分配内存以及回收分配给对象的内存.GC:将内存中不再被使用的对象进行回收.GC的作用域是JVM运行时 ...
- 悬线法 || BZOJ 1057: [ZJOI2007]棋盘制作 || Luogu P1169 [ZJOI2007]棋盘制作
题面:P1169 [ZJOI2007]棋盘制作 题解: 基本是悬线法板子,只是建图判断时有一点点不同. 代码: #include<cstdio> #include<cstring&g ...
- [Day10]继承、抽象类
1.继承:在一个现有类的基础上去构建一个新的类,构建出来的新类被称为子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法. 2.继承的格式 : class 子类 extends 父类{} ...
- python的var_dump,打印对象内容
from __future__ import print_function from types import NoneType __author__ = "Shamim Hasnath&q ...
- airsim 无法打开包括文件corecrt.h
原因: 显示无法打开包括文件corecrt.h.在网上找了很多方法,最后综合起来发现,这个问题网上很多人反映,应该是vs2015的一个BUG,如果是选择"从父级或项目默认设置继承" ...
- 2018-2019-1 20189203《Linux内核原理与分析》第四周作业
第一部分 课本学习 内核版本号:Linux内核自2013年12月起,就以A.B.C.D的方式命名.A和B变得无关紧要,C是内核的真实版本.每一个版本的变化都会带来新的特性,如内部API的变化等,改动的 ...