Python и NoSQL: MongoDB Python 19.11.2010

mongodb.png Это вторая часть из цикла статей про python и NoSQL (первая - про redis).

Теория

MongoDB один из представителей класса NoSQL (Not Only SQL), относится к документно-ориентированным базам данных с не фиксированной схемой данных. Проект является open-source и написан на C++. Для обмена данными с клиентом используется JSON, а данные хранятся в двоичном формате BSON.

Основной структурной единицей в MongoDB есть документ - упорядоченный набор ключей с связанными значениями. Документы в MongoDB представлены абстрактным типом данных, а конкретная реализация зависит от используемого драйвера. Сами документы хранятся в BJON, бинарном формате, который может хранить документы, как последовательность байтов. Пример представление документа на JavaScript*, в виде объекта:

{"firstword" : "Hello world!"}

MongoDB поддерживает шесть типов данных (null, boolean, numeric, string, array и object.) и является type-sensitive и case-sensitive.

В иерархии структур данных, в MongoDB, над документами находятся - коллекции, которые представляют собой группы документов. Если провести аналогию с таблицами в реляционных БД, то документы будут рядами, а коллекции - таблицами.

Существуют некоторые ограничения в MongoDB: за раз можно вставить 16MB данных, размер документов не может превышать 4MB, размер данных для 32-битной версии mongod ограничен до ~2.5 GB.

В качестве storage engine в MongoDB используется memory-mapped file (отображение файла на память) со всеми вытекающими отсюда плюсами и минусами. MongoDB не подвержен атакам типа инъекции (injection attacks), т.к. не выполняет никакого кода при инсертах.

Еще про теоретическую часть о MongoDB:

Сравнение с другими типами БД:

Нагрузочное тестирование есть тут. Список компаний, использующих MongoDB в продакшене.

Пощупать MongoDB можно на try.mongodb.org, а тут есть cheat sheet по командам.

Установка

Установим MongoDB на Ubuntu. Описание установки на Centos/Fedora/RedHat есть тут.

Берем последнюю стабильную версию отсюда.

wget http://fastdl.mongodb.org/linux/mongodb-linux-i686-1.6.3.tgz

Распаковываем:

tar -xvf mongodb-linux-i686-1.6.3.tgz -C /opt/

Создадим папку для данных и файл для логов

sudo mkdir /var/lib/mongodb/
sudo chown `id -u` /var/lib/mongodb/

sudo touch /var/log/mongodb.log
sudo chown `id -u` /var/log/mongodb.log

Создадим конфигурационный файл для mongod

sudo vim /etc/mongod.conf

и запишем в него

port = 5586
fork = true # daemonize it!
logpath = /var/log/mongodb.log
dbpath = /var/lib/mongodb/

теперь создадим скрипт для запуска mongod с выше определенными параметрами

sudo vim /usr/bin/mongod

и запишем в него

/opt/mongodb-linux-i686-1.6.3/bin/mongod --config /etc/mongod.conf

настроем права

sudo chown `id -u` /usr/bin/mongod
sudo chmod ug+x /usr/bin/mongod
sudo chown `id -u` /etc/mongod.conf

Все, можно запускать демон с помощью mongod.

Запустим shell и попробую что-то сделать:

/opt/mongodb-linux-i686-1.6.3/bin/mongo --port 5586

> db.test.save({message:'mongodb'})                 
> db.test.save({message:'nosql'})  
> db.test.find()
{ "_id" : ObjectId("4cdeadbd637b7e915544335a"), "message" : "mongodb" }
{ "_id" : ObjectId("4cdeadc3637b7e915544335b"), "message" : "nosql" }

Использование с Python

Для работы Python с MongoDB существует базовый модуль pymongo (документация). На базе pymongo построены два известных ODM: mongokit и mongoengine. Хорошие сравнение mongokit vs mongoengine есть тут. Еще один ODM - mongoalchemy.

Установим последнюю версию pymongo

pip install pymongo

Для примера возьмем две сущности Киноман и Фильм. Каждый киноман имеет собственную оценку по фильму, посчитаем (с помощью map/reduce) среднюю оценку по фильму.

# coding=utf-8

from pymongo import Connection
from pymongo.code import Code

# создадим соединение 
connection = Connection('localhost', 5586)

# очистим БД
connection.drop_database('cinephiles')

# создадим БД
db = connection.cinephiles

# создадим коллекции для films и users
films = db.films
users = db.users

# создадим новые документы с данными о сущности 'Фильм'
films.insert([{'_id':1, 'title':'The Expendables', 'release':2010}, {'_id':2, 'title':'Iron Man 2', 'release':2010}, {'_id':3, 'title':'Prince of Persia', 'release':2010}])

# выведем список со всеми фильмами
for film in films.find():
    print film

# создадим новые документы с данными о сущности 'Киноман'
users.insert({'name': 'John', 'films':[{'film':1, 'mark':3}, {'film':2, 'mark':5}, {'film':3, 'mark':5}]})
users.insert({'name': 'Jane', 'films':[{'film':1, 'mark':4}, {'film':2, 'mark':3}, {'film':3, 'mark':5}]})
users.insert({'name': 'Sali', 'films':[{'film':1, 'mark':5}, {'film':2, 'mark':2}, {'film':3, 'mark':5}]})

# посчитаем всех киноманов
film_count = films.count()

# подготовим данные для подсчета
map = Code(""" function()  {
        this.films.forEach(
            function(x) {
                emit(x.film, x.mark);
            }
        );
    }""")

# посчитаем среднюю оценку по фильму
reduce = Code("""function (key, values) {
      var sum = 0;
      for(var mark in values) sum += values[mark];
      return sum/%d;
    }""" % film_count)

# выведем среднюю оценку по каждому фильму
result = db.users.map_reduce(map, reduce)
for mark in result.find():
    print mark

Результат:

{u'release': 2010, u'_id': 1, u'title': u'The Expendables'}
{u'release': 2010, u'_id': 2, u'title': u'Iron Man 2'}
{u'release': 2010, u'_id': 3, u'title': u'Prince of Persia'}
{u'_id': 1.0, u'value': 1.3333333333333333}
{u'_id': 2.0, u'value': 1.1111111111111112}
{u'_id': 3.0, u'value': 1.6666666666666667}

Еще хороший пример с методами pymongo есть тут.

Использование с Django

Этот раздел тут упомяну лишь вскользь, более полный вариант будет в будущей заметке.

Мониторинг и администрирование

По-умолчанию с mongod стартует простой http-сервер, по тому же адресу что и сам mongod но порт на 1000 больше, чем порт самого mongod. Этот сервер предоставляет http интерфейс для просмотра базовой информации о сервере MongoDB. Вся представленная информация в простом веб-интерфейсе также может быть получена через shell, например текущую версию сервера, uptime и количество подключений можно узнать с помощью:

> db.runCommand({"serverStatus" : 1})

В базовой поставкой MongoDB есть консольная-команда mongostat - выводит ту же инфу что и serverStatus, но в более дружественном виде.

Для web-админимтрирования MongoDB есть Opricot, подробнее можете прочитать на домашней странице.

Репликации

Другие применения MongoDB

Map Reduce

Дополнительно чтиво

Цитата
Большинство людей счастливы настолько, насколько они сами решили быть счастливы.
Авраам Линкольн
Категории
Архив