【用户行为归因分析项目】- 【企业级项目开发第四站】模拟三类用户行为数据上传到Hadoop

gitee代码仓地址:DataWareHouse: UserBehaviorAttributionAnalysis​​​​​​

一、主方法-应用起点

ProductionOdsDataToHdfs

功能:

读取hive表中的设备信息和应用信息,从全量的设备id和应用id中随机获取

作为用户行为数据的关键信息,然后根据获取到的应用信息和设备信息生成三类用户行为数据并生成文件上传到hdfs中

主要调用功能实现类ProductOdsData

Scala 复制代码
package com.dw.application

import com.dw.service.ProductOdsData

object ProductionOdsDataToHdfs {
  //生产数据
  //五类数据需要生产,其中安装激活卸载数据是每日生产,应用信息和设备信息,在本次项目中设计为不更新


  private val productOdsData = new ProductOdsData

  def main(args: Array[String]): Unit = {

    //获取dim_device_info中的device_id,获取dim_app_info中的app_id,模拟用户行为数据
    val cnt = 180
    val deviceIds: Seq[String] = productOdsData.getDeviceId(cnt)
    val appIds: Seq[String] = productOdsData.getAppId
    //安装数据
    println("####################安装数据准备##########################")
    productOdsData.userInstallData(deviceIds, appIds, cnt)
    //激活数据
    println("####################激活数据准备##########################")

    productOdsData.userActivateData(deviceIds, appIds, cnt)
    //卸载
    println("####################卸载数据准备##########################")

    productOdsData.userUninstallData(deviceIds, appIds, cnt)
  }
}

二、功能实现类ProductOdsData

包含方法:

getDeviceId :从hive表获取所有的设备id

getAppId:从hive表获取所有的应用id

userInstallData :获取安装的配置数据,再调用dataToFile生成用户安装行为数据

userActivateData 获取激活的配置数据,再调用dataToFile生成用户激活行为数据

userUninstallData 获取卸载的配置数据,再调用dataToFile生成用户卸载行为数据

dataToFile 根据输入的设备id和应用id,分别生成三种用户数据,并生成文件上传到hdfs的row层下的对应目录

Scala 复制代码
package com.dw.service

import com.dw.common.utils.ConfigUtil
import com.dw.dao.{HdfsFileWriter, HiveSqlExecute}
import com.dw.util.DateUtils

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import scala.collection.mutable.ArrayBuffer
import scala.util.Random

class ProductOdsData {

//  private val dwdHiveTableName = ConfigUtil.getHiveTableName.getConfig("dwd")
//  private val dwsHiveTableName = ConfigUtil.getHiveTableName.getConfig("dws")
//  private val adsHiveTableName = ConfigUtil.getMysqlTableName.getConfig("ads")
  //加载相关hive表明和hdfs路径名
  private val dimHiveTableName = ConfigUtil.getHiveTableName.getConfig("dim")
  private val odsFilePath = ConfigUtil.getHdfsFilePath.getConfig("hdfs_file_path")
  private val odsFilePrefix = ConfigUtil.getHdfsFilePath.getConfig("hdfs_file_Prefix")

  private val hiveSqlExecute = new HiveSqlExecute
  private val dateRadom = new DateUtils
  private val hdfsFileWriter = new HdfsFileWriter

  /**
   * 获取备id
   *
   * @param dataCnt 需要获取的id数,默认0
   * @return Seq[String]
   */
  def getDeviceId(dataCnt: Int = 0): Seq[String] = {
    val TABLE_NAME = dimHiveTableName.getString("dim_device_info")
    hiveSqlExecute.selectOpt(s"select device_id from ${TABLE_NAME} limit ${dataCnt}").map(
      rows => rows("device_id")
    )
  }

  /**
   * 获取全部的应用id
   *
   * @return Seq[String]
   */
  def getAppId: Seq[String] = {
    val TABLE_NAME = dimHiveTableName.getString("dim_app_info")
    hiveSqlExecute.selectOpt(s"select app_id from ${TABLE_NAME}").map(
      rows => rows("app_id")
    )
  }

  /**
   * 生成用户安装行为信息数据,并生成文件,上传到hdfs上的row层
   *
   * @param deviceIds 获取到的设备id序列
   * @param appIds    获取到的引用id序列
   * @param cnt       需要生成的数据条数
   * @return Seq[String]
   */
  def userInstallData(deviceIds: Seq[String], appIds: Seq[String], cnt: Int): Unit = {
    // 1. 前置校验(避免空值/非法参数)
    if (deviceIds.isEmpty || appIds.isEmpty) {
      throw new IllegalArgumentException("deviceIds和appIds不能为空!")
    }
    val filePath = odsFilePath.getString("user_install_path")
    val filePrefix = odsFilePrefix.getString("user_install_file_Prefix")

    dataToFile(deviceIds, appIds, cnt, filePath, filePrefix)
  }

  /**
   * 生成用户激活行为信息数据,并生成文件,上传到hdfs上的row层
   *
   * @param deviceIds 获取到的设备id序列
   * @param appIds    获取到的引用id序列
   * @param cnt       需要生成的数据条数
   * @return Seq[String]
   */
  def userActivateData(deviceIds: Seq[String], appIds: Seq[String], cnt: Int): Unit = {
    // 1. 前置校验(避免空值/非法参数)
    if (deviceIds.isEmpty || appIds.isEmpty) {
      throw new IllegalArgumentException("deviceIds和appIds不能为空!")
    }
    val filePath = odsFilePath.getString("user_activate_path")
    val datePrefix = odsFilePrefix.getString("user_activate_file_Prefix")
    dataToFile(deviceIds, appIds, cnt, filePath, datePrefix)
  }

  /**
   * 生成用户卸载行为信息数据,并生成文件,上传到hdfs上的row层
   *
   * @param deviceIds 获取到的设备id序列
   * @param appIds    获取到的引用id序列
   * @param cnt       需要生成的数据条数
   * @return Seq[String]
   */
  def userUninstallData(deviceIds: Seq[String], appIds: Seq[String], cnt: Int): Unit = {
    // 1. 前置校验(避免空值/非法参数)
    if (deviceIds.isEmpty || appIds.isEmpty) {
      throw new IllegalArgumentException("deviceIds和appIds不能为空!")
    }
    val filePath = odsFilePath.getString("user_uninstall_path")
    val datePrefix = odsFilePrefix.getString("user_uninstall_file_Prefix")
    dataToFile(deviceIds, appIds, cnt, filePath, datePrefix)
  }

  /**
   * 将生成的数据加载成文件,文件命名为ODS_USER_INSTALL_20251231.000
   * 按照每天数据生成的日期作为文件名一部分
   * 每一百条数据为一个文件,文件序号递增,三位数不足前面补0
   *
   * @param deviceIds  获取到的设备id序列
   * @param appIds     获取到的引用id序列
   * @param cnt        需要生成的数据条数
   * @param filePath   hdfs上对应业务的row层目录
   * @param filePrefix 需要上传的文件前缀(eg:ODS_USER_INSTALL_20251231)
   * @return Seq[String]
   */
  private def dataToFile(deviceIds: Seq[String], appIds: Seq[String], cnt: Int, filePath: String, filePrefix: String): Unit = {
    val today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
    val datePrefix = filePrefix + today
    //检查目录是否存在
    if (hdfsFileWriter.existsHdfsDir(filePath)) {
      if (hdfsFileWriter.createHdfsDir(filePath + "/" + today)) { //创建今天的目录,如果存在就不会再次创建了
        var currentGroup = ArrayBuffer[List[String]]() // 存储当前分组的100条数据
        (1 to cnt).foreach(i => {
          val groupNum = (i - 1) / 100
          val fileNameSuffix = f"$groupNum%03d" //文件名后缀000-999
          val fullFileName = s"${datePrefix}.${fileNameSuffix}"
          if (filePrefix == odsFilePrefix.getString("user_install_file_Prefix")) {
            currentGroup += List(
              deviceIds(Random.nextInt(deviceIds.length)), //随机获取一个设备id
              appIds(Random.nextInt(appIds.length)), //随机获取一个应用id
              dateRadom.getSpecifiedDayInLastYear(), //数据加载时间,一天前的任意时间,格式: yyyy-MM-dd HH:mm:ss
              fullFileName //文件名
            )
          } else {
            currentGroup += List(
              deviceIds(Random.nextInt(deviceIds.length)), //随机获取一个设备id
              appIds(Random.nextInt(appIds.length)), //随机获取一个应用id
              appIds(Random.nextInt(appIds.length)), //随机获取一个应用id,安装数据多一个安装来源渠道
              dateRadom.getSpecifiedDayInLastYear(), //数据加载时间,一天前的任意时间,格式: yyyy-MM-dd HH:mm:ss
              fullFileName //文件名
            )
          }
          //若当前分组满100条则封组,重置当前分组
          if (currentGroup.size == 100 || i == cnt) { // 满100条 或 到最后一条时封组
            hdfsFileWriter.writeToCsvFile(currentGroup.toList, fullFileName, "|") //生成文件
            currentGroup = ArrayBuffer.empty // 重置当前分组
          }
        }
        )
      }
      hdfsFileWriter.putBatchFiles(datePrefix, filePath)
    }
  }

}

至此我们项目架构中的数据生产层已经完成

三、功能验证

1、DIM层设备、应用数据验证

通过日志验证

通过结果验证

2、用户行为数据验证

报错

hdfs建目录

通过日志验证

通过结果验证

相关推荐
LDG_AGI5 分钟前
【推荐系统】深度学习训练框架(二十三):TorchRec端到端超大规模模型分布式训练+推理实战
人工智能·分布式·深度学习·机器学习·数据挖掘·推荐算法
羊小猪~~9 分钟前
数据库学习笔记(十八)--事务
数据库·笔记·后端·sql·学习·mysql
会编程的李较瘦14 分钟前
【期末考试总结】spark课程知识点
大数据·单例模式·spark
Code Slacker14 分钟前
第八届传智杯AI云计算大数据开发挑战赛练习题库(三)
大数据·人工智能·云计算·竞赛
无代码专家15 分钟前
无代码驱动行业数字化转型:从痛点突破到效能重构
大数据·低代码·制造
清晓粼溪20 分钟前
SpringCloud-05-Micrometer Tracing+ZipKin分布式链路追踪
分布式·spring·spring cloud
独自破碎E21 分钟前
聊聊RabbitMQ
分布式·rabbitmq
小股虫24 分钟前
缓存攻防战:在增长中台设计一套高效且安全的缓存体系
java·分布式·安全·缓存·微服务·架构
拓端研究室30 分钟前
2025医疗人工智能报告:AI应用、IVD市场、健康科技|附240+份报告PDF、数据、可视化模板汇总下载
大数据·人工智能·物联网
天远数科35 分钟前
Node.js全栈开发:深度集成天远贷前风险报告接口打造风控中台
大数据·node.js