持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情
背景
使用Hive执行sql的时候执行太慢,所以使用spark执行,效率大大提高,有需求执行几年或者某段时间的sql任务,如果直接指定长时间会任务失败,分多个又需要多次提交,所以写一个小任务自己使用
代码解析
环境初始化
val builder: SparkSession.Builder = SparkSession.builder.enableHiveSupport
val parameterMap: mutable.Map[String, String] = paramsMap.asScala
if(parameterMap != null){
for ((k, v) <- parameterMap) {
builder.config(k, v)
}
}
val spark: SparkSession = builder.getOrCreate
参数配置
val paramsMap = new util.HashMap[String, String]()
//是否开启动态资源配置,根据工作负载来衡量是否应该增加或减少executor,默认false
paramsMap.put("spark.dynamicAllocation.enabled", "false")
//在DML/DDL中是否支持动态分区,默认false
paramsMap.put("hive.exec.dynamic.partition", "true")
//默认strict,在strict模式下,动态分区的使用必须在一个静态分区确认的情况下,其他分区可以是动态
paramsMap.put("hive.exec.dynamic.partition.mode", "nonstrict")
//每个mapper/reducer节点可以创建的最大动态分区数,默认100
paramsMap.put("hive.exec.max.dynamic.partitions.pernode", "10000")
//动态分区的上限,默认1000
paramsMap.put("hive.exec.max.dynamic.partitions", "10000")
//spark.sql.warehouse.dir是spark.sql运行hive的默认路径,如果想运行在hdfs上,可以通过这个配置项来实现,但是一定要是部署好的hive才会生效,spark内置的hive是会将元信息放到spark_home/bin目录下。 //spark.sql.warehouse.dir指定的就是数据的存放位置
paramsMap.put("spark.sql.warehouse.dir","hdfs://xxx/hive/warehouse")
//本地测试
//paramsMap.put("spark.master", "local")
执行过程
//参数判断
if (null == args || args.length != 3) {
throw new Exception("args error " + JSON.toJSONString(args, SerializerFeature.EMPTY: _*))
}
logger.info("args :" + JSON.toJSONString(args, SerializerFeature.EMPTY: _*))
//自己使用所以没有进行严格的参数校验
val startDate = args(0)
val endDate = args(1)
val initSql = args(2)
//获取日期区间
val dateList: mutable.ListBuffer[String] = getBetweenDates(startDate, endDate)
//遍历执行任务
for (elem <- dateList) {
logger.info("elem:" + elem)
val sql: String = HiveUtils.hiveStaticdateReplace(initSql, elem)
logger.info(s"exec sql:$sql")
val start: Long = System.currentTimeMillis()
try {
spark.sql(sql).show(100)
} catch {
case e: Exception =>
throw e
} finally {
val end: Long = System.currentTimeMillis()
logger.info(s"exec sql:$sql total_time:${(end - start) / 1000d}s")
}
}
关闭任务
spark.close()
日期工具方法
def getBetweenDates(start: String, end: String): mutable.ListBuffer[String] = {
val startData = new SimpleDateFormat("yyyy-MM-dd").parse(start); //定义起始日期
val endData = new SimpleDateFormat("yyyy-MM-dd").parse(end); //定义结束日期
val dateFormat: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")
var buffer = new mutable.ListBuffer[String]()
buffer += dateFormat.format(startData.getTime())
val tempStart = Calendar.getInstance()
tempStart.setTime(startData)
tempStart.add(Calendar.DAY_OF_YEAR, 1)
val tempEnd = Calendar.getInstance()
tempEnd.setTime(endData)
while (tempStart.before(tempEnd)) {
// result.add(dateFormat.format(tempStart.getTime()))
buffer += dateFormat.format(tempStart.getTime())
tempStart.add(Calendar.DAY_OF_YEAR, 1)
}
buffer += dateFormat.format(endData.getTime())
logger.error(buffer.toString)
buffer
}
日期替换方法
/**
* 替换hive sql日期
*/
def hiveStaticdateReplace(sql: String, staticdate: String): String = {
sql.replace("current_date()", s"'${staticdate}'").
replace("CURRENT_DATE()", s"'${staticdate}'").
replace("current_date", s"'${staticdate}'").
replace("CURRENT_DATE", s"'${staticdate}'")
}
任务提交
spark-submit --master yarn --deploy-mode cluster --class com.xxx.xxx --driver-cores 1 --driver-memory 1G --num-executors 1 --executor-cores 1 --executor-memory 1G --name BatchExecHiveSql --queue xxx.xxx xxx.jar 2021-01-01 2022-05-31 "insert overwrite table test.xxx partition(staticdate) select * from test.xxx where staticdate = CURRENT_DATE"