Опции только для чтения бинарных файловых хранилищ с использованием Python

Передо мной была поставлена ​​задача настроить базу данных SKU с плоскими файлами для использования на встроенных устройствах с ограниченной памятью и скоростью процессора.

В основном данные, которые мне нужно хранить, состоят из следующего:

Артикул Описание Расположение Цена Кол во

Файл будет состоять из нескольких миллионов записей.

Наиболее важные соображения - это место для хранения и время поиска. Записи должны быть извлечены только из SKU, и это будет только для чтения, поэтому файл может быть отсортирован по SKU.

Я хотел бы получить доступ к этим данным с помощью Python. Так что мои вопросы сводятся к этому.

Существуют ли библиотеки Python, которые могут предоставить мне эту функциональность, или мне нужно развернуть свою собственную?

Если ответ сводится к моему собственному, есть ли у кого-нибудь предложения или хорошие рекомендации для этого?

6 ответов

Решение

Как насчет SQLite с привязками Python? Он имеет немного больше, чем нужно, но это стандартное программное обеспечение и хорошо проверено.

Старый способ - использовать простую таблицу данных ключ / значение, такую ​​как модуль gdbm. Python поставляется с поддержкой этого, но он не встроен в установку Python по умолчанию на моем компьютере.

В общем, используйте SQLite. Как писали другие, он входит в стандартную комплектацию Python и уже используется во многих встроенных системах.

Если записи имеют фиксированную длину, вы можете использовать модуль bisect. Размер файла / размер записи дает количество записей в файле. Биссектный поиск выполнит поиск O(log(n)) в файле, и вам потребуется написать адаптер для проверки на равенство. Хотя я не проверял это, вот эскиз:

import bisect

RECORD_SIZE = 50

class MatchFirst10Chars(object):
    def __init__(self, word):
        self.word = word
    def __lt__(self, other):
        return self.word < other[:10]

class FileLookup(object):
    def __init__(self, f):
        self.f = f
        f.seek(0, 2)
        self.size = f.tell() // RECORD_SIZE
    def __len__(self):
        return self.size

    def __getitem__(self, i):
        self.f.seek(i*RECORD_SIZE)
        return self.f.read(RECORD_SIZE)


SKU = "123-56-89 "
f = open("data_file")
fl = FileLookup(f)
i = bisect.bisect(fl, MatchFirst10Chars(SKU))

Вы можете дополнительно сжать файл и искать файл в формате gzip, но это компромисс между пространством и временем, который вам придется проверить.

Могу ли я предложить CDB? (Привязки Python: python-cdb.)

Это формат, используемый для данных только для чтения, как у вас; в основном это 256 гигантских хеш-таблиц, каждая из которых может иметь различное количество сегментов. Крутая вещь в cdb заключается в том, что файл не нужно загружать в память; он структурирован таким образом, что вы можете делать поиск, просто mmapв битах, которые вам нужны.

Спецификация cdb хорошо читается, не в последнюю очередь потому, что строки отформатированы для создания равномерного правого поля.:-D

Как насчет HDF? Если вам не нужен SQL и требуется быстрый доступ к вашим данным, в Python нет ничего быстрее... для числовых или структурированных данных.

Взгляните на раздел DatabaseInterfaces в Python вики. Это всеобъемлющее. Есть несколько "чистых" опций Python (например, SnakeSQL), которые немного удобнее для развертывания. И, конечно же, всегда есть Berkeley DB и тому подобное, которые являются супер худыми и сырыми.

Честно говоря, SQLite, вероятно, будет хорошо работать для вас. Если вам действительно нужно добиться большей производительности, то вы бы выбрали формат, основанный на записях, такой как BDB.

Вариант ответа Эндрю Далке (так что вы все еще можете использовать бинарный поиск для быстрого поиска SKU), который может уменьшить требования к пространству, заключался бы в том, чтобы иметь записи фиксированного размера в начале файла (по одному на SKU), а затем все описания и Местоположения (как говорят строки с нулевым символом в конце)

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

Вот пример: скажем, у вас есть

SKU         16 bytes
Description Variable length
Location    Variable length
Price       4 bytes (up to $42949672.95)
Quantity    4 bytes (up to 4294967295)



 offset          SKU        desc_off   loc_off      Price      Quantity
0x00000000 SKU0000000000001 0x01f78a40 0x01f78a47  0x000003e8  0x000f4240
0x00000020 SKU0000000000002 0x01f78a53 0x01f78a59    ...
...
... # 999998 more records
...
0x01f78a40 Widget\x00
0x01f78a47 Head office\x00
0x01f78a53 Table\x00
0x01f78a59 Warehouse\x00

Простое решение - CPickle. Вы также можете найти похожие вопросы на SO.

Другие вопросы по тегам