Работа с хранилищами данных в google app engine и сравнение с...
DESCRIPTION
Доклад Михаила Кашкина для PyCamp, Киев 2010TRANSCRIPT
Работа с 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/
• Телефоны на сайте
Saturday, January 30, 2010