shell+sqoop 实现数据抽取的面向对象设计

工作痛点:离线抽取数据,抽取逻辑变动大,增加表的频率高,更新表字段的频率高。手动需要完成虽然工作量不大,但占用时间长,并且技术含量低,重复劳动。

组件: shell 、 sqoop

主体流程框架

在这里插入图片描述
具体每个模块详细信息如下:

第一模块:数据库连接配置文件详情

样例如下:
jdbc_conf.cfg

[1sqlserver]          --数据库信息代理名
ip=192.168.5.250      --连接地址
port=1433             --连接端口       
username=root         --连接用户名
password=passwordname --连接密码

[2sqlserver]          --数据库信息代理名
ip=192.168.5.251
port=3306
username=root
password=passwordname

第二模块 表配置信息文件详情

(可根据具体情况使用不同的配置文件,例如:数据表配置文件,配置表数据文件,历史数据抽取配置文件等)
样例如下:

[table1]                            --表名称(和shell主程序中需要遍历的表清单名一致)
source_db=master                    --源库名
source_schema=info                  --源模式名
source_tablename=sourcetable1       --源表名
source_jdbc=1sqlserver              --数据库信息代理名
target_tablename=table1             --目标表名
target_db=stage_commDB              --目标库名
insert_type=overwrite               --数据更新方式为覆盖更新
partition=1                         --分区设置为 无分区
separator=|                        --HDFS文本分隔符
hiveFile_type=text                 --数据文件类型
column=id,pid,mid,created_time,updated_time,intime  --sqoop执行抽取时需要抽取的字段
where:1=1                          --sqoop抽取时执行的sql查询语句的where条件

[table2]
source_db=master
source_schema=info
source_tablename=sourcetable2
source_jdbc=1sqlserver
target_tablename=table2
target_db=stage_commDB
insert_type=overwrite
partition=1
separator=\t    --HDFS文本分隔符
hiveFile_type=text
column=REPLACE(id,CHAR(9),'')++as++id,created_time,updated_time,intime --sql语句可自定义(语句对应的是源数据库,sql server等)
where:1=1


[table3]
source_db=master
source_schema=info
source_tablename=sourcetable3
source_jdbc=2sqlserver
target_tablename=table3
target_db=stage_DB
insert_type=append    --数据更新类型为增量更新
partition=etl_month   --分区字段为etl_month  
separator=|
hiveFile_type=parquet  --hdfs文件类型为parquet
column=id,pid,mid,created_time,updated_time,intime   --sql查询的字段筛选
query:select++column++from++MsTableName              --引用上面column的变量替换query中的字符串“column”并使用配置信息拼凑字符串“MsTableName”的代替内容,例如stage_DB.table3
where:CONVERT(varchar(6),datatime,112)=DATATIME      --sqoop抽取时自定义的筛选条件,在shell脚本中替换字符串“DATATIME”为特定的某个时间

第三模块 公共抽象方法模块

public_fun.sh

#!/bin/bash

#################################
# shell 脚本公共服务方法类
# 1.获取jdbc用户名密码
# 2.获取抽取表的配置信息
#################################

jdbc_conf=/home/etl/public/jdbc_conf.cfg 

function getJDBC_conf(){
    
    Section=$1     --传入数据库信息代理名,根据代理名查找相关配置文件内容
    echo `date +"%Y%m%d %H:%M:%S"`"--需要获取 【$Section】 配置文件....."
    echo `date +"%Y%m%d %H:%M:%S"`"--读取配置文件 【$jdbc_conf】"
    #options="ip|username|password"
    #echo `date +"%Y%m%d %H:%M:%S"`$Options|tr '\|' '|'
    ip=`cat $jdbc_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/ip/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
    port=`cat $jdbc_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/port/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
    username=`cat $jdbc_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/username/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
    password=`cat $jdbc_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/password/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
    
    echo `date +"%Y%m%d %H:%M:%S"`"【ip】=$ip,【port】=$port,【username】=$username,【password】=$password"
}

#getJDBC_conf 1sqlserver

function getTable_conf(){
    
  Section=$1    --传入表名称
  table_conf=$2  --传入表名称所在的表信息配置文件cfg的绝对路径
  echo `date +"%Y%m%d %H:%M:%S"`"--需要获取 【$Section】 配置文件....."
  echo `date +"%Y%m%d %H:%M:%S"`"--读取配置文件 【$table_conf】"
  source_db=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_db/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  source_schema=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_schema/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  source_tablename=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_tablename/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2);exit}'`
  source_jdbc=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_jdbc/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  target_tablename=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/target_tablename/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2);exit}'`
  target_db=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/target_db/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  insert_type=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/insert_type/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  partition=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/partition/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  separator=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/separator/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  hiveFile_type=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/hiveFile_type/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  column=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/column/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  where=`cat $table_conf | awk -F ':' '/\['"$Section"'\]/{a=1}a==1&&$1~/where/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`    

  echo `date +"%Y%m%d %H:%M:%S"`"【$Section】"
  echo `date +"%Y%m%d %H:%M:%S"`" 配置详情:$source_db,$source_schema,$source_tablename,$source_jdbc,$target_tablename,$target_db,$insert_type,$partition,$separator,$hiveFile_type"
  echo `date +"%Y%m%d %H:%M:%S"`" 抽取列column=$column" 
  echo `date +"%Y%m%d %H:%M:%S"`" 筛选条件where=$where"
}

function getTable_conf2(){

  Section=$1
  table_conf=$2
  echo `date +"%Y%m%d %H:%M:%S"`"--需要获取 【$Section】 配置文件....."
  echo `date +"%Y%m%d %H:%M:%S"`"--读取配置文件 【$table_conf】"
  source_db=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_db/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  source_schema=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_schema/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  source_tablename=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_tablename/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2);exit}'`
  source_jdbc=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/source_jdbc/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  target_tablename=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/target_tablename/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2);exit}'`
  target_db=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/target_db/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  insert_type=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/insert_type/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  partition=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/partition/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  separator=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/separator/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  hiveFile_type=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/hiveFile_type/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  column=`cat $table_conf | awk -F '=' '/\['"$Section"'\]/{a=1}a==1&&$1~/column/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  where=`cat $table_conf | awk -F ':' '/\['"$Section"'\]/{a=1}a==1&&$1~/where/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  query=`cat $table_conf | awk -F ':' '/\['"$Section"'\]/{a=1}a==1&&$1~/query/{gsub(/[[:blank:]]*/,"",$2);printf("%s",$2) ;exit}'`
  echo `date +"%Y%m%d %H:%M:%S"`"【$Section】"
  echo `date +"%Y%m%d %H:%M:%S"`" 配置详情:$source_db,$source_schema,$source_tablename,$source_jdbc,$target_tablename,$target_db,$insert_type,$partition,$separator,$hiveFile_type"
  echo `date +"%Y%m%d %H:%M:%S"`" 抽取列column=$column"
  query="${query//column/$column}"     --拼接query的sql语句,把column具体内容替换掉
  echo `date +"%Y%m%d %H:%M:%S"`" 执行语句query=$query"
  echo `date +"%Y%m%d %H:%M:%S"`" 筛选条件where=$where"
}

第四模块 sqoop抽取的子shell封装模块

包含: 配置表无分区的全删全插类型,数据表按时间分区增量抽取,数据表parquet格式分区抽取等

类型1,全删全插的类型

sqoop_exp_comm2.0.sh

#!/bin/bash

tablename=$1
cfgfile=$2

#引入公共脚本
source /home/etl/public/public_fun.sh

#获取表配置信息
getTable_conf $tablename $cfgfile

#获取表jdbc信息
getJDBC_conf $source_jdbc

etl_date=`date "-d -1 day" "+%Y%m%d"`


column2="${column//++/ }"
MsTableName="$source_schema.$source_tablename with (nolock)"
echo "$MsTableName"
echo "$column2"
if [ "$column2" == "*" ];then 
   echo "-------------------"
   query="select * from $MsTableName where $where and \$CONDITIONS"
elif [ "$column2" == "DIY" ];then
   getTable_conf2 $tablename $cfgfile
   query="${query//++/ }"
else
   query="select $column2 from $MsTableName where $where and \$CONDITIONS and 1=1"
fi

echo "$query"

echo `date +"%Y%m%d %H:%M:%S"`"全删全插"
sqoop import -D mapred.job.queue.name=root.realtime_queue \
-m 1 \
--connect "jdbc:sqlserver://$ip:$port;database=$source_db;username=$username;password=$password" \
--query "${query}"  \
--target-dir "/user/hive/warehouse/$target_db.db/$target_tablename" \
--delete-target-dir \
--fields-terminated-by "${separator}"  \
--null-string '\\N' --null-non-string '\\N'
类型2,有分区增量更新
#!/bin/bash

tablename=$1
cfgfile=$2
DATATIME=$3
YEAR=$4
MONTH=$5
DAY=$6

#引入公共脚本
source /home/etl/public/public_fun.sh

#获取表配置信息
getTable_conf $tablename $cfgfile

#获取表jdbc信息
getJDBC_conf $source_jdbc

etl_date=`date "-d -1 day" "+%Y%m%d"`

column2="${column//++/ }"
MsTableName=$source_schema.$source_tablename
echo "$MsTableName"
echo "$column2"
if [ "$column2" == "*" ];then 
   echo "-------------------"
   query="select * from $MsTableName where CONVERT(varchar(12) , data_time, 112) = '$DATATIME'  and  \$CONDITIONS and 1=1"
else
   query="select $column2 from $MsTableName where CONVERT(varchar(12) , data_time, 112) = '$DATATIME' and \$CONDITIONS and 1=1"
fi

echo `date +"%Y%m%d %H:%M:%S"`"--加载分区------"
echo `date +"%Y%m%d %H:%M:%S"`"--use '$target_db';alter table '$tablename' add IF NOT EXISTS partition (year='$YEAR',month='$MONTH',day='$DAY');truncate table '$tablename'  partition(year='$YEAR',month='$MONTH',day='$DAY')"

hive -S -e 'use '$target_db';alter table '$tablename' add IF NOT EXISTS partition (year='$YEAR',month='$MONTH',day='$DAY'); truncate table '$tablename'  partition(year='$YEAR',month='$MONTH',day='$DAY' )' 
echo "$query"

sqoop import -D mapred.job.queue.name=root.default \
-m 1 \
--append --connect "jdbc:sqlserver://$ip:$port;database=$source_db;username=$username;password=$password" \
--query "${query}"  \
--target-dir "/user/hive/warehouse/$target_db.db/$target_tablename/year=$YEAR/month=$MONTH/day=$DAY" \
--fields-terminated-by "${separator}"  \
--null-string '\\N' --null-non-string '\\N'
类型3,parquet格式按分区增量抽取
#!/bin/bash

tablename=$1
cfgfile=$2
etl_date=$3

echo "etl_date=$etl_date"

#引入公共脚本
source /home/etl/public/public_fun.sh

#获取表配置信息
getTable_conf $tablename $cfgfile

#获取表jdbc信息
getJDBC_conf $source_jdbc

#etl_date=`date "-d -1 day" "+%Y%m%d"`
echo `date +"%Y%m%d %H:%M:%S"`"数据更新日期 $etl_date"

where="${where//etl_date/$etl_date}"

column2="${column//++/ }"
MsTableName="$source_schema.$source_tablename with (nolock)"
echo "$MsTableName"
echo "$column2"
if [ "$column2" == "*" ];then 
   echo "-------------------"
   query="select * from $MsTableName where $where and \$CONDITIONS"
elif [ "$column2" == "DIY" ];then
   getTable_conf2 $tablename $cfgfile
   query="${query//++/ }"
else
   query="select $column2 from $MsTableName where $where and \$CONDITIONS and 1=1"
fi

echo "$query"

echo `date +"%Y%m%d %H:%M:%S"`"--清空表数据"
echo `date +"%Y%m%d %H:%M:%S"`"--use '$target_db';truncate table '$target_tablename'"

hive -S -e 'use '$target_db';truncate table '$target_tablename'' 

echo `date +"%Y%m%d %H:%M:%S"`"全删全插"
sqoop import -D mapred.job.queue.name=root.default \
-m 1 \
--connect "jdbc:sqlserver://$ip:$port;database=$source_db;username=$username;password=$password" \
--query "${query}"  \
--as-parquetfile \
--target-dir "/user/hive/warehouse/$target_db.db/$target_tablename" \
--delete-target-dir \
--fields-terminated-by "${separator}"  \
--null-string '\\N' --null-non-string '\\N'

第五模块 主程序shell脚本

样例

#!/bin/bash

tablename=table1,table2,table3

publicpath=/home/etl/public
cfgfile=/home/etl/public/zxjk_comm_tableList.cfg

table_array=(${tablename//,/ })

echo -e `date '+%Y-%m-%d %H:%M:%S'` "数据抽取开始"
#循环表清单
 for table in ${table_array[@]}
 do 
     HiveTableName=$table
     echo "sh  $publicpath/sqoop_exp_comm2.0.sh $HiveTableName $cfgfile "
     sh  $publicpath/sqoop_exp_comm2.0.sh $HiveTableName $cfgfile 
     #监控HDFS目录下文件数量
     i=1
     while [ $i -le 10 ]
     do
        echo "判断HDFS文件个数......."
        filenum=`hadoop fs -ls /user/hive/warehouse/stage_comm.db/$HiveTableName |wc -l`
        echo  "文件目录:/user/hive/warehouse/stage_comm.db/$HiveTableName 下,文件个数为:${filenum}"
        if [ $filenum -eq 0 ]; then
            echo "HDFS文件个数异常,重新执行"
            echo "HDFS文件个数异常,开始循环抽取数据,第$i次执行开始,sh $publicpath/sqoop_exp_comm2.0.sh $HiveTableName $cfgfile 卸载数据"
            sh $publicpath/sqoop_exp_comm2.0.sh $HiveTableName $cfgfile
        else
            break
        fi
        let i+=1
     done
  echo -e `date '+%Y-%m-%d %H:%M:%S'` "数据抽取结束======================"    

 done
echo -e `date '+%Y-%m-%d %H:%M:%S'` "--结束"
经过以上的配置后,需要离线抽取表数据,就可以通过配置相应的配置文件,以及数据库连接信息来抽取数据。大大减少了重复型劳动,并且通过不断扩充sqoop抽取的子shell封装模块,就可以不断兼容各类数据抽取模式。换个思路来看,就是使用文件将数据表的相关元数据管理起来,通过封装固定类型的shell脚本实现多模式的数据抽取。那么长远的角度来看,将数据库的连接配置文件和表信息的配置文件可以转化为mysql的数据表,通过关系型数据库来管理元数据,用shell脚本查询mysql获取元数据也可以实现上述功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值