文章推薦系統 | 二、同步業務數據

推薦閱讀:
文章推薦系統 | 一、推薦流程設計

在推薦系統架構中,推薦系統的數據庫和業務系統的數據庫是分離的,這樣才能有效避免推薦系統的數據讀寫、計算等對業務系統的影響,所以同步業務數據往往也是推薦系統要做的第一件事情。通常業務數據是存儲在關系型數據庫中,比如 MySQL,而推薦系統通常需要使用大數據平臺,比如 Hadoop,我們可以利用 Sqoop 將 MySQL 中的業務數據同步到 Hive 中,在我們的文章推薦系統中,需要同步的數據包括:

  • 用戶信息表(user_profile):包括 user_id | gender | birthday | real_name | create_time | update_time | register_media_time | id_number | id_card_front | id_card_back | id_card_handheld | area | company | career 等字段。
  • 用戶基礎信息表(user_basic):包括 user_id | mobile | password | user_name | profile_photo | last_login | is_media | article_count | following_count | fans_count | like_count | read_count | introduction | certificate | is_verified | account | email | status 等字段。
  • 文章信息表(news_article_basic):包括 article_id | user_id | channel_id | title | cover | is_advertising | create_time | status | reviewer_id | review_time | delete_time | comment_count | allow_comment | update_time | reject_reason 等字段。
  • 文章內容表(news_article_content):包括 article_id | content | update_time 等字段。
  • 頻道信息表(news_channel):包括 channel_id | channel_name | create_time | update_time | sequence | is_visible | is_default 等字段。

首先,在 Hive 中創建業務數據庫 toutiao,并創建相關表

create database if not exists toutiao comment "user,news information of mysql" location '/user/hive/warehouse/toutiao.db/';
-- 用戶信息表
create table user_profile
(
    user_id             BIGINT comment "userid",
    gender              BOOLEAN comment "gender",
    birthday            STRING comment "birthday",
    real_name           STRING comment "real_name",
    create_time         STRING comment "create_time",
    update_time         STRING comment "update_time",
    register_media_time STRING comment "register_media_time",
    id_number           STRING comment "id_number",
    id_card_front       STRING comment "id_card_front",
    id_card_back        STRING comment "id_card_back",
    id_card_handheld    STRING comment "id_card_handheld",
    area                STRING comment "area",
    company             STRING comment "company",
    career              STRING comment "career"
)
    COMMENT "toutiao user profile"
    row format delimited fields terminated by ',' # 指定分隔符
    LOCATION '/user/hive/warehouse/toutiao.db/user_profile';
-- 用戶基礎信息表
create table user_basic
(
    user_id         BIGINT comment "user_id",
    mobile          STRING comment "mobile",
    password        STRING comment "password",
    profile_photo   STRING comment "profile_photo",
    last_login      STRING comment "last_login",
    is_media        BOOLEAN comment "is_media",
    article_count   BIGINT comment "article_count",
    following_count BIGINT comment "following_count",
    fans_count      BIGINT comment "fans_count",
    like_count      BIGINT comment "like_count",
    read_count      BIGINT comment "read_count",
    introduction    STRING comment "introduction",
    certificate     STRING comment "certificate",
    is_verified     BOOLEAN comment "is_verified"
)
    COMMENT "toutiao user basic"
    row format delimited fields terminated by ',' # 指定分隔符
    LOCATION '/user/hive/warehouse/toutiao.db/user_basic';
-- 文章基礎信息表
create table news_article_basic
(
    article_id  BIGINT comment "article_id",
    user_id     BIGINT comment "user_id",
    channel_id  BIGINT comment "channel_id",
    title       STRING comment "title",
    status      BIGINT comment "status",
    update_time STRING comment "update_time"
)
    COMMENT "toutiao news_article_basic"
    row format delimited fields terminated by ',' # 指定分隔符
    LOCATION '/user/hive/warehouse/toutiao.db/news_article_basic';
-- 文章頻道表
create table news_channel
(
    channel_id   BIGINT comment "channel_id",
    channel_name STRING comment "channel_name",
    create_time  STRING comment "create_time",
    update_time  STRING comment "update_time",
    sequence     BIGINT comment "sequence",
    is_visible   BOOLEAN comment "is_visible",
    is_default   BOOLEAN comment "is_default"
)
    COMMENT "toutiao news_channel"
    row format delimited fields terminated by ',' # 指定分隔符
    LOCATION '/user/hive/warehouse/toutiao.db/news_channel';
-- 文章內容表
create table news_article_content
(
    article_id BIGINT comment "article_id",
    content    STRING comment "content",
    update_time STRING comment "update_time"
)
    COMMENT "toutiao news_article_content"
    row format delimited fields terminated by ',' # 指定分隔符
    LOCATION '/user/hive/warehouse/toutiao.db/news_article_content';

查看 Sqoop 連接到 MySQL 的數據庫列表

sqoop list-databases --connect jdbc:mysql://192.168.19.137:3306/ --username root -P

mysql
sys
toutiao

Sqoop 可以指定全量導入和增量導入,通常我們可以先執行一次全量導入,將歷史數據全部導入進來,后面再通過定時任務執行增量導入,來保持 MySQL 和 Hive 的數據同步,全量導入不需要提前創建 Hive 表,可以自動創建

array=(user_profile user_basic news_article_basic news_channel news_article_content)

for table_name in ${array[@]};
do
    sqoop import \
        --connect jdbc:mysql://192.168.19.137/toutiao \
        --username root \
        --password password \
        --table $table_name \
        --m 5 \ # 線程數
        --hive-home /root/bigdata/hive \ # hive路徑
        --hive-import \ # 導入形式
        --create-hive-table  \ # 自動創建表
        --hive-drop-import-delims \
        --warehouse-dir /user/hive/warehouse/toutiao.db \ # 導入地址
        --hive-table toutiao.$table_name 
done

增量導入,有 append 和 lastmodified 兩種模式

  • append:通過指定一個遞增的列進行更新,只能追加,不能修改
num=0
declare -A check
check=([user_profile]=user_id [user_basic]=user_id [news_article_basic]=article_id [news_channel]=channel_id [news_article_content]=channel_id)

for k in ${!check[@]}
do
    sqoop import \
        --connect jdbc:mysql://192.168.19.137/toutiao \
        --username root \
        --password password \
        --table $k \
        --m 4 \
        --hive-home /root/bigdata/hive \ # hive路徑
        --hive-import \ # 導入到hive
        --create-hive-table  \ # 自動創建表
        --incremental append \ # 按照id更新
        --check-column ${check[$k]} \ # 指定id列
        --last-value ${num} # 指定最后更新的id
done
  • lastmodified:按照最后修改時間更新,支持追加和修改
time=`date +"%Y-%m-%d" -d "-1day"`
declare -A check
check=([user_profile]=update_time [user_basic]=last_login [news_article_basic]=update_time [news_channel]=update_time)
declare -A merge
merge=([user_profile]=user_id [user_basic]=user_id [news_article_basic]=article_id [news_channel]=channel_id)

for k in ${!check[@]}
do
    sqoop import \
        --connect jdbc:mysql://192.168.19.137/toutiao \
        --username root \
        --password password \
        --table $k \
        --m 4 \
        --target-dir /user/hive/warehouse/toutiao.db/$k \ # hive路徑
        --incremental lastmodified \ # 按照最后修改時間更新
        --check-column ${check[$k]} \ # 指定時間列
        --merge-key ${merge[$k]} \ # 根據指定列合并重復或修改數據
        --last-value ${time} # 指定最后修改時間
done

Sqoop 可以直接導入到 Hive,自動創建 Hive 表,但是 lastmodified 模式不支持
Sqoop 也可以先導入到 HDFS,然后再建立 Hive 表關聯,為了使用 lastmodified 模式,通常使用這種方法

--target-dir /user/hive/warehouse/toutiao.db/user_profile # 指定導入的HDFS目錄

若先導入到 HDFS,需要注意 HDFS 默認分隔符為 , 而 Hive 默認分隔符為 /u0001,所以需要在創建 Hive 表時指定分隔符為 HDFS 分隔符 ,,若不指定分隔符,查詢結果將全部為 NULL

row format delimited fields terminated by ',' # 指定分隔符

如果 MySQL 數據中存在特殊字符,如 , \t \n 都會導致 Hive 讀取失敗(但不影響導入到 HDFS 中),可以利用 --query 參數,在讀取時使用 REPLACE() CHAR() CHR() 進行字符替換。如果特殊字符過多,比如 news_article_content 表,可以選擇全量導入

--query 'select article_id, user_id, channel_id, REPLACE(REPLACE(REPLACE(title, CHAR(13),""),CHAR(10),""), ",", " ") title, status, update_time from news_article_basic WHERE $CONDITIONS' \

如果 MySQL 數據中存在 tinyint 類型,必須在 --connet 中加入 ?tinyInt1isBit=false,防止 Hive 將 tinyint 類型默認轉化為 boolean 類型

--connect jdbc:mysql://192.168.19.137/toutiao?tinyInt1isBit=false

MySQL 與 Hive 對應類型如下

MySQL Hive
bigint bigint
tinyint boolean
int int
double double
bit boolean
varchar string
decimal double
date / timestamp string

我們可以利用 crontab 來創建定時任務,將更新命令寫入腳本 import_incremental.sh,輸入 crontab -e 打開編輯界面,輸入如下內容,即可定時執行數據同步任務

# 每隔半小時增量導入一次
*/30 * * * * /root/toutiao_project/scripts/import_incremental.sh

crontab 命令格式為 * * * * * shell,其中前五個 * 分別代表分鐘 (0-59)、小時(0-59)、月內的某天(1-31)、月(1-12)、周內的某天(0-7,周日為 0 或 7),shell 表示要執行的命令或腳本,使用方法如下

# 每隔5分鐘運行一次backupscript腳本
*/5 * * * * /root/backupscript.sh
# 每天的凌晨1點運行backupscript腳本
0 1 * * * /root/backupscript.sh
# 每月的第一個凌晨3:15運行backupscript腳本
15 3 1 * * /root/backupscript.sh

crontab 常用命令如下

crontab -e      # 修改 crontab 文件,如果文件不存在會自動創建。 
crontab -l      # 顯示 crontab 文件。 
crontab -r      # 刪除 crontab 文件。
crontab -ir     # 刪除 crontab 文件前提醒用戶。

service crond status      # 查看crontab服務狀態
service crond start       # 啟動服務 
service crond stop        # 關閉服務 
service crond restart     # 重啟服務 
service crond reload      # 重新載入配置

參考

https://www.bilibili.com/video/av68356229
https://pan.baidu.com/s/1-uvGJ-mEskjhtaial0Xmgw(學習資源已保存至網盤, 提取碼:eakp)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。