sqlite3:连接到云中的数据库(S3)

时间:2019-06-26 16:04:30

标签: python python-3.x sqlite amazon-s3 in-memory-database

我在s3存储桶中有一个小的sqlite数据库(110kb)。每当我运行 python 应用程序时,我都想连接到该数据库。

一个选择是每次我运行 python 应用程序并正常连接时下载数据库。 但是,我想知道是否存在使用S3FileSystemopen通过内存连接到该sqlite数据库的方法。我正在使用sqlite3库和python 3.6

4 个答案:

答案 0 :(得分:2)

否,无法直接连接到存储在云中的sqlite数据库。即使您希望将数据库托管在内存中,也必须在将其加载到内存之前将其完全下载。为此,仍然需要首先从基于磁盘的文件中加载数据库,或者使用DDL命令直接在内存中创建数据库。据我所知,无法将数据流作为sqlite内存数据库进行加载(请参见Example 1: Loading and Saving In-Memory Databases)。

在这种情况下,一旦数据库断开连接,则需要将其重新上传到云存储。 S3FileSystem.open仅返回数据流。流中所有您需要做的就是将文件下载到本地存储,以便可以在本地打开/操作。

如果您确实需要云数据库,则需要查看另一种托管数据库。

答案 1 :(得分:1)

正如其他答案所示,您可能不想将SQLite用作云中的主数据库。

但是,作为一个有趣的附加项目的一部分,我编写了一个Amazon Athena数据源连接器,该连接器使您可以查询SQLite databases in S3 from Athena。为此,我为S3编写了一个只读SQLite接口。

SQLite具有OS Interface or VFS的概念。使用称为APSW的Python SQLite包装器,您可以为任意文件系统编写VFS实现。这是我在项目中所做的,并且包含了以下实现。

要使用此功能,您首先需要注册VFS,然后使用此实现作为驱动程序创建一个新的SQLite连接。

我应该注意,这根本没有优化,因此可能仍然需要根据您的查询从S3中读取完整的数据库。但是在这种特定情况下听起来并不像是一个问题。

S3FS = S3VFS()  # S3VFS defined below

# This odd format is used due to SQLite requirements
sqlite_uri = "file:/{}/{}.sqlite?bucket={}&immutable=1".format(
  S3_PREFIX,
  DATABASE_NAME,
  S3_BUCKET
)

connection = apsw.Connection(sqlite_uri,
  flags=apsw.SQLITE_OPEN_READONLY | apsw.SQLITE_OPEN_URI,
  vfs=S3FS.vfsname
)
cursor = connection.cursor()

一旦有了游标,就可以执行标准的SQL语句,如下所示:

for x,y,z in cursor.execute("select x,y,z from foo"):
    print (cursor.getdescription())  # shows column names and declared types
    print (x,y,z)

VFS实现(需要APSW库和boto3才能实现S3连接)

import apsw
import sys
import boto3

VFS_S3_CLIENT = boto3.client('s3')


class S3VFS(apsw.VFS):
    def __init__(self, vfsname="s3", basevfs=""):
        self.vfsname=vfsname
        self.basevfs=basevfs
        apsw.VFS.__init__(self, self.vfsname, self.basevfs)

    def xOpen(self, name, flags):
        return S3VFSFile(self.basevfs, name, flags)


class S3VFSFile():
    def __init__(self, inheritfromvfsname, filename, flags):
        self.bucket = filename.uri_parameter("bucket")
        self.key = filename.filename().lstrip("/")
        print("Initiated S3 VFS for file: {}".format(self._get_s3_url()))

    def xRead(self, amount, offset):
        response = VFS_S3_CLIENT.get_object(Bucket=self.bucket, Key=self.key, Range='bytes={}-{}'.format(offset, offset + amount))
        response_data = response['Body'].read()
        return response_data

    def xFileSize(self):
        client = boto3.client('s3')
        response = client.head_object( Bucket=self.bucket, Key=self.key)
        return response['ContentLength']

    def xClose(self):
        pass

    def xFileControl(self, op, ptr):
        return False

    def _get_s3_url(self):
        return "s3://{}/{}".format(self.bucket, self.key)

答案 2 :(得分:0)

如果从SQLite读取内容时您的所有操作受到限制,我想这是可能的。但是我不知道写作是否还可以。 就我而言,我使用的是gdal(需要libgdal),而gdal的/ vsis3,/ vsis3-streaming(基于/ vsicurl)使您能够从云中读取SQLite和许多其他数据源。如果您要使用原始SQLite而不是基于gdal的数据源层,则可以通过gdal的API将它们写入本地数据库,但是,如果是这样,为什么不下载并读取它呢?

对我来说,由于我正在处理空间数据,而gdal的DataSource提供了许多用于处理空间数据的API,因此此方法可以正常工作。我仍在寻找写到基于云的SQLite的好方法。

仅供参考,这是gdal虚拟文件系统的文档 https://gdal.org/user/virtual_file_systems.html

答案 3 :(得分:0)

是的,可以使用EFS:

https://www.lambrospetrou.com/articles/aws-lambda-and-sqlite-over-efs/

AWS最近发布了AWS Lambda与Amazon EFS之间的集成。 它支持SQLite所需的NFSv4锁升级/降级。 这意味着SQLite引擎可以对存储在EFS文件系统上的文件具有读/写访问权限。