一步将数据从Postgres DB复制到AWS S3

时间:2018-12-21 15:27:38

标签: java postgresql amazon-s3

我有一个用例,用于将选定的数据从Postgres移动到Amazon S3。这应该一步完成。我正在编写一个Java程序来完成此任务。

我想出了一种分两步复制数据的方法。我使用CopyManager库和copyOut方法将数据放入本地。之后,我将使用Java将同一文件移入S3。

postgres代码将数据导入本地

CopyManager copyManager = new CopyManager((BaseConnection) con);
FileWriter fileWriter = new FileWriter("file.csv");
copyManager.copyOut("COPY (SELECT stmt) TO STDOUT WITH DELIMITER '\t' CSV HEADER", fileWriter);

从本地代码迁移到S3的AWS代码

AmazonS3 conn = new AmazonS3Client(credentials);
conn.setEndpoint("xxx.com");
conn.putObject(
            bucket1.getName(),
            "request.json",
            new File("file.csv")
    );

我希望它能一次性完成,而不是写入文件,然后将文件移至S3。

3 个答案:

答案 0 :(得分:0)

我还没有尝试过,但是我认为您应该可以做到。

您可以传递任何FileWriter,而不是将copyOut()传递给OutputStream。您还可以向InputStream方法提供putObject而不是文件。

因此,您只需要将OutputStream转换为InputStream,就可以使用许多方法(例如,参见this post),也可以使用类似{ {3}}。

答案 1 :(得分:0)

您应该将PutObjectInputStream一起使用。

您可以使用PipedOutputStreamPipedInputStream将输出重定向到putObject的输入

PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream(in);

使用in作为PutObject的参数,并开始在另一个线程中写入out

答案 2 :(得分:0)

如果您愿意使用python进行操作,则以下示例应该有效:

import boto
import gzip
import psycopg2
import tempfile

# database connection setup
connection = psycopg2.connect('postgresql://scott:tiger@localhost/mydatabase')
connection.autocommit = True
cursor = connection.cursor()

# aws connection setup
s3_connection = boto.connect_s3('<aws access key>', '<aws secret key>')
bucket = s3_connection.get_bucket('<bucket>')

with tempfile.NamedTemporaryFile() as t:
    with gzip.GzipFile(t.name, mode='wb') as g:
        cursor.copy_expert("COPY ({0}) TO STDOUT WITH CSV HEADER".format('<select_query>'), g)
    key = boto.s3.key.Key(bucket, '<s3_key>')
    key.set_contents_from_filename(g.name)

此过程利用python中的tempfile模块,该模块允许您创建一个在该过程中被使用然后删除的文件。上下文管理器(with tempfile...)简化了文件写入过程的管理,因此您不必手动删除它。根据您设置临时文件的方式,可以使系统用户可以访问该文件,或使其永不可见。基本上,您是将SELECT语句流式传输到STDOUT,然后将STDOUT写入临时文件。在内存管理,速度和访问方面,您仍然对SELECT语句着迷。

这样做的好处是,您无需将整个文件都保存在内存中,而可以尝试将其传输到S3。缺点是您需要足够的磁盘空间来临时存储文件,并且显然速度较慢,因为您正在写磁盘,而不是在内存中完成全部操作。

要注意的另一件事是,在上传之前,我保持了python使用gzip压缩文件的步骤。我这样做是为了节省上传空间;如果您要上载包含大量重复数据的表,此功能特别有用。

顺便说一句:您应该不要按原样在可以进行SQL注入的环境中使用此方法;如果这是用例的一部分,则有更好的方法来生成COPY命令。