从 Hive 查询时,分区表中的数据不显示

Posted

技术标签:

【中文标题】从 Hive 查询时,分区表中的数据不显示【英文标题】:Data from partitioned table does not show up when queried from Hive 【发布时间】:2018-04-26 13:07:50 【问题描述】:

请注意这个问题不是与this one的重复!我不使用 Spark SQL 进行分区!我正在保存单独的镶木地板文件!

我也在使用 Databricks,它不支持 Hive 风格的 SQL。

我在 Hive 中有一个表(我正在使用 Databricks),其中包含两个分区。它看起来像这样:

CREATE TABLE foo_test (`col0` STRING, `col1` STRING, `col2` STRING, `datestamp` STRING)
USING parquet
OPTIONS (
  `serialization.format` '1'
)
PARTITIONED BY (datestamp)

编辑: *这也是调用show create table foo_test;的结果

我已经用 Spark 手动在这个表中添加了两个分区:

df = spark.read.csv(file_path.format(datestamp), header=True, inferSchema=True)

partitionPath = "/mnt/foo_test/datestamp=/".format(datestamp)

df.coalesce(1).write.parquet(partitionPath, mode="overwrite")


/mnt/foo_test/datestamp=20180101/
/mnt/foo_test/datestamp=20180102/

如果我用 Spark 加载数据,我可以看到它在那里:

spark.read.option("mergeSchema", True).parquet("/mnt/foo_test").show()

+----+----+----+----+---------+
|col0|col1|col2|col3|datestamp|
+----+----+----+----+---------+
| foo| bar| baz|   1| 20180102|
| xul| qux| wom|   2| 20180102|
| bar| foo| baz|   1| 20180102|
| qux| xul| wom|   2| 20180102|
| foo| bar| baz|null| 20180101|
| xul| qux| wom|null| 20180101|
| bar| foo| baz|null| 20180101|
| qux| xul| wom|null| 20180101|
+----+----+----+----+---------+

我的问题是,如果我对该 Hive 表运行 SQL 查询,它不会返回任何内容:

SELECT * FROM foo_test;

OK

即使在手动添加分区之后:

spark.sql("ALTER TABLE foo_test ADD IF NOT EXISTS PARTITION (datestamp=20180102)")

并修复桌子:

MSCK REPAIR TABLE foo_test;

我可以看到根据 Hive 存在分区:

SHOW PARTITIONS foo_test;

partition
datestamp=20180102
datestamp=20180101

但是SELECT 什么也没返回。

这是我的表的描述:

col0    string  null
col1    string  null
col2    string  null
datestamp   string  null
# Partition Information     
# col_name  data_type   comment
datestamp   string  null
# Detailed Table Information        
Database    default 
Table   foo_test    
Owner   root    
Created Thu Apr 26 12:25:06 UTC 2018    
Last Access Thu Jan 01 00:00:00 UTC 1970    
Type    MANAGED 
Provider    parquet 
Table Properties    [transient_lastDdlTime=1524745506]  
Location    dbfs:/user/hive/warehouse/foo_test  
Serde Library   org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe 
InputFormat org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat   
OutputFormat    org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat  
Storage Properties  [serialization.format=1]    
Partition Provider  Catalog

这可能是什么问题?

【问题讨论】:

Spark SQL saveAsTable returns empty result 的可能重复项(另请参见此处的第一个答案) 这不是上述问题的重复。我正在使用 Databricks,因为我在这个问题中已正确标记,它不支持 Hive 风格的 SQL。 @whomever downvoted:愿意解释一下吗? 我正在使用 Databricks,因为我已在此问题中正确标记,它不支持 Hive 风格的 SQL - 就此处所需的程度而言,它与任何其他 Spark 相同应用程序,使用 Hive 支持初始化 SparkSession。 【参考方案1】:

您没有在CREATE TABLE 定义中设置位置,也没有设置新添加分区的位置。

在您的表定义中,您应该将其定义为外部表,并以LOCATIONPATH 参数的形式为其提供数据路径。那么MSCK REPAIR TABLE 应该会正确添加分区。

ALTER TABLE命令需要设置LOCATION参数。在那个 sn-p 中,您只是告诉表“有一个分区 date=20180102”,而没有告诉它数据在哪里。

每https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-AddPartitions

spark.sql("ALTER TABLE foo_test ADD IF NOT EXISTS PARTITION (datestamp=20180102) location '/mnt/foo_test/datestamp=20180102/' ")

【讨论】:

ADD PARTITION 没有LOCATION 在语法上是有效的,并且默认为根路径,所以ALTER TABLE foo_test ADD PARTITION (datestamp=20180102) 应该映射/user/hive/warehouse/foo_test/datestamp=20180102 很高兴我能帮助@AdamArold【参考方案2】:

我不使用 Spark SQL 进行分区!

我不得不不同意。这不是 Hive 表定义:

CREATE TABLE foo_test (`col0` STRING, `col1` STRING, `col2` STRING, `datestamp` STRING)
USING parquet
OPTIONS (
  `serialization.format` '1'
)
PARTITIONED BY (datestamp)

这是一个 Spark 表定义。

Hive table definition would be:

CREATE TABLE foo_test (`col0` STRING, `col1` STRING, `col2` STRING)
PARTITIONED BY (`datestamp` STRING)
STORED AS PARQUET

所以你确实使用了 Spark 分区,正如在 the question you've linked 中以及在 linked JIRA ticket 中进一步解释的那样,Spark 和 Hive 分区方案不兼容..

请注意,只要启用了 Hive 支持,SparkSession 已初始化(Databricks 平台上的默认设置),SparkSession.sql 就支持 Hive 和 Spark。

还不清楚您为什么要在这里写信给/mnt/foo_test/datestamp=,这可能是另一个问题来源。如果您想使用本地文件 API(为什么要使用?),Databricks 默认将其挂载到 /dbfs

由于您在没有位置的情况下调用ADD PARTITIONS,它使用表的根路径(dbfs:/user/hive/warehouse/foo_test 基于DESCRIBE 输出),因此如果您决定使用本地 API,并使用默认配置,您应该写信到

/dbfs/user/hive/warehouse/foo_test/datestamp=20180102

如果您使用非标准配置,最好将其包含在您的问题中。

【讨论】:

所以,你基本上是说这个问题在链接为 "not a duplicate of "? 的问题中得到了回答 @Cerbrus 当你这样说时,我想我会这样做:/ 也许作为评论会更好?虽然很难把代码放在那里。你会建议我删除这个吗? Achyuth suggests there might be some other problem here 也是。 不,没有回答。我正在使用我在问题中标记的 Databricks。链接的解决方案不起作用,因为 Databricks 不支持运行 Hive 风格的 SQL。【参考方案3】:

表格定义指向不同的位置

Location    dbfs:/user/hive/warehouse/foo_test  

它应该指向以下位置/mnt/foo_test

查找带有位置的 hive 创建表

【讨论】:

抱歉,这是使用 Databricks 的产物。位置很好。 能否请您执行 show create table table_name 并更新问题一次。确保 好的,请稍等。 我已编辑我的答案以包含show 的结果。【参考方案4】:

当您在 hive 中创建表时:

CREATE TABLE foo_test (`col0` STRING, `col1` STRING, `col2` STRING)
PARTITIONED BY (`datestamp` STRING)
stored as PARQUET
location '/mnt/foo_test';

您可以使用带有分区的火花写入:

df.repartition($"datestamp").partitionBy("datestamp").write.parquet(partitionPath, mode="overwrite")

这将使用分区路径 /mnt/foo_test/datesamp=***/ 写入配置单元表。

我希望这会有所帮助

【讨论】:

以上是关于从 Hive 查询时,分区表中的数据不显示的主要内容,如果未能解决你的问题,请参考以下文章

Hive 动态分区

Spark 不使用 Hive 分区外部表中的分区信息

hive从查询中获取数据插入到表或动态分区

Hive_分区表

如何从 hive 获取最新的分区数据

hive外部表分区