1. 背景
可以通过不同的方式把数据导入到csv,其中kudu就自带有通过mapreduce方式高效把csv文件导入到自身的工具:ImportCsv. 例如有以下数据的csv文件:
1,name_1,21
2,name_2,22
3,name_3,
其中”,”我们叫做分隔符号,当把以上3个记录的csv文件导入到表t_user(id bigint,name string,age int)时,会发现最终只有id=1,2的记录成功导入。我们理想的情况是3条数据都能导入表,且id=3的记录age为值空。
2. 问题分析
通过追踪kudu的java客户端代码发现了像 3,name_3,这样的行数据最终是会抛出异常的(使用ImportCsv的时候可以配置跳过有异常的行,继续往下导数据),定位到org.apache.kudu.mapreduce.tools.CsvParser
类的parse方法,部分代码片段:
根据代码的逻辑可以得出:以分隔符结尾的行,最后的一列会被抛弃。
所以3,name_3,这一行只会被认为有两个列的值而已,而创建表时的列有3个,最后在导数据时抛出“Not enough columns”异常。
3. 解决方法
为了改动最少的代码以及本来的逻辑,最后选用通过补充字节来解决:既然以分隔符结尾会被当成少一列来处理,那么在本行最后再添加一个分隔符,变成了3,name_3,, ,这样就会被当成3个列了,最后一个列的值为空。
4. 解决步骤
下载相应的源码,稍微修改对应类的逻辑即可
4.1 下载源码
github下载:https://github.com/cloudera/kudu
或者cloudera库下载:http://archive.cloudera.com/kudu/kudu/5/
4.2 修改逻辑
解压后找到java/kudu-client-tools目录下的ImportCsvMapper.java
类文件,我们只需要修改这个类的代码即可:
为类ImportCsvMapper添加属性
在
setup
方法中初始化添加的属性给以分隔符结尾的行补充字节
4.3 添加配置
单独编译kudu-client-tools模块需要将checkstyle_suppressions.xml拷贝到kudu-client-tools根目录:
4.4 重新编译
注意,只需要单独编译kudu-client-tools模块即可,打开CMD路由到java\kudu-client-tools
目录执行以下命令编译:
mvn package -DskipTests
成功后在target目录下可以看到打出的jar包:
我们只需要使用下面的包来导数据即可,它已经包含了相关的依赖。
5. 重新导入
5.1 创建kudu表
CREATE TABLE T_USER (
id BIGINT ,
name string ,
sex String,
PRIMARY KEY(id)
)PARTITION BY HASH PARTITIONS 16 STORED AS KUDU;
注意:这里为了方便所以所有的字段都创建为字符串,因为原来的csv文件有些本来应该是数字的但是存了空值,而空值在使用ImportCsv时转为数字会出错。
5.2 导数据
使用上步骤编译生成的xxxx-with-dependencies.jar包
hadoop jar /data//kudu-client-tools-1.2.0-cdh5.10.0-jar-with-dependencies.jar org.apache.kudu.mapreduce.tools.ImportCsv -Dkudu.master.addresses=master:7051 -Dimportcsv.skip.bad.lines=true '-Dimportcsv.separator=,' 'id,name,sex' impala::impala_kudu.T_USER hdfs://master:8020/data//part-m-000.csv
5.3 验证
通过查询数据来验证是否3条记录都已经导入表
可以看到三条记录都已经可以导入到KUDU里了。