Разработка масштабируемой базы данных продуктов в Google App Engine - PullRequest
1 голос
/ 24 сентября 2010

Я создал базу данных продуктов, которая разделена на 3 части. И каждая часть имеет «под» часть, содержащую метки. Но чем больше я с ним работаю, тем более нестабильным он себя чувствует. И каждое добавление, которое я делаю, требует все больше и больше кода, чтобы заставить его работать.

Продукт состоит из частей, и каждая часть имеет тип. Каждый продукт, часть и тип имеет этикетку. И есть ярлык для каждого языка.

Изделие содержит детали в 2 списке. Один список для частей по умолчанию (по одному для каждого типа) и одна из дополнительных частей.

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

Результат, который я хочу получить, - это список всех объектов продукта, который содержит имя, описание, цену, все части и все типы, которые соответствуют частям. И для этих правильных языковых меток.

Вот так:

product
    - name
    - description (by language)
    - price (by currency)
    - parts
        - part (type name and part name by language)
        - partPrice (by currency)

Проблема с моей текущей настройкой, которая представляет собой дикое сочетание db.ReferenceProperty и db.ListProperty (db.key)

И получение всех данных - это немного хлопот, которые требуют нескольких циклов for, соответствующих вызовам dict и datastore. Ну, это немного беспорядок.

Повторная модель (не проверенная) выглядит следующим образом

class Products(db.model)
    name = db.StringProperty()
    imageUrl = db.StringProperty()
    optionalParts = db.ListProperty(db.Key)
    defaultParts = db.ListProperty(db.Key)
    active = db.BooleanProperty(default=True)

    @property
    def itemId(self):
        return self.key().id()

class ProductPartTypes(db.Model):
    name= db.StringProperty()

    @property
    def itemId(self):
        return self.key().id()

class ProductParts(db.Model):    
    name = db.StringProperty()
    type = db.ReferenceProperty(ProductPartTypes)
    imageUrl = db.StringProperty()
    parts = db.ListProperty(db.Key)

    @property
    def itemId(self):
        return self.key().id()


class Labels(db.Model)
    key = db.StringProperty() #want to store a key here
    language = db.StringProperty()
    label = db.StringProperty()

class Price(db.Model)
    key = db.StringProperty() #want to store a key here
    language = db.StringProperty()
    price = db.IntegerProperty()

Главное, что я разделил Ярлыки и Прайс. Таким образом, они могут содержать этикетки и цены на любые продукты, запчасти или типы.

Так что мне интересно, это твердое решение с архитектурной точки зрения? Будет ли это сохраняться, даже если в каждой модели тысячи записей?

Также приветствуются любые советы по правильному извлечению данных. Мое текущее решение - сначала получить все данные и зациклить их и вставить их в диктанты, но мне кажется, что они могут потерпеть неудачу в любую минуту.

.. Фредрик

Ответы [ 2 ]

3 голосов
/ 24 сентября 2010

Вы должны иметь в виду, что хранилище данных App Engine требует от вас переосмысления вашего обычного способа проектирования баз данных. Сначала это идет вразрез с интуицией, но вы должны максимально денормализовать свои данные, если вы хотите, чтобы ваше приложение было масштабируемым. Хранилище данных было разработано таким образом.

Подход, который я обычно использую, заключается в том, чтобы сначала рассмотреть вопрос о том, какие запросы необходимо выполнить в различных случаях использования, например. какие данные мне нужно получить одновременно? В каком порядке? Какие свойства должны быть проиндексированы?

Если я правильно понимаю, ваша главная цель - получить список продуктов с полной информацией. Кстати, если у вас есть другие сценарии запроса - т.е. фильтрация по цене, типу и т. д. - их также следует учитывать.

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

class ProductPart(db.Model):
    product_name = db.StringProperty()
    product_image_url = db.StringProperty()
    product_active = db.BooleanProperty(default=True)
    product_description = db.StringListProperty(indexed=False) # Contains product description in all languages
    part_name = db.StringProperty()
    part_image_url = db.StringProperty()
    part_type = db.StringListProperty(indexed=False) # Contains part type in all languages
    part_label = db.StringListProperty(indexed=False) # Contains part label in all languages
    part_price = db.ListProperty(float, indexed=False) # Contains part price in all currencies
    part_default = db.BooleanProperty()
    part_optional = db.BooleanProperty()

Об этом решении:

  • ListProperties установлены в indexed = False, чтобы избежать взрывающиеся индексы, если вам не нужно фильтровать по ним.
  • Чтобы получить право описание, ярлык или тип, вам нужно будет установить список значений всегда в том же порядке. Например: part_label [0] является Английский, part_label [1] - испанский, и т. д. та же идея для цен и валюты.
  • После извлечения сущностей из этого модель вам придется сделать некоторые манипуляции в памяти, чтобы получить данные, хорошо структурированные путь хочешь, может в новый словарь.

Очевидно, что в хранилище данных будет много избыточности с таким дизайном - но это нормально, поскольку он позволяет запрашивать хранилище данных в масштабируемом режиме.

Кроме того, это подразумевается не как замена архитектуры, которую вы имели в виду, а скорее как дополнительная Модель, разработанная специально для пользовательских запросов, которые вам нужно выполнить, т.е. получение списков полной информации о продукте / деталях.

Эти сущности ProductPart могут быть заполнены фоновыми задачами, реплицирующими данные, расположенные в других ваших нормализованных сущностях, которые будут авторитетным источником данных. Поскольку у вас достаточно хранилища данных в App Engine, это не должно быть проблемой.

1 голос
/ 24 сентября 2010

IMO ваш дизайн в основном имеет смысл. Я придумал почти такой же дизайн после прочтения вашей постановки проблемы. С некоторыми отличиями

  • У меня были цены с Product и ProductPart, а не отдельной таблицей.
  • Другое отличие было part_types. Если part_type немного, вы можете просто использовать их как список / кортеж Python.

part_types = ('wheel', 'break', 'mirror')

Это также зависит от того, какие запросы вы ожидаете. Если существует много запросов на расчет цены природы (независимо от остальной части продукта и информации о деталях), возможно, имеет смысл спроектировать его так, как вы это сделали.

Вы упомянули, что сначала получите все данные. Не возможно ли запрашивать? Если вы получите все данные в своем приложении, а затем отсортируете / отфильтруете в Python, то это будет медленно. Какую базу данных вы рассматриваете? Для меня Mongodb выглядит хорошим вариантом здесь.

Наконец, почему вы подозреваете даже 1000 записей? Вы можете запустить несколько тестов на вашей базе данных заранее.

Bests

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...