Come salvare DataFrame direttamente su Hive?


85

È possibile salvare DataFramein Spark direttamente su Hive?

Ho provato a convertire DataFramein Rdde quindi salvare come file di testo e quindi caricare in hive. Ma mi chiedo se posso salvare direttamente dataframein hive

Risposte:


118

È possibile creare una tabella temporanea in memoria e archiviarla nella tabella hive utilizzando sqlContext.

Diciamo che il tuo data frame è myDf. Puoi creare una tabella temporanea utilizzando,

myDf.createOrReplaceTempView("mytempTable") 

Quindi puoi utilizzare una semplice istruzione hive per creare una tabella ed eseguire il dump dei dati dalla tua tabella temporanea.

sqlContext.sql("create table mytable as select * from mytempTable");

2
questo ha aggirato gli errori di lettura del parquet che stavo ottenendo usando write.saveAsTable in spark 2.0
ski_squaw

2
Sì, tuttavia, possiamo utilizzare la partizione in base al frame di dati prima di creare la tabella temporanea. @chhantyal
Vinay Kumar

1
Come hai potuto mescolare e abbinare il temporarytavolo con il hivetavolo? Quando lo faccio show tablesinclude solo le hivetabelle per la mia spark 2.3.0installazione
StephenBoesch

1
questa tabella temporanea verrà salvata nel contesto hive e non appartiene in alcun modo alle tabelle hive.
Vinay Kumar

1
ciao @VinayKumar perché dici "Se stai usando saveAsTable (è più come mantenere il tuo dataframe), devi assicurarti di avere abbastanza memoria allocata per la tua applicazione spark". potresti spiegare questo punto?
enneppi

28

Usa DataFrameWriter.saveAsTable. ( df.write.saveAsTable(...)) Vedere Spark SQL e Guida DataFrame .


4
saveAsTable non crea tabelle compatibili con Hive. La migliore soluzione che ho trovato è di Vinay Kumar.
RChat

@ Jacek: ho aggiunto questa nota io stesso, perché penso che la mia risposta sia sbagliata. Lo cancellerei, tranne per il fatto che è accettato. Pensi che la nota sia sbagliata?
Daniel Darabos,

Sì. La nota era sbagliata ed è per questo che l'ho rimossa. "Per favore correggimi se sbaglio" si applica qui :)
Jacek Laskowski

1
questo df.write().saveAsTable(tableName) scriverà anche i dati di streaming nella tabella?
user1870400

1
no non puoi salvare i dati di streaming con saveAsTable non è nemmeno nell'api
Brian

21

Non vedo df.write.saveAsTable(...)deprecato nella documentazione di Spark 2.0. Ha funzionato per noi su Amazon EMR. Siamo stati perfettamente in grado di leggere i dati da S3 in un dataframe, elaborarli, creare una tabella dal risultato e leggerla con MicroStrategy. Anche la risposta di Vinays ha funzionato.


5
Qualcuno ha contrassegnato questa risposta come di bassa qualità a causa della lunghezza e del contenuto. Ad essere sincero probabilmente sarebbe stato meglio come commento. Immagino che sia attivo da due anni e alcune persone lo hanno trovato utile, quindi potrebbe essere utile lasciare le cose come sono?
serakfalcon

Sono d'accordo, commentare sarebbe stata la scelta migliore. Lezione appresa :-)
Alex

15

devi avere / creare un HiveContext

import org.apache.spark.sql.hive.HiveContext;

HiveContext sqlContext = new org.apache.spark.sql.hive.HiveContext(sc.sc());

Quindi salva direttamente il dataframe o seleziona le colonne da memorizzare come tabella hive

df è dataframe

df.write().mode("overwrite").saveAsTable("schemaName.tableName");

o

df.select(df.col("col1"),df.col("col2"), df.col("col3")) .write().mode("overwrite").saveAsTable("schemaName.tableName");

o

df.write().mode(SaveMode.Overwrite).saveAsTable("dbName.tableName");

SaveModes sono Aggiungi / Ignora / Sovrascrivi / ErrorIfExists

Ho aggiunto qui la definizione per HiveContext dalla documentazione di Spark,

Oltre a SQLContext di base, puoi anche creare un HiveContext, che fornisce un superset delle funzionalità fornite da SQLContext di base. Altre funzionalità includono la possibilità di scrivere query utilizzando il parser HiveQL più completo, l'accesso alle UDF Hive e la capacità di leggere i dati dalle tabelle Hive. Per usare un HiveContext, non è necessario disporre di una configurazione Hive esistente e tutte le origini dati disponibili per un SQLContext sono ancora disponibili. HiveContext viene pacchettizzato solo separatamente per evitare di includere tutte le dipendenze di Hive nella build Spark predefinita.


su Spark versione 1.6.2, l'utilizzo di "dbName.tableName" restituisce questo errore:

org.apache.spark.sql.AnalysisException: non è consentito specificare il nome del database o altri qualificatori per le tabelle temporanee. Se il nome della tabella contiene punti (.), Si prega di citare il nome della tabella con i backtick ()


Il secondo comando è: 'df.select (df.col ("col1"), df.col ("col2"), df.col ("col3")) .write (). Mode ("overwrite"). SaveAsTable ("schemaName.tableName"); ' richiedi che le colonne selezionate che intendi sovrascrivere esistano già nella tabella? Quindi hai la tabella esistente e sovrascrivi solo le colonne 1,2,3 esistenti con i nuovi dati dal tuo df in Spark? è interpretato bene?
dieHellste

3
df.write().mode...deve essere modificato indf.write.mode...
utente 923227

8

Salvare in Hive è solo questione di utilizzare il write()metodo del tuo SQLContext:

df.write.saveAsTable(tableName)

Vedi https://spark.apache.org/docs/2.1.0/api/java/org/apache/spark/sql/DataFrameWriter.html#saveAsTable(java.lang.String)

Da Spark 2.2: usa DataSet invece DataFrame.


Mi sembra di avere un errore che afferma che Giobbe è stato interrotto. Ho provato il seguente codice pyspark_df.write.mode ("overwrite"). SaveAsTable ("InjuryTab2")
Sade

Ciao! perchè questo? From Spark 2.2: use DataSet instead DataFrame.
onofricamila

3

Scusa se scrivo in ritardo al post ma non vedo risposta accettata.

df.write().saveAsTablelancerà AnalysisExceptione non è compatibile con la tabella HIVE.

Memorizzare DF come df.write().format("hive")dovrebbe fare il trucco!

Tuttavia, se ciò non funziona, quindi, seguendo i commenti e le risposte precedenti, questa è la soluzione migliore secondo me (aperta ai suggerimenti però).

L'approccio migliore è creare esplicitamente la tabella HIVE (inclusa la tabella PARTITIONED),

def createHiveTable: Unit ={
spark.sql("CREATE TABLE $hive_table_name($fields) " +
  "PARTITIONED BY ($partition_column String) STORED AS $StorageType")
}

salva DF come tabella temporanea,

df.createOrReplaceTempView("$tempTableName")

e inserire nella tabella PARTITIONED HIVE:

spark.sql("insert into table default.$hive_table_name PARTITION($partition_column) select * from $tempTableName")
spark.sql("select * from default.$hive_table_name").show(1000,false)

Ovviamente l' ULTIMA COLONNA in DF sarà la COLONNA DI PARTIZIONE, quindi crea la tabella HIVE di conseguenza!

Si prega di commentare se funziona! o no.


--AGGIORNARE--

df.write()
  .partitionBy("$partition_column")
  .format("hive")
  .mode(SaveMode.append)
  .saveAsTable($new_table_name_to_be_created_in_hive)  //Table should not exist OR should be a PARTITIONED table in HIVE

1

Ecco la versione di PySpark per creare un tavolo Hive da file parquet. Potresti aver generato file Parquet utilizzando uno schema dedotto e ora desideri inviare la definizione al metastore Hive. Puoi anche inviare la definizione al sistema come AWS Glue o AWS Athena e non solo al metastore Hive. Qui sto usando spark.sql per inviare / creare una tabella permanente.

   # Location where my parquet files are present.
    df = spark.read.parquet("s3://my-location/data/")
    cols = df.dtypes
    buf = []
    buf.append('CREATE EXTERNAL TABLE test123 (')
    keyanddatatypes =  df.dtypes
    sizeof = len(df.dtypes)
    print ("size----------",sizeof)
    count=1;
    for eachvalue in keyanddatatypes:
        print count,sizeof,eachvalue
        if count == sizeof:
            total = str(eachvalue[0])+str(' ')+str(eachvalue[1])
        else:
            total = str(eachvalue[0]) + str(' ') + str(eachvalue[1]) + str(',')
        buf.append(total)
        count = count + 1

    buf.append(' )')
    buf.append(' STORED as parquet ')
    buf.append("LOCATION")
    buf.append("'")
    buf.append('s3://my-location/data/')
    buf.append("'")
    buf.append("'")
    ##partition by pt
    tabledef = ''.join(buf)

    print "---------print definition ---------"
    print tabledef
    ## create a table using spark.sql. Assuming you are using spark 2.1+
    spark.sql(tabledef);

1

Per le tabelle esterne Hive utilizzo questa funzione in PySpark:

def save_table(sparkSession, dataframe, database, table_name, save_format="PARQUET"):
    print("Saving result in {}.{}".format(database, table_name))
    output_schema = "," \
        .join(["{} {}".format(x.name.lower(), x.dataType) for x in list(dataframe.schema)]) \
        .replace("StringType", "STRING") \
        .replace("IntegerType", "INT") \
        .replace("DateType", "DATE") \
        .replace("LongType", "INT") \
        .replace("TimestampType", "INT") \
        .replace("BooleanType", "BOOLEAN") \
        .replace("FloatType", "FLOAT")\
        .replace("DoubleType","FLOAT")
    output_schema = re.sub(r'DecimalType[(][0-9]+,[0-9]+[)]', 'FLOAT', output_schema)

    sparkSession.sql("DROP TABLE IF EXISTS {}.{}".format(database, table_name))

    query = "CREATE EXTERNAL TABLE IF NOT EXISTS {}.{} ({}) STORED AS {} LOCATION '/user/hive/{}/{}'" \
        .format(database, table_name, output_schema, save_format, database, table_name)
    sparkSession.sql(query)
    dataframe.write.insertInto('{}.{}'.format(database, table_name),overwrite = True)

1

Nel mio caso funziona bene:

from pyspark_llap import HiveWarehouseSession
hive = HiveWarehouseSession.session(spark).build()
hive.setDatabase("DatabaseName")
df = spark.read.format("csv").option("Header",True).load("/user/csvlocation.csv")
df.write.format(HiveWarehouseSession().HIVE_WAREHOUSE_CONNECTOR).option("table",<tablename>).save()

Fatto!!

Puoi leggere i dati, lasciarti dare come "dipendente"

hive.executeQuery("select * from Employee").show()

Per maggiori dettagli usa questo URL: https://docs.cloudera.com/HDPDocuments/HDP3/HDP-3.1.5/integrating-hive/content/hive-read-write-operations.html


0

Potresti usare la libreria Spark-llap di Hortonworks in questo modo

import com.hortonworks.hwc.HiveWarehouseSession

df.write
  .format("com.hortonworks.spark.sql.hive.llap.HiveWarehouseConnector")
  .mode("append")
  .option("table", "myDatabase.myTable")
  .save()

-1

Se vuoi creare una tabella hive (che non esiste) da un dataframe (a volte non riesce a creare con DataFrameWriter.saveAsTable). StructType.toDDLaiuterà a elencare le colonne come una stringa.

val df = ...

val schemaStr = df.schema.toDDL # This gives the columns 
spark.sql(s"""create table hive_table ( ${schemaStr})""")

//Now write the dataframe to the table
df.write.saveAsTable("hive_table")

hive_tableverrà creato nello spazio predefinito poiché non abbiamo fornito alcun database in spark.sql(). stg.hive_tablepuò essere utilizzato per creare hive_tablenel stgdatabase.


Esempio dettagliato trovato qui: stackoverflow.com/a/56833395/1592191
mrsrinivas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.