将 Spark 数据帧保存到 Hive:table 不可读,因为 "parquet not a SequenceFile"

save Spark dataframe to Hive: table not readable because "parquet not a SequenceFile"

我想使用 PySpark 将 Spark (v 1.3.0) 数据帧中的数据保存到 Hive table。

documentation 状态:

"spark.sql.hive.convertMetastoreParquet: When set to false, Spark SQL will use the Hive SerDe for parquet tables instead of the built in support."

Spark tutorial,好像这个属性可以设置:

from pyspark.sql import HiveContext

sqlContext = HiveContext(sc)
sqlContext.sql("SET spark.sql.hive.convertMetastoreParquet=false")

# code to create dataframe

my_dataframe.saveAsTable("my_dataframe")

但是,当我尝试在 Hive it 中查询保存的 table 时 returns:

hive> select * from my_dataframe;
OK
Failed with exception java.io.IOException:java.io.IOException: 
hdfs://hadoop01.woolford.io:8020/user/hive/warehouse/my_dataframe/part-r-00001.parquet
not a SequenceFile

如何保存 table 以便在 Hive 中立即可读?

我去过那里...
API 在这方面有点误导。
DataFrame.saveAsTable 创建一个 Hive table,而是一个内部 Spark table 源。
它还将某些内容存储到 Hive Metastore 中,但不是您想要的内容。
这个 remark 是由关于 Spark 1.3 的 spark 用户邮件列表制作的。

如果您希望从 Spark 创建一个 Hive table,您可以使用这种方法:
1. 通过 SparkSQL 使用 Create Table ... 用于 Hive 元存储。
2. 对实际数据使用 DataFrame.insertInto(tableName, overwriteMode) (Spark 1.3)

我上周遇到了这个问题并找到了解决方法

故事是这样的: 如果我在没有 partitionBy:

的情况下创建 table,我可以在 Hive 中看到 table
spark-shell>someDF.write.mode(SaveMode.Overwrite)
                  .format("parquet")
                  .saveAsTable("TBL_HIVE_IS_HAPPY")

hive> desc TBL_HIVE_IS_HAPPY;
      OK
      user_id                   string                                      
      email                     string                                      
      ts                        string                                      

但是 Hive 无法理解 table 模式(模式为空...)如果我这样做:

spark-shell>someDF.write.mode(SaveMode.Overwrite)
                  .format("parquet")
                  .saveAsTable("TBL_HIVE_IS_NOT_HAPPY")

hive> desc TBL_HIVE_IS_NOT_HAPPY;
      # col_name                data_type               from_deserializer  

[解决方法]:

spark-shell>sqlContext.sql("SET spark.sql.hive.convertMetastoreParquet=false")
spark-shell>df.write
              .partitionBy("ts")
              .mode(SaveMode.Overwrite)
              .saveAsTable("Happy_HIVE")//Suppose this table is saved at /apps/hive/warehouse/Happy_HIVE


hive> DROP TABLE IF EXISTS Happy_HIVE;
hive> CREATE EXTERNAL TABLE Happy_HIVE (user_id string,email string,ts string)
                                       PARTITIONED BY(day STRING)
                                       STORED AS PARQUET
                                       LOCATION '/apps/hive/warehouse/Happy_HIVE';
hive> MSCK REPAIR TABLE Happy_HIVE;

问题是通过DataframeAPI(partitionBy+saveAsTable)创建的数据源table与Hive不兼容。(看这个link). By setting spark.sql.hive.convertMetastoreParquet to false as suggested in the doc,Spark只把数据放到HDFS上,但不会在 Hive 上创建 table。然后您可以手动进入配置单元 shell 以创建外部 table,并使用指向数据位置的正确架构和分区定义。 我已经在 Spark 1.6.1 中对此进行了测试,它对我有用。希望对您有所帮助!

我在pyspark做过,spark版本2.3.0:

在我们需要 save/overwrite 数据的地方创建空 table,例如:

create table databaseName.NewTableName like databaseName.OldTableName;

然后 运行 下面的命令:

df1.write.mode("overwrite").partitionBy("year","month","day").format("parquet").saveAsTable("databaseName.NewTableName");

问题是您无法使用 hive 阅读此 table 但可以使用 spark 阅读。

元数据尚不存在。换句话说,它会将存在于 HDFS 但不存在于 Metastore 中的任何分区添加到 Hive Metastore。