osap一站式分析模型
运营系统分析平台技术设计:
- 项目定义于运营系统关键指标的数据分析
- 关键代码描述:
- HiveWriter 主要用于写hive表抽象,包括加分区,写hive表,写success文件:
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.spark.sql.SparkSession class HiveWriter(tableName: String, outputDir: String, currentDate: String) { val currentYear = currentDate.substring(0, 4)
val currentMonth = currentDate.substring(4, 6)
val currentDay = currentDate.substring(6, 8) //加分区
def addPartition(ss: SparkSession, hour: String): Unit = {
var query: String = ""
if(hour == ""){
query =
s"""ALTER TABLE $tableName ADD IF NOT EXISTS
|PARTITION(year='$currentYear',month='$currentMonth',day='$currentDay')
|LOCATION '$outputDir/$currentYear/$currentMonth/$currentDay'
""".stripMargin
}else{
query =
s"""ALTER TABLE $tableName ADD IF NOT EXISTS
|PARTITION(year='$currentYear',month='$currentMonth',day='$currentDay',hour=$hour)
|LOCATION '$outputDir/$currentYear/$currentMonth/$currentDay/$hour'
""".stripMargin
}
ss.sql(query)
} //写hive表
def save(ss:SparkSession, name: String, hour: String): Unit = {
var query: String = ""
if(hour == ""){
query =
s"""
|INSERT overwrite TABLE ${tableName} partition(YEAR=${currentYear},MONTH=${currentMonth},DAY=${currentDay})
|SELECT *
|FROM ${name}
""".stripMargin
}else{
query =
s"""
|INSERT overwrite TABLE ${tableName} partition(YEAR=${currentYear},MONTH=${currentMonth},DAY=${currentDay},HOUR=${hour})
|SELECT *
|FROM ${name}
""".stripMargin }
ss.sql(query)
} //写success文件
def writeSuccFile(ss: SparkSession, hour: String): Unit = {
val conf = ss.sparkContext.hadoopConfiguration
val hdfs = FileSystem.get(conf)
var path: String = ""
if(hour == ""){
path = s"${outputDir}/${currentYear}/${currentMonth}/${currentDay}/_SUCCESS"
}else{
path = s"${outputDir}/${currentYear}/${currentMonth}/${currentDay}/${hour}/_SUCCESS"
}
val success = new Path(path)
hdfs.create(success)
} }HiveConf
- QueryConf 主要用于根据传递来的表,时间等信息构建各种ETL需要的SQL:
class QueryConf(tableName: String, currentDate: String, outputDir: String, callTableName: String) { val oneWeekAgo = CommonUtils.calTime(currentDate, Calendar.DATE, -6) //查询字段
val resFields = Seq("pope_act_id","group_id","pid","order_id","is_complete","pay_suc_time") val payQuery =
s"""
|SELECT DISTINCT cast(order_id AS string) order_id,
| pay_suc_time
|FROM table
|WHERE concat(YEAR,MONTH,DAY) = ${currentDate} |AND pay_suc_time != ''
|AND pay_suc_time IS NOT NULL
|AND order_id IS NOT NULL""".stripMargin val callQuery =
s"""
|SELECT DISTINCT pope_act_id,
| group_id,
| pid,
| order_id,
| is_complete
|FROM ${callTableName}
|WHERE concat(YEAR,MONTH,DAY) BETWEEN ${oneWeekAgo} AND ${currentDate}
|AND pope_act_id != ''
|AND pid != 0""".stripMargin }QueryConf
- Process 执行器代码主要用于实际执行的封装:
import org.apache.spark.sql.SparkSession class Process(ss: SparkSession, queryConf: QueryConf, writer: HiveWriter) { def processPay(): Unit = { val payRawData = ss.sql(queryConf.payQuery)
val callRawData = ss.sql(queryConf.callQuery)
val payData = payRawData.join(callRawData,Seq("order_id"),"inner")
.selectExpr(queryConf.resFields: _*) val name = "pay_tbl"
payData.createOrReplaceTempView(name) writer.addPartition(ss, "")
writer.save(ss, name, "")
writer.writeSuccFile(ss, "") } }
object Process {
def apply(ss: SparkSession, queryConf: QueryConf, writer: HiveWriter): Process = {
new Process(ss, queryConf, writer)
}
} - 程序串联 :
val Array(appName, tableName, currentDate, outputDir, callTableName) = args
val ss = SparkSession.builder().appName(appName).enableHiveSupport().getOrCreate() val queryConf = new QueryConf(tableName, currentDate, outputDir, callTableName)
val writer = new HiveWriter(tableName, outputDir, currentDate) val processor = Process(ss,queryConf,writer)
processor.processPay() ss.stop()串联程序
- 关键技术细节:
- SQL字符串表达式建议如下:s"""sql""".stripMargin,更整洁更好维护复杂的SQL
- 涉及到时间计算,预先unix_timestamp(observe_end_time) 在SQL中转化成时间戳,在map算子中只做最简单的判断计算
- Scala 枚举:
object ActivityCallTBL extends Enumeration {
type ActivityCallTBL = Value
val callStatus = Value("gulfstream_ods.ods_binlog_d_order_status_increment")
val callBase = Value("gulfstream_ods.ods_binlog_d_order_base_increment")
} - 定义结构体: {} 里面能写复杂代码定义产出结果,适用于一句话搞不定返回值的情况
- ROW_NUMBER()函数,常用案例包括
- 取出每种rate下score最大的两条记录
- SQL实例:以下意思就是取a_birth_time最早的order信息:
select order_id, passenger_id pid, product_id, a_birth_time ,unix_timestamp(a_birth_time) tim, area, starting_lng, starting_lat, dest_lng, dest_lat, type order_type, combo_type, require_level, extra_info
from ( select * , row_number() over (partition by order_id order by a_birth_time ) as tid
from gulfstream_ods.ods_binlog_d_order_base_increment
where concat(year,month,day,hour)='2017112309' ) a where tid = 1
- sql cast功能: cast(order_id AS string) order_id, spark.sql实现: df.select(df("colA").cast("int"))
sql nvl功能 : nvl(t1.a_create_time,'1971-01-01 00:00:00') AS create_time
- spark select Seq() : selectExpr(Seq(): _*)
- import org.apache.spark.sql.functions 定义spark中用Scala实现的各种SQL常用算子
- withColumn("is_complete",functions.lit(0)) 使用常数类型构造一个新的column,withColumn("testkey", concat($"apollo_exp_id", lit(":0:"), $"apollo_group_id"))
- df("colA") =!= df("colB") column不等于算子
- 添加UDF函数 val genCarpool = spark.udf.register("genCarpool", func), 使用ds.withColumn("ds_carpool", genCarpool(ds("raw_ct")))
- import org.apache.spark.sql.functions._ 之后就能使用 from_unixtime(Colunm) 函数了。
- import spark.implicits._ 牛逼的隐式转换把Scala类型 转化为 DF的类型,包括能使用df.select($"sss")
- functions.explode : spark中集合类打平函数,会把一个集合中的多个元素打平成多个Row
- df.drop 删除指定的column
- functions.when : functions.when(resPre("new_carpool").contains(resPre("ds_carpool")) and ???,1).otherwise(0), 关键技巧先转换成String(1,2,3,4) 再判断contains基本值
- coalesce(10) 在结果DF之后加上控制写hive表最合适的part个数
- package object activity 包对象更好适合常量场景
- <: 继承关系,[T <: Conf]
DF启用别名: activeMarketingActDF.alias("a").join(odsGCouponRuleInfoDF.alias("b"), $"a.info_id" === $"b.id").selectExpr("a.id")
- flatMap函数: 当map中返回的是 LIST 会把结果打平
- selectExpr表达式: ds.selectExpr("colA", "colB as newName", "abs(colC)")
- 多个列中最大,最小值: greatest(exprs: Column*) 跳过null least(exprs: Column*) 跳过null 取最小的值
其他有效函数
- between
- isNaN
- isNull
sparkGC太多可以优化点如下
- 调大task个数,更快GC,减少长时间GC时间拖慢整个进程。优化参数如下
--conf spark.dynamicAllocation.maxExecutors=1000 \
--conf spark.executor.cores=4 \
- 调大执行器的年轻代大小: --conf "spark.executor.extraJavaOptions=-XX:NewSize=2048m"
- 调大task个数,更快GC,减少长时间GC时间拖慢整个进程。优化参数如下
- YarnScheduler: Lost executor 13 on bigdata-hdp-apache1005.xg01.diditaxi.com: Container killed by YARN for exceeding memory limits. 12.5 GB of 12 GB physical memory used. Consider boosting spark.yarn.executor.memoryOverhead. 解决手段:
- --conf spark.executor.memory=12g
- repartition 设置大点
- --conf spark.shuffle.spill.numElementsForceSpillThreshold=1500000 ,内存中row的数量超过这个值,不再放到内存直接写磁盘
osap一站式分析模型的更多相关文章
- Moebius集群:SQL Server一站式数据平台
一.Moebius集群的架构及原理 1.无共享磁盘架构 Moebius集群采用无共享磁盘架构设计,各个机器可以不连接一个共享的设备,数据可以存储在每个机器自己的存储介质中.这样每个机器就不需要硬件上的 ...
- 层次分析模型(AHP)及其MATLAB实现
今天用将近一天的时间学习了层次分析模型(AHP),主要参考了一份pdf,这个网站,和暨南大学章老师的课件,现写出一些自己总结的要点. 一.层次分析法的基本步骤: 角度一: 实际问题——分解——> ...
- 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析(转)
本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/20537737 作者:毛星云(浅墨) ...
- 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发
掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...
- 一站式Hadoop&Spark云计算分布式大数据和Android&HTML5移动互联网解决方案课程(Hadoop、Spark、Android、HTML5)V2的第一门课程
Hadoop是云计算的事实标准软件框架,是云计算理念.机制和商业化的具体实现,是整个云计算技术学习中公认的核心和最具有价值内容. 如何从企业级开发实战的角度开始,在实际企业级动手操作中深入浅出并循序渐 ...
- 一站式远程页面调试工具spy-debugger 2.0,已支持HTTPS
项目名称: spy-debugger 项目地址:https://github.com/wuchangming/spy-debugger 关于spy-debugger npm Build Status ...
- Liunx+C编程一站式学习
Liunx+C编程一站式学习这本书有什么特点?面向什么样的读者?这本书最初是为某培训班的嵌入式系统Linux工程师就业班课程量身定做的教材之一.该课程是为期四个月的全日制职业培训,要求学员毕业时具备非 ...
- 老司机带你用vagrant打造一站式python开发测试环境
前言 作为一个学习和使用Python的老司机,好像应该经常总结一点东西的,让新司机尽快上路,少走弯路,然后大家一起愉快的玩耍. 今天,咱们就使用vagrant配合xshell打造一站式Python ...
- 为智能硬件提供一站式解决方案——机智云GoKit评测
为智能硬件提供一站式解决方案——机智云GoKit评测 2014年12月24日 作者: ladouyu 3 17,414+ 4 EMW3162GoKit开发板STM32F103智能硬件机智云2.0 从物 ...
随机推荐
- SQL server 数据库备份大
首先简单的介绍一下Sql server 备份的类型有: 1:完整备份(所有的数据文件和部分的事务日志文件) 2:差异备份(最后一次完成备份后数据库改变的部分) 3:文件和文件组备份(对指定的文件和文件 ...
- python第四课——线程、进程、协程
面试or笔试题:简述线程.进程.协程之间的关系? 内容概要 1.进程与线程优.缺点的比较 2.适用情况 3.线程 线程的创建 setDaemon join event RLock 队列 4.进程 创建 ...
- mysql安装教程以及配置快捷方式
1.首先双击exe 3.Next 安装过程省略.... Win+r 然后输入:cmd 打开dos窗口后: 输入: mysql -uroot -p你设置的密码 案例:mysql -uroot -proo ...
- JAVA基础知识总结:七
一.面向对象编程 1.什么是面向对象? 万物皆对象 案例一:我想吃大盘鸡 面向过程 面向对象 1.我自己去买一只鸡 1.委托一个会砍价的人去帮忙买鸡 2.我自己宰鸡 2.委托一个胆大的人宰鸡 3.我自 ...
- ajax+分页
<!DOCTYPE html> <html> <head lang="zh-cn"> <meta charset="UTF-8& ...
- Java web学习 Cookie&&Session
cookie&&session 会话技术 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,成为一次会话.会 话技术就是记录这次会话中客户端的状态与数据的. 会话技术分为Coo ...
- 读书笔记-你不知道的JS上-闭包与模块
闭包定义 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行. 看一段最简单的闭包代码: function foo() { var a = 2; //闭包 fun ...
- rewrite写法
RewriteRule ^/android-special-(\d+).html$ /special/index.php?c=index&a=specialDetail&speid=$ ...
- 1034: [ZJOI2008]泡泡堂BNB
1034: [ZJOI2008]泡泡堂BNB Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3234 Solved: 1655[Submit][St ...
- Problem E
题意:看电视,计算出最多看多少个电视,已给出电视起始终止时间: 解体思路:思路这个题拿到手没多想,上课的例题,就照葫芦画瓢写了一个: 感悟:虽然刚开始学贪心,第一遍代码就AC了有点小小的成就感: 代码 ...