sqlite3:连接到云中的数据库 (S3)
sqlite3: Connect to a database in cloud (S3)
我在 s3 存储桶中有一个小的 sqlite 数据库 (110kb)。每次我 运行 我的 python 应用程序时,我都想连接到该数据库。
一个选项是每次我 运行 python 应用程序时下载数据库并正常连接它。 但是 我想知道是否存在使用 S3FileSystem
和 open
通过内存连接到该 sqlite 数据库的方法。我正在使用 sqlite3
库和 python 3.6
不,无法直接连接到存储在云端的 sqlite 数据库。即使您想将数据库托管在内存中,也必须在加载到内存之前将其完全下载。要做到这一点仍然需要首先从 disc-based 文件加载数据库或使用 DDL 命令直接在内存中创建它。据我所知,无法将数据流加载为 sqlite in-memory 数据库(参见 Example 1: Loading and Saving In-Memory Databases)。
在这种情况下,一旦数据库断开连接,就需要re-uploaded到云存储。 S3FileSystem.open
只是returns一个数据流。流允许您做的就是将文件下载到本地存储,以便可以在本地打开/操作它。
如果您确实需要云数据库,则需要研究另一种托管数据库。
如其他答案所示,您可能不想使用 SQLite 作为云中的主数据库。
但是,作为一个有趣的副项目的一部分,我编写了一个允许您查询的 Amazon Athena 数据源连接器 SQLite databases in S3 from Athena。为此,我为 S3 编写了一个只读 SQLite 接口。
SQLite有一个OS Interface or VFS. Using a Python SQLite wrapper called APSW的概念,你可以为任意文件系统编写一个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 实施(S3 连接需要 APSW 库和 boto3)
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)
如果您的所有操作都仅限于从 SQLite 读取,我想这是可能的。但我不知道是否也可以写作。
就我而言,我使用的是 gdal(需要 libgdal),而 gdal 的 /vsis3、/vsis3-streaming(基于 /vsicurl)使您能够从云端读取 SQLite 和许多其他数据源。如果你想使用原始 SQLite 而不是基于 gdal 的数据源层,你可以通过 gdal 的 API 将它们写入本地数据库,但是,如果是这样,为什么不下载它并阅读它呢?
对我来说,因为我正在处理空间数据并且 gdal 的 DataSource 提供了很多 APIs 来操作空间数据,所以这种方法工作正常。我仍在寻找一种写入基于云的 SQLite 的好方法。
仅供参考,这是gdal虚拟文件系统的文档
https://gdal.org/user/virtual_file_systems.html
是的,使用 EFS 是可能的:
https://www.lambrospetrou.com/articles/aws-lambda-and-sqlite-over-efs/
AWS 最近发布了 AWS Lambda 和 Amazon EFS 之间的集成。
它支持 SQLite 所需的 NFSv4 锁 upgrading/downgrading。
这意味着 SQLite 引擎可以 read/write 访问存储在 EFS 文件系统上的文件。
(灵感来自 )
如果数据库只是用于读取,则有https://github.com/michalc/sqlite-s3-query(完全公开:由我编写)
修改自述文件中的示例,假设您在 eu-west-2
中的存储桶 my-bucket
中有 my-db.sqlite
(以及环境变量中的凭据):
from sqlite_s3_query import sqlite_s3_query
with \
sqlite_s3_query(url='https://my-bucket.s3.eu-west-2.amazonaws.com/my-db.sqlite') as query, \
query('SELECT * FROM my_table WHERE my_column = ?', params=('my-value',)) as (columns, rows):
for row in rows:
print(row)
我在 s3 存储桶中有一个小的 sqlite 数据库 (110kb)。每次我 运行 我的 python 应用程序时,我都想连接到该数据库。
一个选项是每次我 运行 python 应用程序时下载数据库并正常连接它。 但是 我想知道是否存在使用 S3FileSystem
和 open
通过内存连接到该 sqlite 数据库的方法。我正在使用 sqlite3
库和 python 3.6
不,无法直接连接到存储在云端的 sqlite 数据库。即使您想将数据库托管在内存中,也必须在加载到内存之前将其完全下载。要做到这一点仍然需要首先从 disc-based 文件加载数据库或使用 DDL 命令直接在内存中创建它。据我所知,无法将数据流加载为 sqlite in-memory 数据库(参见 Example 1: Loading and Saving In-Memory Databases)。
在这种情况下,一旦数据库断开连接,就需要re-uploaded到云存储。 S3FileSystem.open
只是returns一个数据流。流允许您做的就是将文件下载到本地存储,以便可以在本地打开/操作它。
如果您确实需要云数据库,则需要研究另一种托管数据库。
如其他答案所示,您可能不想使用 SQLite 作为云中的主数据库。
但是,作为一个有趣的副项目的一部分,我编写了一个允许您查询的 Amazon Athena 数据源连接器 SQLite databases in S3 from Athena。为此,我为 S3 编写了一个只读 SQLite 接口。
SQLite有一个OS Interface or VFS. Using a Python SQLite wrapper called APSW的概念,你可以为任意文件系统编写一个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 实施(S3 连接需要 APSW 库和 boto3)
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)
如果您的所有操作都仅限于从 SQLite 读取,我想这是可能的。但我不知道是否也可以写作。 就我而言,我使用的是 gdal(需要 libgdal),而 gdal 的 /vsis3、/vsis3-streaming(基于 /vsicurl)使您能够从云端读取 SQLite 和许多其他数据源。如果你想使用原始 SQLite 而不是基于 gdal 的数据源层,你可以通过 gdal 的 API 将它们写入本地数据库,但是,如果是这样,为什么不下载它并阅读它呢?
对我来说,因为我正在处理空间数据并且 gdal 的 DataSource 提供了很多 APIs 来操作空间数据,所以这种方法工作正常。我仍在寻找一种写入基于云的 SQLite 的好方法。
仅供参考,这是gdal虚拟文件系统的文档 https://gdal.org/user/virtual_file_systems.html
是的,使用 EFS 是可能的:
https://www.lambrospetrou.com/articles/aws-lambda-and-sqlite-over-efs/
AWS 最近发布了 AWS Lambda 和 Amazon EFS 之间的集成。 它支持 SQLite 所需的 NFSv4 锁 upgrading/downgrading。 这意味着 SQLite 引擎可以 read/write 访问存储在 EFS 文件系统上的文件。
(灵感来自
如果数据库只是用于读取,则有https://github.com/michalc/sqlite-s3-query(完全公开:由我编写)
修改自述文件中的示例,假设您在 eu-west-2
中的存储桶 my-bucket
中有 my-db.sqlite
(以及环境变量中的凭据):
from sqlite_s3_query import sqlite_s3_query
with \
sqlite_s3_query(url='https://my-bucket.s3.eu-west-2.amazonaws.com/my-db.sqlite') as query, \
query('SELECT * FROM my_table WHERE my_column = ?', params=('my-value',)) as (columns, rows):
for row in rows:
print(row)