У меня есть небольшая база данных sqlite (110 КБ) в ведро s3. Я хочу подключаться к этой базе данных каждый раз, когда запускаю свое приложение python .

Можно просто загружать базу данных каждый раз, когда я запускаю приложение python , и подключаю его как обычно. Но я хочу знать, существует ли способ подключения к этой базе данных sqlite через память, используя S3FileSystem и open. Я использую библиотеку sqlite3 и Python 3.6

3
FcknGioconda 26 Июн 2019 в 19:04

2 ответа

Лучший ответ

Нет, невозможно напрямую подключиться к базе данных sqlite, хранящейся в облаке. Даже если вы хотите разместить базу данных в памяти, она все равно должна быть полностью загружена перед загрузкой в память. Для этого по-прежнему требуется сначала загрузить базу данных из файла на диске или с помощью команд DDL, чтобы создать ее непосредственно в памяти. Насколько мне известно, нет способа загрузить поток данных в качестве базы данных sqlite в памяти (см. Пример 1 : Загрузка и сохранение баз данных в памяти).

В таком случае после отключения базы данных ее необходимо будет повторно загрузить в облачное хранилище. S3FileSystem.open просто возвращает поток данных. Все, что вам позволит поток, это загрузить файл в локальное хранилище, чтобы его можно было открывать / манипулировать локально.

Если вам действительно нужна облачная база данных, вам нужно посмотреть другую базу данных.

3
C Perkins 26 Июн 2019 в 18:18

Как показывают другие ответы, вы, вероятно, не хотите использовать SQLite в качестве основной базы данных в облаке.

Однако в рамках веселого проекта я написал коннектор источника данных Amazon Athena, который позволяет запрашивать базы данных SQLite. в S3 из Афины. Чтобы сделать это, я написал доступный только для чтения интерфейс SQLite для S3.

В SQLite есть концепция интерфейса ОС или VFS. Используя оболочку Python SQLite с именем 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)
1
dacort 21 Дек 2019 в 06:48