如何制作一个自动更新 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-blahblah7251c663-blahblah 以相同的顺序映射了相同的列?

以上是关于如何制作一个自动更新 Hive 的表的主要内容,如果未能解决你的问题,请参考以下文章

创建自动更新的日历事件列表

如何使用自动增量更新字段 CONCAT?

Word文档如何自动更新Power BI数据和图表?

如何使用计数查询来(自动)更新表中的列

hive表分区的修复

MySQL 服务器未启动。服务器端SQL语句不好?损坏的表?面板自动更新?