运营系统分析平台技术设计:

  1. 项目定义于运营系统关键指标的数据分析
  2. 关键代码描述:
    1. 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

    2. 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

    3. 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)
      }
      }
    4. 程序串联 : 
      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()

      串联程序

  3. 关键技术细节:
    1. SQL字符串表达式建议如下:s"""sql""".stripMargin,更整洁更好维护复杂的SQL
    2. 涉及到时间计算,预先unix_timestamp(observe_end_time) 在SQL中转化成时间戳,在map算子中只做最简单的判断计算
    3. 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")
      }
    4. 定义结构体: {} 里面能写复杂代码定义产出结果,适用于一句话搞不定返回值的情况
    5. ROW_NUMBER()函数,常用案例包括 
      1.   取出每种rate下score最大的两条记录
      2.   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
    1. sql cast功能: cast(order_id AS string) order_id, spark.sql实现: df.select(df("colA").cast("int"))
    2. sql nvl功能 : nvl(t1.a_create_time,'1971-01-01 00:00:00') AS create_time

    3. spark select Seq() : selectExpr(Seq(): _*)
    4. import org.apache.spark.sql.functions  定义spark中用Scala实现的各种SQL常用算子
    5. withColumn("is_complete",functions.lit(0))  使用常数类型构造一个新的column,withColumn("testkey", concat($"apollo_exp_id", lit(":0:"), $"apollo_group_id"))
    6. df("colA") =!= df("colB")   column不等于算子
    7. 添加UDF函数 val genCarpool = spark.udf.register("genCarpool", func), 使用ds.withColumn("ds_carpool", genCarpool(ds("raw_ct")))
    8. import org.apache.spark.sql.functions._ 之后就能使用   from_unixtime(Colunm) 函数了。
    9. import spark.implicits._   牛逼的隐式转换把Scala类型 转化为  DF的类型,包括能使用df.select($"sss")
    10. functions.explode : spark中集合类打平函数,会把一个集合中的多个元素打平成多个Row
    11. df.drop  删除指定的column
    12. functions.when : functions.when(resPre("new_carpool").contains(resPre("ds_carpool")) and ???,1).otherwise(0), 关键技巧先转换成String(1,2,3,4) 再判断contains基本值
    13. coalesce(10) 在结果DF之后加上控制写hive表最合适的part个数
    14. package object activity 包对象更好适合常量场景
    15. <: 继承关系,[T <: Conf]
    16. DF启用别名: activeMarketingActDF.alias("a").join(odsGCouponRuleInfoDF.alias("b"), $"a.info_id" === $"b.id").selectExpr("a.id")

    17. flatMap函数: 当map中返回的是 LIST 会把结果打平
    18. selectExpr表达式: ds.selectExpr("colA", "colB as newName", "abs(colC)")
    19. 多个列中最大,最小值: greatest(exprs: Column*)  跳过null least(exprs: Column*) 跳过null 取最小的值
    20. 其他有效函数

      1. between
      2. isNaN
      3. isNull
    21. sparkGC太多可以优化点如下

      1. 调大task个数,更快GC,减少长时间GC时间拖慢整个进程。优化参数如下
        1. --conf spark.dynamicAllocation.maxExecutors=1000 \
          --conf spark.executor.cores=4 \

      2. 调大执行器的年轻代大小: --conf "spark.executor.extraJavaOptions=-XX:NewSize=2048m"
    22. 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.   解决手段:
      1. --conf spark.executor.memory=12g
      2. repartition 设置大点
      3. --conf  spark.shuffle.spill.numElementsForceSpillThreshold=1500000 ,内存中row的数量超过这个值,不再放到内存直接写磁盘

osap一站式分析模型的更多相关文章

  1. Moebius集群:SQL Server一站式数据平台

    一.Moebius集群的架构及原理 1.无共享磁盘架构 Moebius集群采用无共享磁盘架构设计,各个机器可以不连接一个共享的设备,数据可以存储在每个机器自己的存储介质中.这样每个机器就不需要硬件上的 ...

  2. 层次分析模型(AHP)及其MATLAB实现

    今天用将近一天的时间学习了层次分析模型(AHP),主要参考了一份pdf,这个网站,和暨南大学章老师的课件,现写出一些自己总结的要点. 一.层次分析法的基本步骤: 角度一: 实际问题——分解——> ...

  3. 【OpenCV入门教程之三】 图像的载入,显示和输出 一站式完全解析(转)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/20537737 作者:毛星云(浅墨)  ...

  4. 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发

    掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...

  5. 一站式Hadoop&Spark云计算分布式大数据和Android&HTML5移动互联网解决方案课程(Hadoop、Spark、Android、HTML5)V2的第一门课程

    Hadoop是云计算的事实标准软件框架,是云计算理念.机制和商业化的具体实现,是整个云计算技术学习中公认的核心和最具有价值内容. 如何从企业级开发实战的角度开始,在实际企业级动手操作中深入浅出并循序渐 ...

  6. 一站式远程页面调试工具spy-debugger 2.0,已支持HTTPS

    项目名称: spy-debugger 项目地址:https://github.com/wuchangming/spy-debugger 关于spy-debugger npm Build Status ...

  7. Liunx+C编程一站式学习

    Liunx+C编程一站式学习这本书有什么特点?面向什么样的读者?这本书最初是为某培训班的嵌入式系统Linux工程师就业班课程量身定做的教材之一.该课程是为期四个月的全日制职业培训,要求学员毕业时具备非 ...

  8. 老司机带你用vagrant打造一站式python开发测试环境

      前言 作为一个学习和使用Python的老司机,好像应该经常总结一点东西的,让新司机尽快上路,少走弯路,然后大家一起愉快的玩耍. 今天,咱们就使用vagrant配合xshell打造一站式Python ...

  9. 为智能硬件提供一站式解决方案——机智云GoKit评测

    为智能硬件提供一站式解决方案——机智云GoKit评测 2014年12月24日 作者: ladouyu 3 17,414+ 4 EMW3162GoKit开发板STM32F103智能硬件机智云2.0 从物 ...

随机推荐

  1. 我的第一个python web开发框架(7)——本地部署前端访问服务器

    PS:本系列内容进度节奏会放的很慢,每次知识点都尽量少一点,这样大家接触的知识点少了,会更容易理解,因为少即是多.另外,对于后面代码部分,虽然尽量不用那些复杂的封装和类,但它并不表示看了就能全部记住, ...

  2. WPF 如何画出1像素的线

    如何有人告诉你,请你画出1像素的线,是不是觉得很简单,实际上在 WPF 上还是比较难的. 本文告诉大家,如何让画出的线不模糊 画出线的第一个方法,创建一个 Canvas ,添加一个线 界面代码 < ...

  3. WordCount项目

    采用的源码来自http://blog.csdn.net/lnz001/article/details/54851551 经修改后,已上传至GitHub.https://github.com/FengX ...

  4. PHP入门,clone和__clone

      前 言 这篇文章主要介绍了PHP编程中的__clone()方法使用详解,__clone()方法相当于一个浅拷贝,是PHP入门学习中的基础知识,需要的朋友可以参考下. 1对象是引用数据类型,当使用= ...

  5. HDU 2665 Kth number(划分树)

    Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...

  6. Linux必知必会的目录与启动过程

    第1章 /etc/目录 1.1 /etc/sysconfig/network-scripts/ifcfg-eth0 linux第一块网卡的配置文件 [root@znix ~]# cat /etc/sy ...

  7. android+eclipse+mysql+servlet(Android与mysql建立链接)

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原创地址  .作者信息和本声明.http://www.cnblogs.com/zhu520/p/7724524.html 经过两天的时间我终于把A ...

  8. React + Node 单页应用「二」OAuth 2.0 授权认证 & GitHub 授权实践

    关于项目 项目地址 预览地址 记录最近做的一个 demo,前端使用 React,用 React Router 实现前端路由,Koa 2 搭建 API Server, 最后通过 Nginx 做请求转发. ...

  9. 在微信端使用video标签,播放结束会出现QQ浏览器推荐视频的解决办法(vue)

    会出现播放结束显示QQ浏览器推荐视频的原因:(我是vue的项目,而且我是新手,只是单纯的给大家分享一个方法,代码比较low请自动忽略) 因为在x5(QQ浏览器)内核中,把video标签劫持了,只要是检 ...

  10. 学Java的前景与就业,资深程序员教你怎么开始学Java!

    IT行业一直是就业的热门岗位,程序员这个职业稳定性和收入比都有着不错的前景,那么学Java的前景和就业是什么样的呢?随着入行Java的准程序员越来越多,各种学习Java的流派也层出不穷!其实在编程的世 ...