Sqoop简单介绍
Sqoop是用来在Hadoop平台和其他结构性存储(比如关系型数据库)之间解决大量数据传输问题的工具。也就是说可以从Oracle,MySQL,PostgreSQL等数据库中将数据传输到HDFS,Hive,HBase上,反之也可以。
简单说一下Sqoop的原理。它实际上就是将导入导出这个工作通过指令翻译成一个java文件,然后通过MapReduce来执行格式的转换和传输工作。
具体怎么配置,怎么使用,官方文档在这里 ——Sqoop User Guide 。
官方文档写得很全,其他博客其实没有官方文档写的清楚。
问题描述
我写了个接口能够根据用户输入的数据库类型,表名,数据库名,就可以自动生成对应的Sqoop脚本,用户自己就不用额外写一份可能还会出错的脚本,能直接用Sqoop将数据库中的数据抽取到Hive上。
以Oracle作为例子,Oracle中的数据抽出来转换为Java是由对应的映射关系的。问题就在于有些数据类型格式在Java中没有找到对应的映射关系,导致Sqoop导入失败。比如Oracle中的Bit,Blob,Clob,LongText字段。因此在执行脚本的时候会出现导入失败的问题。
后来通过阅读官方文档后得知,Sqoop在遇到这些特殊字段类型时,是可以强制转换的,具体看 SqoopUserGuide - controlling type mapping 。
--map-column-java <mapping> 重写SQL到Java类型的映射
--map-column-hive <mapping> 重写Hive到Java类型的映射
举个例子,比如说SQL中的原先字段id
强制转为String类型,字段value
强制转为Integer类型(不管他们原本是什么),那么:
$ sqoop import ... --map-column-java id=String,value=Integer
这样就可以解决Sqoop在导入导出数据的时候格式错误的问题。
具体SQL类型中哪些格式对应着HIVE中的哪些格式,看这个链接: sqoop导数类型不支持解决办法:Hive does not support the SQL type for column 。参考这个链接,接下来做一个关系型数据库数据类型映射Java的对应类型的归纳。
对应数据类型
- 以Oracle数据库为例,它可以映射到java的数据类型:
public String toJavaType(int sqlType) {
// Mappings taken from:
// http://java.sun.com/j2se/1.3/docs/guide/jdbc/getstart/mapping.html
if (sqlType == Types.INTEGER) {
return "Integer";
} else if (sqlType == Types.VARCHAR) {
return "String";
} else if (sqlType == Types.CHAR) {
return "String";
} else if (sqlType == Types.LONGVARCHAR) {
return "String";
} else if (sqlType == Types.NVARCHAR) {
return "String";
} else if (sqlType == Types.NCHAR) {
return "String";
} else if (sqlType == Types.LONGNVARCHAR) {
return "String";
} else if (sqlType == Types.NUMERIC) {
return "java.math.BigDecimal";
} else if (sqlType == Types.DECIMAL) {
return "java.math.BigDecimal";
} else if (sqlType == Types.BIT) {
return "Boolean";
} else if (sqlType == Types.BOOLEAN) {
return "Boolean";
} else if (sqlType == Types.TINYINT) {
return "Integer";
} else if (sqlType == Types.SMALLINT) {
return "Integer";
} else if (sqlType == Types.BIGINT) {
return "Long";
} else if (sqlType == Types.REAL) {
return "Float";
} else if (sqlType == Types.FLOAT) {
return "Double";
} else if (sqlType == Types.DOUBLE) {
return "Double";
} else if (sqlType == Types.DATE) {
return "java.sql.Date";
} else if (sqlType == Types.TIME) {
return "java.sql.Time";
} else if (sqlType == Types.TIMESTAMP) {
return "java.sql.Timestamp";
} else if (sqlType == Types.BINARY
|| sqlType == Types.VARBINARY) {
return BytesWritable.class.getName();
} else if (sqlType == Types.CLOB) {
return ClobRef.class.getName();
} else if (sqlType == Types.BLOB
|| sqlType == Types.LONGVARBINARY) {
return BlobRef.class.getName();
} else {
// TODO(aaron): Support DISTINCT, ARRAY, STRUCT, REF, JAVA_OBJECT.
// Return null indicating database-specific manager should return a
// java data type if it can find one for any nonstandard type.
return null;
}
- 建表时,Oracle映射到Hive的数据类型(查看
org.apache.sqoop.hive.HiveTypes
)
public static String toHiveType(int sqlType) {
switch (sqlType) {
case Types.INTEGER:
case Types.SMALLINT:
return "INT";
case Types.VARCHAR:
case Types.CHAR:
case Types.LONGVARCHAR:
case Types.NVARCHAR:
case Types.NCHAR:
case Types.LONGNVARCHAR:
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.CLOB:
return "STRING";
case Types.NUMERIC:
case Types.DECIMAL:
case Types.FLOAT:
case Types.DOUBLE:
case Types.REAL:
return "DOUBLE";
case Types.BIT:
case Types.BOOLEAN:
return "BOOLEAN";
case Types.TINYINT:
return "TINYINT";
case Types.BIGINT:
return "BIGINT";
default:
// TODO(aaron): Support BINARY, VARBINARY, LONGVARBINARY, DISTINCT,
// BLOB, ARRAY, STRUCT, REF, JAVA_OBJECT.
return null;
}
}
- 特殊的字段类型
通过使用强制转换的方式来导入。
- Oracle中的Blob,LongBlob导入到Hive中对应是String。要在脚本中添加如下配置,在映射成java的时候映射为String,Hive中也要映射为String:
$ sqoop import ... --map-column-java <mapping> [字段名]=String \
--map-column-hive <mapping> [字段名]=String
- Oracle的Bit字段则映射为String。若是按照常规映射,则会映射成boolean的
true
或者false
。而原先在数据库中展示的则是0
和1
。添加以下配置:
$ sqoop import ... --map-column-java <mapping> [字段名]=String
** 凭之前做项目印象打的,如果有错误请指正。
网友评论