Работа с хранилищами данных в Google App Engine и сравнение с...

Preview:

DESCRIPTION

Доклад Михаила Кашкина для PyCamp, Киев 2010

Citation preview

Работа с Datastore, отличия от RDBM

Pycamp, Киев. 30 января 2010

Saturday, January 30, 2010

Обо мне

• Python с 2001 года

• Модератор групп: Plone, Django, Google App Engine, Erlang, Zope3

• Веду блоги http://app-engine.tumblr.com/ и http://xenru.livejournal.com/

• Разработка серверной части приложений для социальных сетей (VK.com, Facebook)

Saturday, January 30, 2010

План доклада

• Модели- Виды- Создание- Модификация

• Свойства модели• Индексы

• Ключи

• Язык запросов GQL*

Saturday, January 30, 2010

Сравнение с реляционными БД

• Расчет на то, что аудитория уже активно работает с реляционными базами данных

• Показать как решаются обычные задачи• В комментариях попытаться представить подход Datastore как шаг в развитии

Saturday, January 30, 2010

Datastore — это

• Одно из хранилищ данных Google App Engine (второе memcache)

• Масштабируемое• Распределенное• Не является реляционной БД• Что-то что заставляет вас менять привычную архитектуру приложений

Saturday, January 30, 2010

Опять на пониманиеSaturday, January 30, 2010

Схема

Saturday, January 30, 2010

Создание “таблицы”

• В Postgres или MySQL создаем модель данных потом отображаем ее на схеме базы данных

• Datastore сразу работает с моделями

Saturday, January 30, 2010

Типы моделей

• db.Model — “классическая” модель

• db.Expando — динамическая модель

• db.polymodel.PolyModel — для создания иерархических моделей

Saturday, January 30, 2010

Give it a lickSaturday, January 30, 2010

Определение модели

from google.appengine.ext import db

class Contact(db.Model): """ Мои контакты """ name = db.StringProperty() phone = db.PhoneNumberProperty() size = db.StringProperty(required=True, choices=set(["small", "norm", "big"]))

Saturday, January 30, 2010

Расширение модели

from google.appengine.ext import db

class Contact(db.Model): """ Мои контакты """ name = db.StringProperty() phone = db.PhoneNumberProperty() size = db.StringProperty(required=True, choices=set(["small", "norm", "big"])) opinion = db.FloatProperty(default=0)

Saturday, January 30, 2010

“Реальная жизнь”

• Провести какие-то важные изменения модели• Удалить поля, добавить новые, старые конвертировать

Saturday, January 30, 2010

Изменение базового класса

from google.appengine.ext import db

class Contact(db.Expando): """ Мои контакты """ name = db.StringProperty() phone = db.PhoneNumberProperty() ...

Saturday, January 30, 2010

Свойства

Saturday, January 30, 2010

Свойства/типы столбцов

• Базовых 24 вида! Включая:

• Строковые• Булевые• Бинарные• Дата/время• География

• Email / IM / Телефоны

• Ссылки• Ключи• Массивы• Целые и дробные• Blob’ы

Saturday, January 30, 2010

Свойства — больше не священная корова, а просто

говядина!

Saturday, January 30, 2010

Привет, пупсы!

Saturday, January 30, 2010

Реальные примеры

• Вычислимые свойства на основе исходных значений других свойств

• Свойства доступные только текущему домену•

Saturday, January 30, 2010

Как это делаетсяclass PickleProperty(db.Property): """ Пример своего свойства """ data_type = db.Blob def get_value_for_datastore(self, model_instance): value = self.__get__(model_instance, model_instance.__class__) if value is not None: return db.Blob(pickle.dumps(value)) def make_value_from_datastore(self, value): if value is not None: return pickle.loads(str(value))

def default_value(self): return copy.copy(self.default)

Saturday, January 30, 2010

В действии>>> class PickleModel(db.Model):... data = PickleProperty()

>>> model = PickleModel()>>> model.data = {"foo": "bar"}>>> model.data{'foo': 'bar'}>>> model.put() datastore_types.Key.from_path(u'PickleModel', ...)

>>> model2 = PickleModel.all().get()>>> model2.data{'foo': 'bar'}

Saturday, January 30, 2010

Свойства внутри

• Есть определенный базовый набор типов значений (их видно в консоли программиста)

• Есть определенный порядок сортировки в индексах

Saturday, January 30, 2010

Индексы

Saturday, January 30, 2010

Внутреннее устройство

• Индексы строятся отдельно от данных

• Индексы обновляются не в тот же момент когда происходит запись транзакции

Saturday, January 30, 2010

Реальное устройство commit()

Момент времени

0 1 2

Операция

Данные

obj.val = NEW obj.commit()

Изменения не видимы никому

Изменения видимы по ключу

Изменения индекса

Saturday, January 30, 2010

Моделируемые ситуации

• Когда после сохранения данных они не видны в результатах поиска

• Фильтр возвращает данные с неактуальным состоянием

Saturday, January 30, 2010

Ключи

Saturday, January 30, 2010

Ключ это не UID

• Мы можем присваивать ключи

• Должен быть уникальным• Состоит из нескольких параметров• Пользовательская часть довольно большая (до 80 кб)

Saturday, January 30, 2010

Пример “статически сайт”from google.appengine.ext import dbclass StaticContent(db.Model): """ Статический сайт """ content_type = db.StringProperty(default="text/html") headers = db.StringListProperty() body = db.BlobProperty() status = db.IntegerProperty(required=True, default=200) last_modified = db.DateTimeProperty(required=True, auto_now=True)

Saturday, January 30, 2010

Пример: продолжение

def get(path): return StaticContent.get_by_key_name(path)

def set(path, body, content_type, **kwargs): content = StaticContent( key_name=path, body=body, content_type=content_type, **kwargs) content.put() return content

Saturday, January 30, 2010

class StaticContentHandler(webapp.RequestHandler): def output_content(self, content): self.response.headers['Content-Type'] = content.content_type last_modified = content.last_modified.strftime(HTTP_DATE_FMT) self.response.headers['Last-Modified'] = last_modified for header in content.headers: key, value = header.split(':', 1) self.response.headers[key] = value.strip() self.response.set_status(content.status) self.response.out.write(content.body) def get(self, path): content = get(path) if not content: self.error(404) self.response.out.write('Not found') return self.output_content(content)

Saturday, January 30, 2010

Пример: настройка обработчика

application = webapp.WSGIApplication([('(/.*)', StaticContentHandler)])

def main(): run_wsgi_app(application)

if __name__ == '__main__': main()

Saturday, January 30, 2010

ок?Saturday, January 30, 2010

Язык запросов *

Saturday, January 30, 2010

GQL не SQL

• Не язык запросов, а фильтр данных• Специфическая система индексов со своими особенностями

• Быстрее работает выдача маленьких объемов выборки чем больших

• Поддерживает более 10 ограничений за раз

Saturday, January 30, 2010

Вопросы??

Saturday, January 30, 2010

Спасибо!

Saturday, January 30, 2010

Контакты

• http://app-engine.tumblr.com/

• mkashkin@gmail.com

• Телефоны на сайте

Saturday, January 30, 2010

Recommended