从多个服务器加载数据时避免数据重复

时间:2015-08-18 13:09:21

标签: hadoop hive

我有十几个Web服务器,每个都将数据写入日志文件。在每小时开始时,使用运行命令的cron脚本将前一小时的数据加载到配置单元:

hive -e "LOAD DATA LOCAL INPATH 'myfile.log' INTO TABLE my_table PARTITION(dt='2015-08-17-05')"

在某些情况下,命令失败并以0以外的代码退出,在这种情况下,我们的脚本等待并再次尝试。问题是,在某些情况下失败,数据加载失败,即使它显示失败消息。我如何确定数据是否已加载?

加载数据

>的“失败”示例:

  

将数据加载到表default.my_table分区(dt = 2015-08-17-05)   异常失败   org.apache.hadoop.hive.ql.metadata.HiveException:无法更改   划分。 FAILED:执行错误,返回代码1   org.apache.hadoop.hive.ql.exec.MoveTask

修改 或者,有没有办法查询hive加载到其中的文件名?我可以使用DESCRIBE查看文件数量。我可以知道他们的名字吗?

2 个答案:

答案 0 :(得分:2)

关于“已在分区中加载了哪些文件”:

  • 如果您使用了EXTERNAL TABLE并刚刚上传了原始数据 映射到LOCATION的HDFS目录中的文件,然后你可以

(a)从命令行在该目录上运行hdfs dfs -ls(或使用等效的Java API调用) (b)运行Hive查询,例如select distinct INPUT__FILE__NAME from (...)

  • 但在您的情况下,您将数据复制到“托管”表中,所以在那里 无法检索数据沿袭(即使用了哪个日志文件) 创建每个托管数据文件)
  • ...除非您在日志文件中明确 原始文件名, 当然(在“特殊”标题记录上,或在每条记录的开头 - 可以用好的sed完成)

关于“如何自动避免INSERT上的重复”:有一种方法,但它需要相当多的重新设计,并且在处理时间/(额外的Map步骤加MapJoin)/方面会花费你。 ..

  1. 将您的日志文件映射到EXTERNAL TABLE,以便您可以运行 INSERT-SELECT查询
  2. 使用INPUT__FILE__NAME伪列作为源
  3. 将原始文件名上传到托管表中
  4. 添加一个带有相关子查询的WHERE NOT EXISTS子句,这样如果源文件名已经存在于目标中,那么就不再加载

    INSERT INTO TABLE Target SELECT ColA, ColB, ColC, INPUT__FILE__NAME AS SrcFileName FROM Source src WHERE NOT EXISTS (SELECT DISTINCT 1 FROM Target trg WHERE trg.SrcFileName =src.INPUT__FILE__NAME )

    注意实际需要的愚蠢的DISTINCT,以避免吹掉Mappers中的RAM;对于像Oracle这样成熟的DBMS来说它会毫无用处,但是Hive优化器仍然相当粗糙......

答案 1 :(得分:0)

我不相信你可以简单地在Hadoop / Hive中这样做。以下是python中实现的基础知识:

import subprocess
x=subprocess.check_output([hive -e "select count(*) from my_table where dt='2015-08-17-05'"])
print type(x)
print x

但你必须花一些时间使用反斜杠才能让hive -e使用python工作。这可能非常困难。首先使用该简单查询编写文件可能更容易,然后使用hive -f filename。然后,打印subprocess.check_output的输出以查看输出的存储方式。您可能需要执行一些正则表达式或类型转换,但我认为它应该以字符串形式返回。然后只需使用if语句:

if x > 0:
    pass
else:
    hive -e "LOAD DATA LOCAL INPATH 'myfile.log' INTO TABLE my_table PARTITION(dt='2015-08-17-05')"