web-dev-qa-db-fra.com

sauvegarder la base de données Spark dans Hive: table illisible voiture "le parquet n'est pas un fichier de séquence"

J'aimerais enregistrer les données d'une structure de données Spark (v 1.3.0) dans une table Hive à l'aide de PySpark.

La documentation indique:

"spark.sql.Hive.convertMetastoreParquet: Lorsqu'il est défini sur false, Spark SQL utilise Hive SerDe pour les tables de parquet au lieu du support intégré."

En regardant le didacticiel Spark , il semble que cette propriété puisse être définie:

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")

Cependant, lorsque j'essaie d'interroger la table enregistrée dans Hive, elle renvoie:

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

Comment enregistrer la table afin qu'elle soit immédiatement lisible dans Hive?

9
Alex Woolford

J'ai été là...
L'API est un peu trompeur sur celui-ci.
DataFrame.saveAsTable fait not crée une table Hive, mais une source de table Spark interne.
Il stocke également quelque chose dans Hive metastore, mais pas ce que vous souhaitez.
Cette remarque a été faite par la liste de diffusion spark-user concernant Spark 1.3. 

Si vous souhaitez créer une table Hive à partir de Spark, vous pouvez utiliser cette approche:
1. Utilisez Create Table ... via SparkSQL pour le métastore.
2. Utilisez DataFrame.insertInto(tableName, overwriteMode) pour les données réelles (Spark 1.3) 

16
Leet-Falcon

J'ai frappé ce problème la semaine dernière et j'ai pu trouver une solution de contournement

Voici l'histoire: Je peux voir la table dans Hive si j'ai créé la table sans partitionBy:

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                                      

Mais Hive ne comprend pas le schéma de la table (le schéma est vide ...) si je fais ceci:

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  

[Solution]:

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;

Le problème est que la table de source de données créée via l'API Dataframe (partitionBy + saveAsTable) n'est pas compatible avec Hive (voir this link ). En définissant spark.sql.Hive.convertMetastoreParquet sur false comme suggéré dans le fichier doc , Spark ne place les données que sur HDFS, mais ne crée pas de table sur Hive. Et ensuite, vous pouvez manuellement accéder à Hive Shell pour créer une table externe avec la définition correcte du schéma et de la partition pointant vers l'emplacement des données. Je l'ai testé dans Spark 1.6.1 et cela a fonctionné pour moi. J'espère que ça aide!

3
Yuan Zhao

J'ai fait dans pyspark, version 2.3.0:

crée une table vide sur laquelle nous devons sauvegarder/écraser des données telles que:

create table databaseName.NewTableName like databaseName.OldTableName;

puis lancez la commande ci-dessous:

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

Le problème est que vous ne pouvez pas lire ce tableau avec Hive, mais que vous pouvez lire avec étincelle.

0
dinesh rajput