推薦閱讀:
文章推薦系統 | 一、推薦流程設計
在推薦系統架構中,推薦系統的數據庫和業務系統的數據庫是分離的,這樣才能有效避免推薦系統的數據讀寫、計算等對業務系統的影響,所以同步業務數據往往也是推薦系統要做的第一件事情。通常業務數據是存儲在關系型數據庫中,比如 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)