您的位置:首页 > 运维架构

利用sqoop从数据源获取数据到hive的流程化

2015-05-11 18:35 309 查看
  在流程化中,我不太清楚其他朋友是怎么做的,这里参考我司的数据仓库的调度逻辑将sqoop脚本放到shell里执行,最终结果能基本解决后期日常维护、代码重用的需求;注意这里只讨论从数据源获取数据到hive而不包括在hive中对数据的处理脚本,但是是值得参考的

目标

 根据需要每天从业务库导入前一天的数据,在hive中生成一个日表,格式与数据源保持一致即可,比如今天2015年5月11日,那么我们将在凌晨从数据源中获取的2015年5月10日的数据;这里hive当做一个数据仓库来使用,先将数据原封不动的抽取过来,相当于三层结构中的ods层。

测试环境

数据源:MS sqlserver 2012
hadoop-2.5.0  hive-0.13  sqoop-1.4.5
对应的数据库为fengmingdw


1、数据源的配置文件  

  关于配置文件的存在是为了将所用相关的属性整合到同一个文件,每一个需要对应属性的脚本,只要到里面去读就可以了;在设计过程中这里提供了两种方法,方法一可以参考一下,建议直接方法二

方法一,自定义配置文件

配置文件格式可以自选,包括诸如xml、ini等等,考虑到shell实现的困难,这里选取最简单的
形如xxx=aaaa ,这是linux中通用的配置文件方式


#文件命名为datawarehouse
ip=192.168.73.12   #注意等号两边不要有空格
username=testUser
passwd=123456
dbname=fdw
connectURL="jdbc:sqlserver://`echo $ip`;DatabaseName=`echo $dbname`"


读取该文件的方法参考如下

function load_config()
{
filePath="/home/9003547/datasource.d/`echo $1`" #这是我存放的配置文件路径
echo $filePath
if [ -f "$filePath" ]; then
. $filePath
fi
}
load_config datawarehouse  #传入配置文件名称
echo $ip                   #读取的参数
echo $connectURL


在对应的脚本中加入此代码就可以获取到ip、connectURL等配置在datawarehouse中的值

方法二,options-file参数

sqoop中提供了一个选项 --options-file,允许sqoop去读取一段文件内的脚本
这里提供一个文件,路径为 /home/9003547/sqooppath/fdw.txt,该文件内容如下


import
--connect
jdbc:sqlserver://192.168.73.12:1433;DatabaseName=fdw
--username
testUser
--password
123456


在sqoop中可以使用类似语句就可以重复引用文件fdw.txt中的信息

sqoop --options-file /home/9003547/sqooppath/fdw.txt \
--table myTestTable \
--xxxxxx #后面补充相应的参数


  这种情况,对于大量的数据来源库可能需要自己维护,十几二十可以用,但是更多的就可能有点乏力了,事实上不管有多少数据源都建议给予一个良好的命名规范,至少能要让使用者能够看命名就知道内容

shell中的sqoop与hive脚本

  在这里做简单的设置,包括传入一个日期参数作为表名、将hive中存在的表名给删除、sqoop抽取表数据

日期参数的设置

  因为是每天一个表存放数据,所以采取的方式是表名+日期,这里设置日期参数

#定义时间,允许传入一个时间,如果未传递则默认当前日期的前一天
if [ -z $1 ]
then
d_date=`date +%Y%m%d --date="-1 day"`
else
d_date=$1
fi
tableName=testTable_$d_date


shell中的hive

  在hive中提供了临时访问hive终端的方式,即使用 【hive -e “语句块”】,也可以通过【hive -f 文件名】 去执行hive脚本文件

  在hive中的参数定义,可以直接使用shell中的参数(下面的判断代码块既是如此)

#判断hive中的表是否存在,存在就删掉,以支持重复抽取
hive -e  "drop table if exists dino.$tableName"  #指定了库名


  另一种参数使用方式是利用hiveconf,但这个不能通过hive -e这种方式去使用,只能在文件中去引用

格式如下

hive -hiveconf variable1='aaa' -hiveconf variable2='bbb' -f xxx.hql


xxx.hql 内容如下,这里只为了说明参数的引用

select * from testTable where col1 betweeb '${hiveconf:variable1}' and '${hiveconf:variable2}'


shell中的sqoop

#sqoop  抽取数据,这里是全表抽取,即没有加where和column参数
sqoop --options-file /home/9003547/sqooppath/fengmingdw.txt \
--table $tableName \
--delete-target-dir --target-dir  /user/hive/tmp/$tableName \
--hive-import --hive-table dino.$tableName \
--create-hive-table \
--hive-overwrite \
--null-non-string '\\N'  \
--null-string '\\N'  \
--fields-terminated-by '\t' \
--lines-terminated-by '\n'   \
--m 1


完整的脚本将放在本文的最后面,这是一些简单的属性说明

1、target-dir 指的是hdfs上的目录,需要当前用户具有读写权限,否则会被拒绝
2、$tableName 是在shell中预先定义的表名,该表名由两部分组成 表名+日期,中间使用下划线分开
3、hive中的null值,在rdbms上的null值在hive中会直接转换成字符串“null”,如果不需要可以使用null-non-string和null-string两个参数将其替换掉,这里将其转换为hive中的空值,即‘\N’,记得转义
4、如果不是一张表,比如只要某些列并限定条,可以使用--columns "col1,col2" --where "col1>2 and col2<10"类似参数


sqoop结果的记录

  在shell中,我们可以把运行的日志利用符号【>>】将结果指向到指定的文件中,但是如果脚本太多,那么把每一个脚本的记录都写入同一个hive表或者rdbms中的表是一个比较好的选择

  这里提供一个hive中的建表语句

create table dino.etl_table2 (
etl_name string comment 'sqoop的job名,可以用table_name替代'
,table_name  string comment '表名,如果MyTestTabel_20150511则MyTestTable'
,etl_date  string comment '取日期,如果MyTestTabel_20150511则20150511'
,start_time string comment 'sqoop脚本的开始时间'
,end_time string comment 'sqoop脚本的结束时间'
,etl_rows int comment  '保留字段,抽取的数据行数,hive中不知道怎么获取'
,etl_hours int comment '保留字段,抽取的具体小时时间点'
)
comment 'table for keeping etl audit record'
row  format delimited
fields terminated by '\t'
lines terminated by '\n'
stored as textfile;


  这里的保留字段是因为在之前的RDBMS中存在的,保留因为后续可能有需要export到RDBMS,这里根据各自需求可以自行建表

  该表的意义是在每次sqoop之后往hive中写入一个记录,相关的脚本如下

  首先在路径/home/9003547/sqooppath下建了一个sh文件,命名为
hive_etl_record.sh


if [ $# != 5 ];then
echo 'must be provide 5 paras'
echo $#
exit 2
fi
echo "传入的参数值为以下"
for arg in "$@"
do
echo $arg
done
#参数赋值
table_name=$1
etl_date=$2
etl_status=$3
start_time=$4
etl_errors=$5

hive -e "
insert into table dino.view_etl_audit
select  '$table_name'as  etl_name
,'$table_name'as etl_table
,'$etl_date' as  etl_date
,$etl_status as etl_status
,'$start_time' as start_time
,from_unixtime(unix_timestamp(),'yyyy-MM-dd HH:mm:ss')as end_time
,'$etl_errors'as etl_errors
,'\\N' as etl_rows
,'\\N'as etl_hour
from    dino.dual;
"


注:dual表是一个自建的表,相当于oracle中的dual,只有一列属性为string,并且值只有一个为”x”



这个表的存在只是为了在select一些自给的值的时候使用,只要注意里面只有一行数据就可以了

这个
hive_etl_record.sh
的存在是为了实现代码重用,在实际的sqoop中可以方便的直接传递参数。下面是使用这个文件的实际方法

#判断sqoop执行结果,紧跟在上面的sqoop语句之后
if [$? -ne 0];then
etl_status=0
etl_error="errors"
else
etl_status=1
etl_error="\\N"
fi

#日志写入到hive中,参数顺序对应说明
#table_name=$1
#etl_date=$2
#etl_status=$3
#start_time=$4
#etl_errors=$5

./home/9003547/sqooppath/hive_etl_record.sh "$table" "$d_date" "$etl_status" start_date" "$start_date" "$etl_errors"


完整的代码

在上述中,更多的是对零散代码的说明,已经贴出了

option-file中的代码  fdw.txt
hive_etl_record.sh的配置


现在贴出一个完整的使用脚本

#!/bin/bash
. ~/.bashrc
#这里要用户自己填写的,有两个地方,第一个是设置tableName的设置,第二个是sqoop语句要自己看表看需求来写
#使用说明
#       抽取指定的表名的数据
#       如果用户在执行该脚本的时候不传入日期参数则默认为当前日期的前一天进行
#       否则为用户指定的日期,格式为yyyyMMdd,如要抽取2015-05-10的数据,那么执行的方式应该是如下
#               sh  脚本名 20150510

#声明获取的数据表名
table=ods_crm_rolegroup

logfile=/home/9003547/sqooplog/$table.txt
#日期
#得到业务日期,如果没有传入日期参数,则由系统直接赋值
if [ -z $1 ]
then
d_date=`date +%Y%m%d --date="-1 day"`
else
d_date=$1
fi
echo $d_date  >> $logfile

d_date_format=`echo ${d_date} | awk '{print substr($d_date,1,4)"-"substr($0,5,2)"-"substr($0,7,2)}'`
echo ${d_date_format} >> $logfile

start_date=`date '+%Y-%m-%d %H:%M:%S'`
echo ${start_date} >> $logfile
tableName=$table"_"$d_date
echo $tableName
#判断表在hive中是否存在,存在就删除,这里hive中的库名为dino
hive -e  "drop table if exists dino.$tableName"

#sqoop  抽取数据,这里全表抽取
sqoop --options-file /home/9003547/sqooppath/fdw.txt \
--table $tableName \
--delete-target-dir --target-dir  /user/hive/tmp/$tableName \
--hive-import --hive-table dino.$tableName \
--hive-drop-import-delims --create-hive-table \
--hive-overwrite \
--null-non-string '\\N'  \
--null-string '\\N'  \
--fields-terminated-by '\t' \
--lines-terminated-by '\n'      \
--m 1

#判断sqoop执行结果,etl_status为0表示失败,为1表示成功,由于这里无法获取到错误信息,只能以"errors"代替
if [ $? -ne 0 ];then
etl_status=0
etl_error="errors"
echo "执行失败" >> $logfile
else
etl_status=1
#etl_error="\\N"
echo "执行成功" >> $logfile
fi
#日志写入到hive中,参数顺序对应说明

#table_name=$1
#etl_date=$2
#etl_status=$3
#start_time=$4
#etl_errors=$5
#write audit of etl's recored  into  hive's table

sh /home/9003547/sqooppath/hive_etl_record.sh "$table" "$d_date" "$etl_status"  "$start_date" "$etl_errors"


以上就是完整的脚本说明

  这个东西的调度方式可以采用linux自带的crontab,但是如果有条件最好还是弄一个可视化图形进行操作,包括作业的顺序、重跑等,在系统后台维护各个作业的依赖关系,这样对所有的作业维护才是最轻松的,具体的话这个设计到web或者客户端开发,需要更专业的同事实现

可能的优化

  这个脚本只是按照最简单的方式去处理,如果而已尝试着用python直接将sqoop语句写进去会更好,这样对日志输出又或者配置文件维护都会更方便一点,完善的地方包括但不限于以下内容

1、明细日志输出到文件

2、sqoop脚本错误结果获取存入库中,这样每天不但不用翻明细的日志文件,也可以直接在hive中select出来

3、如果可以将现在写在hive中的日志记录写入RDBMS,速度快一点也不需要在export回去,最直接的就是写入mysql,因为hive的元数据也存储在这里呀,现成的数据库可以使用。

内容很简单,分享出来一起学习,如果有做改进,我会第一时间修改本文以提供最新的进展,如果看到的朋友有建议也请留言交流
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: