使用复制命令-pyspark将Dataframe火花到Postgres

时间:2018-07-30 12:44:23

标签: postgresql apache-spark pyspark

我需要将Spark数据帧写入Postgres DB。 我已经使用了以下

df.write
.option("numPartitions",partions)
.option("batchsize",batchsize)
.jdbc(url=url, table="table_name", mode=append, properties=properties) 

这很好,但是,我想与“复制”命令进行比较

尝试了以下

output = io.StringIO() 

 csv_new.write
.format("csv")
.option("header", "true")
.save(path=output)

output.seek(0)
contents = output.getvalue()
cursor.copy_from(output, 'tb_pivot_table', null="") \\using psycopg2 
con_bb.commit() 

这似乎没有错误   “类型”对象不可迭代

与Pandas数据框配合良好

output= io.StringIO()
df.to_csv(path_or_buf=output,sep='\t', header=False, index=False)
output.seek(0)
contents = output.getvalue()
cursor.copy_from(output, 'tb_ts_devicedatacollection_aggregate', null="")  
con_bb.commit()

任何人都将介绍如何在Pyspark中实现等效的Pandas。 附言:它的性能至关重要,因此无法将Spark df转换为Pandas df。 任何帮助将不胜感激

2 个答案:

答案 0 :(得分:0)

据我所知,Spark没有提供内部使用 copy 命令的方法。

如果要从hdfs加载postgres,则可能对Sqoop感兴趣。它允许导出存储在hdfs上的csv。而且,它能够产生多个 copy 语句。在我的实验中,添加4个映射器与仅一个映射器相比,摄取速度提高了2倍。这应该比使用spark jdbc的方式要快。

以下是步骤:

  1. df.write.csv(“ my / hdfs / folder”)
  2.   

    sqoop导出   --connect“ jdbc:postgresql:// postgres_host / postgres_db”    - 用户名   --password文件file:///home/$USER/.password   --export-dir my_csv_table    - 表   -米4    - 直接   -行以'\ n'结尾   -以','结尾的字段   --模式

答案 1 :(得分:0)

目前对我来说效果很好的(100-200GB 的 csv 文件,大约有 1.000.000.000 行)正在使用 psycopg2 和多处理

可用内核数:200

首先,我将 spark 数据帧导出到多个文件中,这些文件是可用内核的多个文件

filepath="/base_path/psql_multiprocessing_data"

df.repartition(400) \
    .write \
    .mode("overwrite") \
    .format("csv") \ # even faster using binary format, but ok with csv
    .save(filepath,header='false')

然后我通过

并行遍历文件夹中的所有文件
import glob
import psycopg2   
from multiprocessing import Pool, cpu_count

file_path_list=sorted(glob.glob("/base_path/psql_multiprocessing_data/*.csv"))

def psql_copy_load(fileName):
    con = psycopg2.connect(database="my_db",user="my_user",password="my_password",host="my_host",port="my_port")
    cursor = con.cursor()
    with open(fileName, 'r') as f:
        # next(f)  # in case to skip the header row.
        cursor.copy_from(f, 'my_schema.my_table', sep=",")
    
    con.commit()
    con.close()
    return (fileName)
    

with Pool(cpu_count()) as p:
        p.map(psql_copy_load,file_path_list)

print("parallelism (cores): ",cpu_count())
print("files processed: ",len(file_path_list))

我没有进一步尝试将数据导出为二进制文件,因为它因正确的标题和数据类型而变得复杂,而且我对大约 25-30 分钟(6 列)的运行时间感到满意