如何将DataFrame直接保存到Hive?


85

是否可以DataFrame直接将火花保存到Hive?

我尝试过转换DataFrameRdd,然后另存为文本文件,然后在配置单元中加载。但我想知道我是否可以直接保存dataframe到蜂巢

Answers:


116

您可以创建一个内存中临时表,然后使用sqlContext将它们存储在配置单元表中。

假设您的数据框是myDf。您可以使用创建一个临时表,

myDf.createOrReplaceTempView("mytempTable") 

然后,您可以使用简单的hive语句创建表并从临时表中转储数据。

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

2
这解决了我在spark 2.0中使用write.saveAsTable时遇到的拼花读取错误
ski_squaw

2
是的。但是,我们可以在创建临时表之前在数据帧上使用partition by。@chhantyal
Vinay Kumar

1
您如何将temporary桌子与hive桌子混合搭配?在执行操作时show tables,仅包含hive用于spark 2.3.0安装的表格
StephenBoesch

1
该临时表将保存到您的配置单元上下文中,并且不以任何方式属于配置单元表。
Vinay Kumar

1
@VinayKumar,您好,为什么说“如果您使用saveAsTable(它更像是持久保存数据帧),则必须确保为您的spark应用程序分配了足够的内存”。你能解释一下这一点吗?
enneppi

27

使用DataFrameWriter.saveAsTable。(df.write.saveAsTable(...))参见Spark SQL和DataFrame指南


4
saveAsTable不会创建与Hive兼容的表。我发现最好的解决方案是Vinay Kumar。
RChat '16

@Jacek:我自己添加了此注释,因为我认为我的答案是错误的。我会删除它,除了它被接受。您认为笔记不对吗?
丹尼尔·达拉博斯

是。笔记写错了,这就是为什么我将其删除。“请纠正我,如果我错了”在这里适用:)
Jacek Laskowski

1
df.write().saveAsTable(tableName) 还会将流数据写入表吗?
user1870400

1
不,您无法使用saveAsTable保存流数据,甚至在api中也无法保存
Brian

20

我没有df.write.saveAsTable(...)在Spark 2.0文档中看到过时的内容。它在Amazon EMR上为我们工作。我们完全能够将S3中的数据读取到数据帧中,对其进行处理,根据结果创建表并使用MicroStrategy对其进行读取。Vinays的回答也起作用了。


5
由于篇幅和内容,有人将这个答案标记为低质量。老实说,作为评论可能会更好。我想这已经有两年了,有些人发现它很有帮助,所以将事情保持原状可能会很好吗?
serakfalcon

我同意,评论本来是更好的选择。获得的经验教训:-)
亚历克斯(Alex)

15

您需要拥有/创建一个HiveContext

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

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

然后直接保存数据框或选择要存储为配置单元表的列

df是数据框

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

要么

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

要么

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

SaveModes为Append / Ignore / Overwrite / ErrorIfExists

我在此处添加了Spark文档中HiveContext的定义,

除了基本的SQLContext外,您还可以创建HiveContext,它提供基本SQLContext提供的功能的超集。其他功能包括使用更完整的HiveQL解析器编写查询,访问Hive UDF以及从Hive表读取数据的功能。要使用HiveContext,您不需要已有的Hive设置,并且SQLContext可用的所有数据源仍然可用。HiveContext仅单独打包,以避免在默认的Spark版本中包含所有Hive的依赖项。


在Spark版本1.6.2上,使用“ dbName.tableName”会出现此错误:

org.apache.spark.sql.AnalysisException:临时表不允许指定数据库名称或其他限定符。如果表名中包含点(。),请在表名中加上反引号()。


是第二个命令:'df.select(df.col(“ col1”),df.col(“ col2”),df.col(“ col3”)).write()。mode(“ overwrite”)。saveAsTable (“ schemaName.tableName”);' 要求表中已经存在要覆盖的选定列?因此,您拥有现有表,并且仅使用Spark中df的新数据覆盖现有的1,2,3列?解释正确吗?
dieHellste '16

3
df.write().mode...需要更改为df.write.mode...
用户923227 '18

8

保存到Hive只是使用write()SQLContext的方法即可:

df.write.saveAsTable(tableName)

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

从Spark 2.2:使用DataSet代替DataFrame。


我似乎有一个错误,指出工作已中止。我尝试了以下代码pyspark_df.write.mode(“ overwrite”)。saveAsTable(“ InjuryTab2”)
Sade

嗨!为什么这个?From Spark 2.2: use DataSet instead DataFrame.
onofricamila

3

抱歉,帖子发到很晚,但我没有找到答案。

df.write().saveAsTable将抛出AnalysisException并且与HIVE表不兼容。

存储DFdf.write().format("hive")应该可以解决问题!

但是,如果这不起作用,那么请按照前面的评论和答案进行操作,这是我认为最好的解决方案(尽管可以接受建议)。

最好的方法是显式创建HIVE表(包括PARTITIONED表),

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

将DF保存为临时表,

df.createOrReplaceTempView("$tempTableName")

并插入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)

当然,DF中的最后一个列将是分区列,因此相应地创建HIVE表!

如果有效,请发表评论!或不。


-更新-

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

这是PySpark版本,用于从实木复合地板文件创建Hive表。您可能已经使用推断的架构生成了Parquet文件,现在想将定义推送到Hive元存储。您还可以将定义推送到AWS Glue或AWS Athena等系统,而不仅仅是推送到Hive Metastore。在这里,我使用spark.sql来推送/创建永久表。

   # 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

对于Hive外部表,我在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

就我而言,这很好:

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

做完了!

您可以读取数据,让您作为“员工”

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

有关更多详细信息,请使用以下URL:https : //docs.cloudera.com/HDPDocuments/HDP3/HDP-3.1.5/integrating-hive/content/hive-read-write-operations.html


0

如果您要从数据框创建配置单元表(不存在)(有时无法使用创建DataFrameWriter.saveAsTable)。StructType.toDDL将有助于将列以字符串形式列出。

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_table将会在默认空间中创建,因为我们没有在提供任何数据库spark.sql()stg.hive_table可用于hive_tablestg数据库中创建。


在此处找到详细的示例:stackoverflow.com/a/56833395/1592191
mrsrinivas

0

您可以像这样使用Hortonworks spark-llap

import com.hortonworks.hwc.HiveWarehouseSession

df.write
  .format(HiveWarehouseSession.HIVE_WAREHOUSE_CONNECTOR)
  .mode("append")
  .option("table", "myDatabase.myTable")
  .save()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.