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 从物 ...
随机推荐
- WPF DataGrid复制单元格问题
当复制出现 以下错误时:System.Runtime.InteropServices.COMException (0x800401D0),这是在WPF剪贴板程序错误. 解决方法:则在需要在App.xa ...
- Visual studio 创建项目失败vstemplate
Visual studio 创建项目失败 提示 the vstemplate file references the wizard class 'Microsoft.VisualStudio.WinR ...
- 关于scanf 与 cin gets(),getline()......输入输出字符串的区别
很对人对于字符串的输入输出一直是比较模糊的,今天总结一下几个常用的输入流符号对于输入字符串时的区别: 1.scanf(),首先 它遇到空格或回车键(\n)就会结束,并且会将回车符算入字符串中: 2.c ...
- RabbitMQ 笔记-基本概念
ConnectionFactory.Connection.Channel ConnectionFactory.Connection.Channel,这三个都是RabbitMQ对外提供的API中最基本的 ...
- 【ASP.NET MVC 学习笔记】- 03 Razor语法
本文参考:http://www.cnblogs.com/willick/p/3224144.html 1.Razor语句以@开头. 2.每个View都有自己的Model属性,可通过@Model调用.语 ...
- JAVA基础知识总结:九
二.面向对象特性之继承 1.什么是继承? 如果两个或者两个以上的类具有相同的属性和方法,我们可以抽取一个类出来,在抽取出来的类中声明各个类中公共的部分 被抽取出来的类-------父类,基类,超类 两 ...
- MongoDB固定集合(Capped Collections)
MongoDB 固定集合(Capped Collections)是性能出色且有着固定大小的集合,对于大小固定,我们可以想象其就像一个环形队列,当集合空间用完后,再插入的元素就会覆盖最初始的头部的元素! ...
- javascript编写一个简单的编译器(理解抽象语法树AST)
javascript编写一个简单的编译器(理解抽象语法树AST) 编译器 是一种接收一段代码,然后把它转成一些其他一种机制.我们现在来做一个在一张纸上画出一条线,那么我们画出一条线需要定义的条件如下: ...
- Java多线程高并发学习笔记——阻塞队列
在探讨可重入锁之后,接下来学习阻塞队列,这边篇文章也是断断续续的写了很久,因为最近开始学ssm框架,准备做一个自己的小网站,后续可能更新自己写网站的技术分享. 请尊重作者劳动成果,转载请标明原文链接: ...
- 关于01背包求第k优解
引用:http://szy961124.blog.163.com/blog/static/132346674201092775320970/ 求次优解.第K优解 对于求次优解.第K优解类的问题,如果相 ...