如何制作一个自动更新 Hive 的表
Posted
技术标签:
【中文标题】如何制作一个自动更新 Hive 的表【英文标题】:How to make a table that is automatically updated Hive 【发布时间】:2015-08-26 19:48:57 【问题描述】:我在 Hive 中创建了一个外部表,该表使用来自 HDFS 中 Parquet 存储的数据。
删除HDFS中的数据时,表中没有数据。当数据再次插入 HDFS 中的同一位置时,表不会更新以包含新数据。如果我将新记录插入到包含数据的现有表中,则在我运行 Hive 查询时不会显示新数据。
我如何在 Hive 中创建表:
CREATE EXTERNAL TABLE nodes (id string) STORED AS PARQUET LOCATION "/hdfs/nodes";
相关错误:
Error: java.io.FileNotFoundException: File does not exist: /hdfs/nodes/part-r-00038-2149d17d-f890-48bc-a9dd-5ea07b0ec590.gz.parquet
我看过几篇解释外部表应该包含最新数据的帖子,例如here。但是,这对我来说不是这样,我不知道发生了什么。
我再次将相同的数据插入数据库,并查询表。它包含与以前相同数量的数据。然后,我创建了一个具有不同名称的相同表。它包含两倍的数据,这是正确的数量。
问题可能与元存储数据库有关。我使用 PostgreSQL 而不是 Derby 作为数据库。
相关信息:
Hive 0.13.0 Spark 流式传输 1.4.1 PostgreSQL 9.3 CentOS 7编辑:
检查 Parquet 文件后,我发现零件文件的文件名似乎不兼容。
-rw-r--r-- 3 hdfs hdfs 18702811 2015-08-27 08:22 /hdfs/nodes/part-r-00000-1670f7a9-9d7c-4206-84b5-e812d1d8fd9a.gz.parquet
-rw-r--r-- 3 hdfs hdfs 18703029 2015-08-26 15:43 /hdfs/nodes/part-r-00000-7251c663-f76e-4903-8c5d-e0c6f61e0192.gz.parquet
-rw-r--r-- 3 hdfs hdfs 18724320 2015-08-27 08:22 /hdfs/nodes/part-r-00001-1670f7a9-9d7c-4206-84b5-e812d1d8fd9a.gz.parquet
-rw-r--r-- 3 hdfs hdfs 18723575 2015-08-26 15:43 /hdfs/nodes/part-r-00001-7251c663-f76e-4903-8c5d-e0c6f61e0192.gz.parquet
这些文件是在上述错误中找不到 Hive 时导致 Hive 出错的文件。这意味着外部表不是动态的,接受目录中的任何文件(如果你在 HDFS 中这样称呼它),而是可能只是在创建时跟踪目录中的 parquet 文件列表。
示例 Spark 代码:
nodes.foreachRDD(rdd =>
if (!rdd.isEmpty())
sqlContext.createDataFrame(rdd.map(
n => Row(n.stuff), ParquetStore.nodeSchema)
.write.mode(SaveMode.Append).parquet(node_name)
)
nodeSchema
是架构,node_name
是“/hdfs/nodes”
查看我关于获取Hive external tables to detect new files.的其他问题
【问题讨论】:
如果删除表然后重新创建它,会发生什么情况? 我做了一个`select count(*) from nodes;',删除了表,重新创建了表,然后重新进行了查询。两次结果相同。 您声明“没有显示新数据”——就像 Spark 作业仍在写入文件一样,它们的长度小于 1 个块,因此 HDFS 不会使它们可用于其他进程,例如蜂巢。然后你提到一个 IOError File doesn't exist - 就像 Hive 在设置执行计划时检测到文件,然后一些进程在实际执行之前删除了文件(小型 Parquet 文件的后台合并进程?! 我不熟悉这种格式,但这是 ORC 处理“交易”的方式)。 所以不清楚到底发生了什么,但闻起来像是 Spark、HDFS 和 Hive 之间的阻抗不匹配。 【参考方案1】:为了让 Hive 更新其表,我不得不求助于使用 Hive 的分区功能。通过在每次 Spark 运行期间创建一个新分区,我在 /hdfs/nodes
目录内部创建了一系列目录,如下所示:
/hdfs/nodes/timestamp=<a-timestamp>/<parquet-files>
/hdfs/nodes/timestamp=<a-different-timestamp>/<parquet-files>
然后,在每个 Spark 作业完成后,我在我的 Spark 作业中使用 HiveContext
运行 Hive 命令 MSCK REPAIR TABLE nodes
,它会查找新分区并更新表。
我意识到这不是自动的,但它至少有效。
【讨论】:
【参考方案2】:好的,所以您可能需要将文件封装在一个文件夹中。 Hive 外部表必须映射到可能有多个文件的文件夹上。
尝试将文件写入:/path/to/hdfs/nodes/file 然后将外部表映射到/path/to/hdfs/nodes
所以在文件夹节点中,您将只有 parquet 文件,它应该可以工作
【讨论】:
我更新了我的问题以表明我正在按照您的建议进行操作。我相信问题可能在于,由于我每次运行程序时都将多个文件写入该目录,Hive 可能只查看我第一次创建表时所在的文件。 你能发布火花代码吗?我不明白为什么 hive 将部分数据搜索到节点目录中。 已更新,但我相信我找到了解决方案,即使不是我的问题的真正答案。 只是为了确定:该文件夹包含 Parquet 文件,没有其他内容(没有子目录,没有SUCCESS__
标志等)?并且所有 Parquet 文件都具有完全相同的结构,例如在显示的示例中,作业 1670f7a9-blahblah 和 7251c663-blahblah 以相同的顺序映射了相同的列?以上是关于如何制作一个自动更新 Hive 的表的主要内容,如果未能解决你的问题,请参考以下文章