จะบันทึก DataFrame ลงใน Hive ได้อย่างไร?


85

เป็นไปได้ไหมที่จะบันทึกเป็นDataFrameประกายโดยตรงไปยัง Hive?

ฉันได้ลองแปลงDataFrameเป็นRddแล้วบันทึกเป็นไฟล์ข้อความจากนั้นโหลดในกลุ่ม แต่ฉันสงสัยว่าฉันสามารถบันทึกdataframeลงในรังได้โดยตรงหรือไม่

คำตอบ:


118

คุณสามารถสร้างตารางชั่วคราวในหน่วยความจำและเก็บไว้ในตารางไฮฟ์โดยใช้ sqlContext

สมมติว่า data frame ของคุณคือ myDf คุณสามารถสร้างตารางชั่วคราวโดยใช้

myDf.createOrReplaceTempView("mytempTable") 

จากนั้นคุณสามารถใช้คำสั่งกลุ่มง่ายๆเพื่อสร้างตารางและถ่ายโอนข้อมูลจากตารางชั่วคราวของคุณ

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

2
สิ่งนี้มีข้อผิดพลาดในการอ่านปาร์เก้ที่ฉันได้รับเมื่อใช้ write.saveAsTable ใน spark 2.0
ski_squaw

2
ใช่อย่างไรก็ตามเราสามารถใช้พาร์ติชันโดยบน data frame ก่อนสร้างตารางชั่วคราว @chhantyal
Vinay Kumar

1
คุณสามารถผสมและจับคู่temporaryโต๊ะกับhiveโต๊ะได้อย่างไร? เมื่อดำเนินการshow tablesดังกล่าวรวมเฉพาะhiveตารางสำหรับspark 2.3.0การติดตั้งของฉัน
StephenBoesch

1
ตารางชั่วคราวนี้จะถูกบันทึกลงในบริบทกลุ่มของคุณและไม่ได้เป็นของตารางรัง แต่อย่างใด
Vinay Kumar

1
สวัสดี @VinayKumar ทำไมคุณถึงพูดว่า "ถ้าคุณใช้ saveAsTable (มันเหมือนกับการคงกรอบข้อมูลของคุณไว้) คุณต้องแน่ใจว่าคุณมีหน่วยความจำเพียงพอที่จัดสรรให้กับแอปพลิเคชัน Spark ของคุณ" คุณช่วยอธิบายประเด็นนี้ได้ไหม
enneppi

28

ใช้DataFrameWriter.saveAsTable. ( df.write.saveAsTable(...)) ดูSQL Spark และ DataFrame คู่มือ


4
saveAsTable ไม่สร้างตารางที่เข้ากันได้กับ Hive ทางออกที่ดีที่สุดที่ฉันพบคือ Vinay Kumar
RChat

@Jacek: ฉันได้เพิ่มบันทึกนี้ด้วยตัวเองเพราะฉันคิดว่าคำตอบของฉันผิด ฉันจะลบมันยกเว้นว่ามันได้รับการยอมรับ คุณคิดว่าโน้ตผิดหรือไม่?
Daniel Darabos

ใช่. โน้ตผิดจึงลบออก "กรุณาแก้ไขฉันถ้าฉันผิด" ใช้ที่นี่ :)
Jacek Laskowski

1
จะdf.write().saveAsTable(tableName) เขียนข้อมูลสตรีมลงในตารางด้วยหรือไม่
user1870400

1
ไม่คุณไม่สามารถบันทึกข้อมูลสตรีมด้วย saveAsTable มันไม่ได้อยู่ใน api ด้วยซ้ำ
Brian

21

ฉันไม่เห็นว่าdf.write.saveAsTable(...)เลิกใช้แล้วในเอกสาร Spark 2.0 มันได้ผลสำหรับเราใน Amazon EMR เราสามารถอ่านข้อมูลจาก S3 ลงใน dataframe ได้อย่างสมบูรณ์ประมวลผลสร้างตารางจากผลลัพธ์และอ่านด้วย MicroStrategy คำตอบของ Vinays ก็ใช้ได้เช่นกัน


5
มีคนแจ้งว่าคำตอบนี้มีคุณภาพต่ำเนื่องจากความยาวและเนื้อหา พูดตามตรงมันน่าจะดีกว่าในความคิดเห็น ฉันเดาว่ามันเป็นเวลาสองปีแล้วและบางคนพบว่ามันมีประโยชน์ดังนั้นอาจเป็นการดีที่จะปล่อยให้สิ่งต่างๆเป็นอยู่
serakfalcon

ฉันเห็นด้วยความคิดเห็นน่าจะเป็นทางเลือกที่ดีกว่า บทเรียนที่ได้เรียนรู้ :-)
อเล็กซ์

15

คุณต้องมี / สร้าง HiveContext

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

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

จากนั้นบันทึกดาต้าเฟรมโดยตรงหรือเลือกคอลัมน์เพื่อจัดเก็บเป็นตารางรัง

df คือ dataframe

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

ฉันเพิ่มคำจำกัดความสำหรับ HiveContext จาก Spark Documentation ที่นี่

นอกจาก SQLContext พื้นฐานแล้วคุณยังสามารถสร้าง HiveContext ซึ่งจัดเตรียมส่วนเหนือของฟังก์ชันที่จัดเตรียมโดย SQLContext พื้นฐาน คุณสมบัติเพิ่มเติม ได้แก่ ความสามารถในการเขียนแบบสอบถามโดยใช้ตัวแยกวิเคราะห์ HiveQL ที่สมบูรณ์ยิ่งขึ้นการเข้าถึง Hive UDFs และความสามารถในการอ่านข้อมูลจากตาราง Hive ในการใช้ HiveContext คุณไม่จำเป็นต้องมีการตั้งค่า Hive ที่มีอยู่และแหล่งข้อมูลทั้งหมดที่มีอยู่ใน SQLContext จะยังคงมีอยู่ HiveContext ได้รับการบรรจุแยกต่างหากเพื่อหลีกเลี่ยงการรวมการอ้างอิงทั้งหมดของ Hive ใน Spark build เริ่มต้น


บน Spark เวอร์ชัน 1.6.2 โดยใช้ "dbName.tableName" ทำให้เกิดข้อผิดพลาดนี้:

org.apache.spark.sql.AnalysisException: ไม่อนุญาตให้ระบุชื่อฐานข้อมูลหรือคุณสมบัติอื่น ๆ สำหรับตารางชั่วคราว หากชื่อตารางมีจุด (.) อยู่ในนั้นโปรดอ้างอิงชื่อตารางด้วย backticks ()`


เป็นคำสั่งที่สอง: 'df.select (df.col ("col1"), df.col ("col2"), df.col ("col3")) .write (). mode ("overwrite"). saveAsTable ("schemaName.tableName"); ' ต้องการให้คอลัมน์ที่เลือกที่คุณต้องการเขียนทับมีอยู่แล้วในตาราง? ดังนั้นคุณจึงมีตารางที่มีอยู่และคุณเขียนทับคอลัมน์ที่มีอยู่แล้วเพียง 1,2,3 ด้วยข้อมูลใหม่จาก df ของคุณในจุดประกาย? แปลว่าถูกไหม
dieHellste

3
df.write().mode...ต้องเปลี่ยนเป็นdf.write.mode...
ผู้ใช้ 923227

8

การบันทึกไปยังไฮฟ์เป็นเพียงเรื่องของการใช้write()วิธีการ SQLC ของคุณ

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


ดูเหมือนว่าฉันจะมีข้อผิดพลาดที่แจ้งว่า Job ถูกยกเลิก ฉันลองใช้รหัสต่อไปนี้ pyspark_df.write.mode ("overwrite") saveAsTable ("InjuryTab2")
Sade

ไฮ! ทำไมถึงเป็นเช่นนี้? From Spark 2.2: use DataSet instead DataFrame.
onofricamila

3

ขออภัยที่เขียนโพสต์ช้า แต่ไม่พบคำตอบ

df.write().saveAsTableจะโยนAnalysisExceptionและไม่เข้ากันได้กับตาราง HIVE

การจัดเก็บ DF df.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)

นำเสนอLAST COLUMNใน DF จะเป็นPARTITION COLUMNดังนั้นให้สร้างตาราง HIVE ตามนั้น!

โปรดแสดงความคิดเห็นว่ามันได้ผล! หรือไม่.


- UPDATE--

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 สำหรับสร้างตารางไฮฟ์จากไฟล์ปาร์เก้ คุณอาจสร้างไฟล์ Parquet โดยใช้สคีมาที่สรุปแล้วและตอนนี้ต้องการส่งคำจำกัดความไปยัง Hive metastore คุณยังสามารถส่งคำจำกัดความไปยังระบบเช่น AWS Glue หรือ AWS Athena และไม่ใช่แค่การแพร่กระจายของ Hive เท่านั้น ที่นี่ฉันใช้ 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

คุณสามารถใช้ไลบรารีspark-llap ของ Hortonworks ได้เช่นนี้

import com.hortonworks.hwc.HiveWarehouseSession

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

-1

หากคุณต้องการสร้างตารางไฮฟ์ (ซึ่งไม่มีอยู่) จากดาต้าเฟรม (บางครั้งก็ไม่สามารถสร้างด้วย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_tableในstgฐานข้อมูล


ดูตัวอย่างโดยละเอียดได้ที่นี่: stackoverflow.com/a/56833395/1592191
mrsrinivas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.