пятница, 22 января 2010 г.

kvlite или KeyValue datastore на базе sqlite3

Надеюсь не будет большим преувеличением если скажу, что sqlite одна из самых распространенных баз данных. Ее можно встреть:
- в мобильных телефонах Nokia, Google Android, Apple iPhone
- в броузерах Firefox, Safari, Chrome
- в приложениях таких компаний как Adobe, Google, McAfee, Microsoft, Skype, Sun, ...
- в сервисах Dropbox
- поддержка включена в языки программирования Python, PHP, REALbasic, ...


sqlite в своей практике я использую практически каждый день. Это и простейшие базы данных, всевозможные обработчики, сборщики информации, временные хранилища данных. Достаточно простая и быстрая база данных. И что самое главное, совершенно не нужна инсталляция. Существуют большое количество бесплатных приложений под различные операционные системы для работы как с консоли так и в GUI.

Для меня наибольший интерес представляет возможность работы с sqlite из python. Его поддержка включена в интерпретатор начиная с версии 2.5. В целом все устраивает, но есть на мой взгляд несколько неудобств:
- сложности в изменении схемы базы данных. По правде сказать, это касается всех реляционных баз данных, а не только sqlite.
- Блокировки базы: SQLite uses reader/writer locks on the entire database file. That means if any process is reading from any part of the database, all other processes are prevented from writing any other part of the database. Similarly, if any one process is writing to the database, all other processes are prevented from reading any other part of the database.

Попыткой исправить данные неудобства или скажем минимизировать их и стал проект, который я назвал как kvlite. kvlite - это оболочка над sqlite, которая позволяет хранить данные в виде пары ключ-значение на каждое поле. Каждая пара хранится в отдельном файле базы данных, что позволит уменьшить время блокировки файла. А чтобы добавить новое поле в базу достаточно будет создать объект класса KeyValue, который позволяет работать с парами ключ-значение.

Возможности класса:

- создание файла БД sqlite для пары ключ/значение, где в качестве параметров передаются: путь, где будет или уже находится файл sqlite; имя поля и его тип. Расширение ".sql3" добавляется по умолчанию. Если файл с таким именем уже существует, считается что пара уже создана.
kv = KeyValue(path='store', name='field_int', value_type='INTEGER')
- для добавления значений используется метод put. Добавление возможно по одному значению:
kv.put(1)
kv.put(2)
...
kv.put(9)
списком:
kv.put((1,2,3))
либо парой ключ/значение в виде словаря:
kv.put(('key1':1,'key2':2,'key3':3))
при добавлении по одному значению или списком, значение ключа назначается автоматически.

- для удаления используется метод delete. Возможно путем передачи ключей (как одного, так и нескольких в виде списка):
kv.delete('3f558154-96da-4619-8428-23733054cfb6')
kv.delete(('3f558154-96da-4619-8428-23733054cfb7', 3f558154-96da-4619-8428-23733054cfb8))
- выборка всех записей ключ/значение
kv.all()
- выполнение SQL запроса. Данные хранятся в таблице kv c двумя полями, где k - поле ключа, v - поле значения
kv.sql('SELECT * FROM kv WHERE v LIKE "%test%"')
- по умолчанию sqlite использует транзакции, соответственно для сохранения изменений необходимо вызвать commit
kv.commit()
Проект только начал свое существование, так что любая помощь советом/идеей как улучшить/исправления и т.д. всегда приветствуется. Вы можете помочь даже указав ссылки на похожие проекты (python+sqlite3).

Домашняя страница проекта http://code.google.com/p/kvlite/

7 комментариев:

  1. А каких размеров предполагается keyset ? Большое кол-во файлов в директории - это намного хуже (ext?,ntfs), чем global lock на DB.

    ОтветитьУдалить
  2. Файлов в директории будет не много. Хотя конечно зависит от числа полей. Для уменьшения числа файлов в директории можно применять логическую разбивку по типу хранимых данных. Например для хранения контактов:

    contacts/
    - firstname.sql3
    - lastname.sql3
    - email.sql3
    - phone.sql3
    - fax.sql3
    ...

    ОтветитьУдалить
  3. Для книг может быть назначена другая директория:

    books/
    - name.sql3
    - author.sql3
    - publisher.sql3
    ...

    ОтветитьУдалить
  4. А как это сказывается на памяти? БД в памяти, это не только данные, но и сами структуры, которые могут быть достаточно сложными (например: B-trie, Hashtable).
    Кстати, в классической k-v БД для чтения ключа используется get(k), а для чтения всех клучей или k-v тюплов что-то вроде keys/values/dataset. Зачем там sql ?!

    з.ы. Чего-то комменарии мои исчезают (Я писал о "Ходе конем", а комментарий пропал) ?

    ОтветитьУдалить
  5. Если сравнивать классическую реляционную базу и k-v, то конечно же k-v занимает больше памяти. Хотя бы тем, что на каждое значение приходится еще и ключ. Но это цена schemaless решения.

    SQL нужен для sqlite3, он является backend-ом, а kvite всего лишь оболочка над ним.

    P.S. Вообще-то странно, я не получил даже нотификации об оставленном комментарии на "ход конем". Если не сложно, повтори пожалуйста. Мне интересно твое мнение

    ОтветитьУдалить
  6. Я имел в виду, что k-v база должна прятать поднаготную "механику":
    Вместо kv.sql('SELECT * FROM kv WHERE v LIKE "%test%"')
    я бы ожидал:
    kv.values();
    Вдобавок kv.put(1) является нарушением идеологии k-v
    :-)

    ОтветитьУдалить
  7. метод sql по большей "так на всякий случай". В будущем конечно же правильней будет его скрыть.

    Основные методы - это get, put, delete, filter.

    kv.put(1) - согласен, не красиво. Но данный подход и не будет использоваться. Скоро выйдет новый модуль Store, который будет объединять пары ключ/значения. Надеюсь с его выходом перенести и документацию на http://code.google.com/p/kvlite/

    ОтветитьУдалить