大數據【企業級360°全方位用戶畫像】匹配型標籤累計開發

寫在前面: 博主是一名軟件工程系大數據應用開發專業大二的學生,暱稱來源於《愛麗絲夢遊仙境》中的Alice和自己的暱稱。作爲一名互聯網小白,寫博客一方面是爲了記錄自己的學習歷程,一方面是希望能夠幫助到很多和自己一樣處於起步階段的萌新。由於水平有限,博客中難免會有一些錯誤,有紕漏之處懇請各位大佬不吝賜教!個人小站:http://alices.ibilibili.xyz/ , 博客主頁:https://alice.blog.csdn.net/
儘管當前水平可能不及各位大佬,但我還是希望自己能夠做得更好,因爲一天的生活就是一生的縮影。我希望在最美的年華,做最好的自己

        在前面的博客中,博主已經爲大家帶來了關於大數據【用戶畫像】項目匹配型標籤開發的一個步驟流程(👉大數據【企業級360°全方位用戶畫像】匹配型標籤開發)。本篇博客帶來的同樣是匹配型標籤的開發,不同於之前的是,本次標籤開發需要將最終的結果與之前的用戶標籤數據進行合併,而並非是覆寫!

        想知道如何實現的朋友可以點個關注,我們繼續往下看。
在這裏插入圖片描述


匹配型標籤開發

        本次我們開發的仍然是匹配型標籤,以Hbase中用戶表的job字段爲例。我們做一個用戶的job標籤匹配。
在這裏插入圖片描述
        獲悉需求之後,我們在web頁面上通過手動添加的方式,添加了四級標籤 職業,五級標籤 不同的職業名稱。

在這裏插入圖片描述
        添加完畢,我們可以在MySQL數據庫中找到對應的數據信息
在這裏插入圖片描述
        再去查看Hbase表中是否存在job列的數據

scan "tbl_users",{COLUMNS => "detail:job",LIMIT => 5}

在這裏插入圖片描述
        確認了MySQL和Hbase中都有job的數據後,我們就可以愉快地寫代碼了~

在這裏插入圖片描述

書寫代碼

<1>創建一個sparksession

        爲了後面我們好通過觀察控制檯,分析數據的變化過程,我們還可以設置日誌級別,減少程序運行時不必要冗餘信息出現在控制檯。

    // 1. 創建SparkSQL
    //   用於讀取mysql , hbase等數據
    val spark: SparkSession = SparkSession.builder().appName("JobTag").master("local[*]").getOrCreate()
     
    // 設置日誌級別
    spark.sparkContext.setLogLevel("WARN")

<2>連接MySQL

        我們肯定是需要先讀取MySQL中的四級和五級的標籤數據的,這裏我們先進行MySQL數據庫的連接。

// 設置Spark連接MySQL所需要的字段
    var url: String ="jdbc:mysql://bd001:3306/tags_new2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&user=root&password=123456"
    var table: String ="tbl_basic_tag"   //mysql數據表的表名
    var properties:Properties = new Properties

    // 連接MySQL
    val mysqlConn: DataFrame = spark.read.jdbc(url,table,properties)

<3>讀取四級標籤數據

        這一步,我們正式開始讀取MySQL中的四級標籤數據,爲了方便在其他地方調用,這裏我們還創建了一個方法,用於將MySQL中的數據存入Map後又用樣例類進行封裝。

        需要注意的是,在進行DataSet轉換成Map,或者List的時候,需導入隱式轉換,不然程序會報錯

   // 引入隱式轉換
    import  spark.implicits._
    //引入java 和scala相互轉換
    import scala.collection.JavaConverters._
    //引入sparkSQL的內置函數
    import org.apache.spark.sql.functions._

    // 3. 讀取MySQL數據庫的四級標籤
    val fourTagsDS: Dataset[Row] = mysqlConn.select("id","rule").where("id=65")

    val KVMaps: Map[String, String] = fourTagsDS.map(row => {
      // 獲取到rule值
      val RuleValue: String = row.getAs("rule").toString

      // 使用“##”對數據進行切分
      val KVMaps: Array[(String, String)] = RuleValue.split("##").map(kv => {
        val arr: Array[String] = kv.split("=")
        (arr(0), arr(1))
      })
      KVMaps
    }).collectAsList().get(0).toMap

    println(KVMaps)

    var hbaseMeta:HBaseMeta=toHBaseMeta(KVMaps)

        其中樣例類代碼爲

  //將mysql中的四級標籤的rule  封裝成HBaseMeta
  //方便後續使用的時候方便調用
  def toHBaseMeta(KVMap: Map[String, String]): HBaseMeta = {
    //開始封裝
    HBaseMeta(KVMap.getOrElse("inType",""),
      KVMap.getOrElse(HBaseMeta.ZKHOSTS,""),
      KVMap.getOrElse(HBaseMeta.ZKPORT,""),
      KVMap.getOrElse(HBaseMeta.HBASETABLE,""),
      KVMap.getOrElse(HBaseMeta.FAMILY,""),
      KVMap.getOrElse(HBaseMeta.SELECTFIELDS,""),
      KVMap.getOrElse(HBaseMeta.ROWKEY,"")
    )
  }

<4> 讀取五級標籤數據

        這一步,我們通過手動添加的標籤值對應的pid,將該標籤下的5級標籤全部獲取。並將返回的每條數據封裝成樣例類,所有結果保存在了一個List中。

    //4. 讀取mysql數據庫的五級標籤
    // 匹配職業
    val fiveTagsDS: Dataset[Row] = mysqlConn.select("id","rule").where("pid=65")

    // 將FiveTagsDS  封裝成樣例類TagRule

    val fiveTageList: List[TagRule] = fiveTagsDS.map(row => {
      // row 是一條數據
      // 獲取出id 和 rule
      val id: Int = row.getAs("id").toString.toInt
      val rule: String = row.getAs("rule").toString

      // 封裝樣例類
      TagRule(id,rule)
    }).collectAsList()   // 將DataSet轉換成util.List[TagRule]   這個類型遍歷時無法獲取id,rule數據
      .asScala.toList    // 將util.List轉換成list   需要隱式轉換    import scala.collection.JavaConverters._

        for(a<- fiveTageList){
           println(a.id+"      "+a.rule)
        }

<5> 讀取Hbase中的數據

        基於第三步我們讀取的四級標籤的數據,我們可以通過配置信息從Hbase中讀取數據,只不過跟之前一樣,爲了加快讀取Hbase的時間,我們將其作爲一個數據源來讀取,而並非傳統的客戶端進行讀取。

      // 讀取hbase中的數據,這裏將hbase作爲數據源進行讀取
    val hbaseDatas: DataFrame = spark.read.format("com.czxy.tools.HBaseDataSource")
      // hbaseMeta.zkHosts 就是 192.168.10.20  和 下面是兩種不同的寫法
      .option("zkHosts",hbaseMeta.zkHosts)
      .option(HBaseMeta.ZKPORT, hbaseMeta.zkPort)
      .option(HBaseMeta.HBASETABLE, hbaseMeta.hbaseTable)
      .option(HBaseMeta.FAMILY, hbaseMeta.family)
      .option(HBaseMeta.SELECTFIELDS, hbaseMeta.selectFields)
      .load()

    // 展示一些數據
    hbaseDatas.show(5)

    //| id|job|
    //+---+---+
    //|  1|  3|
    //| 10|  5|
    //|100|  3|
    //|101|  1|
    //|102|  1|
    //+---+---+

<6> 標籤匹配

        這一步我們需要根據hbase數據和五級標籤的數據進行標籤匹配。

        需要注意的是,匹配的時候需要使用到udf函數。

 // 需要自定義UDF函數
    val getUserTags: UserDefinedFunction = udf((rule: String) => {

      // 設置標籤的默認值
      var tagId: Int = 0
      // 遍歷每一個五級標籤的rule
      for (tagRule <- fiveTageList) {

        if (tagRule.rule == rule) {
          tagId = tagRule.id
        }
      }
      tagId
    })

    // 6、使用五級標籤與Hbase的數據進行匹配獲取標籤
    val jobNewTags : DataFrame = hbaseDatas.select('id.as ("userId"),getUserTags('job).as("tagsId"))
    jobNewTags.show(5)

    //+------+------+
    //|userId|tagsId|
    //+------+------+
    //|     1|    68|
    //|    10|    70|
    //|   100|    68|
    //|   101|    66|
    //|   102|    66|
    //+------+------+

<7>讀取hbase中歷史數據,與新數據合併

        從這一步開始,真正與之前匹配完就完事的程序不同。我們需要將Hbase中的歷史數據讀取出來,與新計算的指標進行一個join合併。

        其中也需要編寫udf對標籤進行拼接,並對拼接後的數據進行去重處理。

    /*  定義一個udf,用於處理舊數據和新數據中的數據 */
    val getAllTages: UserDefinedFunction = udf((genderOldDatas: String, jobNewTags: String) => {

      if (genderOldDatas == "") {
        jobNewTags
      } else if (jobNewTags == "") {
        genderOldDatas
      } else if (genderOldDatas == "" && jobNewTags == "") {
        ""
      } else {
        val alltages: String = genderOldDatas + "," + jobNewTags  //可能會出現 83,94,94
        // 對重複數據去重
        alltages.split(",").distinct // 83 94
        // 使用逗號分隔,返回字符串類型
          .mkString(",") // 83,84
      }
    })


    // 7、解決數據覆蓋的問題
    // 讀取test,追加標籤後覆蓋寫入
    // 標籤去重


    val genderOldDatas: DataFrame = spark.read.format("com.czxy.tools.HBaseDataSource")
      // hbaseMeta.zkHosts 就是 192.168.10.20  和 下面是兩種不同的寫法
      .option("zkHosts","192.168.10.20")
      .option(HBaseMeta.ZKPORT, "2181")
      .option(HBaseMeta.HBASETABLE, "test")
      .option(HBaseMeta.FAMILY, "detail")
      .option(HBaseMeta.SELECTFIELDS, "userId,tagsId")
      .load()

    genderOldDatas.show(5)
   //+------+------+
    //|userId|tagsId|
    //+------+------+
    //|     1|  6,68|
    //|    10|  6,70|
    //|   100|  6,68|
    //|   101|  5,66|
    //|   102|  6,66|
    //+------+------+

    // 新表和舊錶進行join
    val joinTags: DataFrame = genderOldDatas.join(jobNewTags, genderOldDatas("userId") === jobNewTags("userId"))

    val allTags: DataFrame = joinTags.select(
      // 處理第一個字段
      when((genderOldDatas.col("userId").isNotNull), (genderOldDatas.col("userId")))
        .when((jobNewTags.col("userId").isNotNull), (jobNewTags.col("userId")))
        .as("userId"),

      getAllTages(genderOldDatas.col("tagsId"), jobNewTags.col("tagsId")).as("tagsId")
    )

    allTags.show()
    //+------+------+
    //|userId|tagsId|
    //+------+------+
    //|   296|  5,71|
    //|   467|  6,71|
    //|   675|  6,68|
    //|   691|  5,66|
    //|   829|  5,70|

<8>將最終結果寫入到Hbase(數據覆蓋)

        經過第七步數據的合併之後,我們只需將最終的結果寫入到Hbase中即可。

// 將最終結果進行覆蓋
    allTags.write.format("com.czxy.tools.HBaseDataSource")
      .option("zkHosts", hbaseMeta.zkHosts)
      .option(HBaseMeta.ZKPORT, hbaseMeta.zkPort)
      .option(HBaseMeta.HBASETABLE,"test")
      .option(HBaseMeta.FAMILY, "detail")
      .option(HBaseMeta.SELECTFIELDS, "userId,tagsId")
      .save()

        這個時候我們再去查詢Hbase中test表的數據。

        scan "test",{LIMIT => 5}

在這裏插入圖片描述
        當發現每個用戶都有了兩個標籤值時(ps:一個是上一篇文章開發的性別標籤,另一個是我們本篇開發的工作標籤),就說明我們標籤的累計開發就成功了。

過程小結

1、爲讀取hbase,mysql數據,創建一個sparksession,設置appname,master
2、鏈接mysql數據庫,設置url,tablename, properties
3、讀取四級標籤數據
        a)通過ID讀取四級數據的rule。(ID是固定死的)
        b)創建四級標籤時不要直接指定jar文件名和參數等。創建完四級標籤後,開發代碼後,再在四級標籤中添加jar文件信息。
        c)將讀取的字符串類型數據封裝成樣例類,以便於後續使用
                i.將字符串先按照##切分數據,再按照=切分數據
                ii.將切分後的數據封裝成Map
                iii.最後將Map封裝成樣例類
4、讀取五級標籤數據
        a)讀物數據中pid=XXX的數據,查詢出ID和rule
        b)將id 和rule封裝成樣例類
        c)最終返回List內部爲樣例類
5、基於第三步讀取的hbase表、列族、字段。到相應的表中讀取字段
6、根據hbase數據和五級標籤的數據進行標籤匹配
        a)匹配時使用udf函數進行匹配
7、讀取hbase中歷史數據到程序中
        a)將歷史數據和新計算出來的指標進行join.
        b)獲取join後的用戶ID和用戶標籤,編寫UDF將標籤進行拼接
        c)拼接後的數據需要進行去重
8、將最終拼接後的數據寫入hbase(數據的覆蓋)

小結

        本篇博客主要在前一篇的基礎上,爲大家帶來了如何在已有標籤的情況下進行累計開發。即將原有數據和新數據進行合併,並重寫的技巧。

        如果以上過程中出現了任何的紕漏錯誤,煩請大佬們指正😅

        受益的朋友或對大數據技術感興趣的夥伴記得點贊關注支持一波🙏

        希望我們都能在學習的道路上越走越遠😉
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章