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 从物 ...
随机推荐
- JavaEE 对象的串行化(Serialization)
什么情况下需要序列化 a)当你想把的内存中的对象写入到硬盘的时候:b)当你想用套接字在网络上传送对象的时候:c)当你想通过RMI传输对象的时候:再稍微解释一下:a)比如说你的内存不够用了,那计算机就要 ...
- Node Inspector 代理实现
本文首发于 https://github.com/whxaxes/blog/issues/9 背景 平时做 node 开发的时候,通过 node inspector 来进行断点调试是一个很常用的 de ...
- Developing Universal Windows Apps 开发UWA应用 问答
开始是一些欢迎,就不翻译 Question: Is the code already there? Answer: There is some code on that codeplex site, ...
- .NET采集数据,放入数据库总结
第一次做采集Json的还简单一些但是XML的简直了......... JSON //采集数据 public string GetBetRecordToRepository()//随便你返回什么 { t ...
- swiper使用小结
最近做一个移动端项目想用Swiper移动端插件,需求实现一个轮播图的效果,并且需要自定义分页器,效果跟这个差不多这里demo 好吧,开始动手! 注意参考的3.0Swiper的API文档需要引入3.0版 ...
- PHP垃圾回收机制
一.引用计数基本知识 每个php变量存在一个叫"zval"的变量容器中,当一个变量被赋常量值时,就会生成一个zval变量容器.一个zval变量容器,除了包含变量的类型和值,还包括两 ...
- jdbc链接hive报错:java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransport
写了个jdbc连接hive2的demo,结果报错:java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransport,实际 ...
- 笔记-java泛型详解
首先,先说明一下,java泛型文章的出处:http://www.cnblogs.com/lzq198754/p/5780426.html 作为学习笔记保存. 1.为什么需要泛型 泛型在Java中有很重 ...
- SpringMVC自定义配置消息转换器踩坑总结
问题描述 最近在开发时候碰到一个问题,springmvc页面向后台传数据的时候,通常我是这样处理的,在前台把数据打成一个json,在后台接口中使用@requestbody定义一个对象来接收,但是这次数 ...
- A Very Simple Problem
A Very Simple Problem Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...