现有如下,一堆数据文件,以日期命名,因为需要按分区加载到一个分区表中。

如果手动加载,会浪费很多时间,所以有两种方式实现自动遍历并加载到hive表。

java 覆盖 批量写入txt java批量写入hive_hdfs

第一种:JAVA代码

连接hdfs,读取每一个数据,远程执行hive -e,这样会浪费大量的中间过程。

package com.czxy.demo05;

import net.neoremind.sshxcute.core.ConnBean;
import net.neoremind.sshxcute.core.Result;
import net.neoremind.sshxcute.core.SSHExec;
import net.neoremind.sshxcute.task.impl.ExecCommand;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.log4j.Logger;

import java.net.URI;

/**
 * app_traffic
 */
public class LoadData02 {
    public static void main(String[] args) throws Exception{
        Configuration conf = new Configuration();

        //该类的对象是一个文件系统对象
        FileSystem fileSystem=FileSystem.get(new URI("hdfs://192.168.100.201:8020"),conf);

        //获取某一目录下的所有文件
        FileStatus stats[]=fileSystem.listStatus(new Path("/HistoryDatas/app_traffic_data_output"));

        //设置链接的服务器
        ConnBean connBean=new ConnBean("hadoop01", "root","123456" );
        //链接服务器
        SSHExec sshExec =SSHExec.getInstance(connBean);
        sshExec.connect();

        //控制台输出对象
        Logger test = Logger.getLogger("Test");
        //遍历
        for(int i = 0; i < stats.length; ++i){
            //获取文件路径
            Path path = stats[i].getPath();

            //获取文件名中的日期
            String date = path.getName().split("\\.")[0];
            String[] split = date.split("-");

            //截取出年月日,按分区加载数据
            String year =split[0];
            String month = split[1];
            String day = split[2];


            //设置执行的命令  注意,hive -e 只认准双引号,所以使用转义的双引号而不是单引号↓ 分区加DT是为了和表中字段区别
            ExecCommand execCommand=new ExecCommand("hive -e \"use telecom;LOAD DATA INPATH '"+path+"' OVERWRITE INTO TABLE app_traffic PARTITION (DTyear='"+year+"',DTmonth='"+month+"',DTday='"+day+"');\"");
            //执行命令
            Result exec = sshExec.exec(execCommand);

            test.info("当前进度:"+i+"   总进度:"+stats.length);
        }

        //关闭连接
        sshExec.disconnect();
        //关闭HDFS文件系统对象
        fileSystem.close();

    }
}

第二种:shell脚本

脚本执行省去了建立连接和本机与节点传输数据的时间,更快!

#!/bin/bash  
#将要导入的文件路径写到files0.txt备用
hadoop fs -ls /HistoryDatas/app_traffic_data_output/ | awk '{print $8}' > files0.txt

#按行读取files0.txt每一行是一个路径
#路径示例:/HistoryDatas/app_traffic_data_output/2018-08-29.txt
cat ./files0.txt | while read line
do
	#截取出日期字符串
	VarDate=$(echo $line | awk -F '/' {'print $4'} | awk -F '.' {'print $1'} )
	
	#分别获取年月日,按分区加载数据
	VarYear=$(echo $VarDate | awk -F '-' '{print $1}')
	VarMonth=$(echo $VarDate | awk -F '-' '{print $2}')
	VarDay=$(echo $VarDate | awk -F '-' '{print $3}')

	#执行数据加载
	hive -e "use telecom;LOAD DATA INPATH '"${line}"' OVERWRITE INTO TABLE app_traffic PARTITION (DTyear='"${VarYear}"',DTmonth='"${VarMonth}"',DTday='"${VarDay}"');"
	
	
done


#$()表示提取命令的标准输出  shell 赋值符号两边不能有空格
#AWK没有标准输入,如果把$line放在后面,awk会把整个文件都读走,所以使用管道,让awk只处理管道里的内容
#这样就不会造成只执行一次循环的情况了

上面这个是第一版,赶工赶出来的,下面这个经过优化,速度更快(快了10倍不止)

#!/bin/bash  
#将要导入的文件路径写到files0.txt备用
hadoop fs -ls /HistoryDatas/networkqualityinfo_db_data_output/ | awk '{print $8}' > files0.txt

#按行读取files0.txt每一行是一个路径
echo 'use telecom;' >> tmpSQL.sql
#路径示例:/HistoryDatas/app_traffic_data_output/2018-08-29.txt
cat ./files0.txt | while read line
do
	#截取出日期字符串
	VarDate=$(echo $line | awk -F '/' {'print $4'} | awk -F '.' {'print $1'} )
	
	#分别获取年月日,按分区加载数据
	VarYear=$(echo $VarDate | awk -F '-' '{print $1}')
	VarMonth=$(echo $VarDate | awk -F '-' '{print $2}')
	VarDay=$(echo $VarDate | awk -F '-' '{print $3}')

	#执行数据加载
	
	echo 'LOAD DATA INPATH "'"${line}"'" OVERWRITE INTO TABLE networkqualityinfo PARTITION (DTyear="'"${VarYear}"'",DTmonth="'"${VarMonth}"'",DTday="'"${VarDay}"'");' >> tmpSQL.sql
	#hive -e "use telecom;LOAD DATA INPATH '"${line}"' OVERWRITE INTO TABLE networkqualityinfo PARTITION (DTyear='"${VarYear}"',DTmonth='"${VarMonth}"',DTday='"${VarDay}"');"
	
	
done



#$()表示提取命令的标准输出  shell 赋值符号两边不能有空格
#AWK没有标准输入,如果把$line放在后面,awk会把整个文件都读走,所以使用管道,让awk只处理管道里的内容
#这样就不会造成只执行一次循环的情况了

生成的tmpSQL.sql里面第一行为use telecom;
是使用数据库,然鹅,第二行的path估计会是空的,需要手动修改。
(load data inpath “” 那个双引号估计是空的)

如果查看生成的.sql文件没问题,就可以使用hive -f 执行了
由于hive -e 需要重复的启动hive和关闭hive浪费了不少时间,
这样可以节约大量的时间。