【问题标题】:Designing a scalable product database on Google App Engine在 Google App Engine 上设计可扩展的产品数据库
【发布时间】:2010-09-24 23:31:17
【问题描述】:

我已经建立了一个分为 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 和数据存储调用。嗯,有点乱。

重新模型(未经测试)看起来像这样

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()

这里的主要内容是我已经将标签和价格分开了。因此,这些可以包含任何产品、零件或类型的标签和价格。

所以我很好奇,从架构的角度来看,这是一个可靠的解决方案吗?即使每个模型中有数千个条目,这也会成立吗?

此外,我们欢迎任何有关以良好方式检索数据的提示。我目前的解决方案是先获取所有数据,然后对它们进行 for 循环并将它们粘贴在 dicts 中,但感觉它可能随时失败。

..弗雷德里克

【问题讨论】:

    标签: python google-app-engine architecture google-cloud-datastore


    【解决方案1】:

    您需要记住,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 上有大量数据存储空间,因此这应该不是问题。

    【讨论】:

    • 我真的很喜欢这个背景创意!我正在考虑一个综合解决方案。我的包含逻辑的解决方案和您由后台任务生成的解决方案像您描述的那样应用它。然后结果尝试获取非规范化数据(如果存在),或者对我的模型进行查询。什么是爆炸式索引?
    • 这里是一些关于爆炸索引的信息:code.google.com/appengine/docs/python/datastore/…
    【解决方案2】:

    IMO 你的设计大多是有意义的。在阅读了您的问题陈述后,我确实提出了几乎相同的设计。有一些不同

    • 我的 Product 和 ProductPart 价格不是单独的表格。
    • 其他区别是part_types。如果没有很多 part_type 你可以简单地将它们作为 python 列表/元组。

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

    这还取决于您预期的查询类型。如果有许多自然价格计算查询(独立于产品和零件信息的其余部分),那么按照您的方式设计它可能是有意义的。

    您提到您将首先获取所有数据。不可以查询吗?如果您在应用程序中获取全部数据,然后在 python 中排序/过滤,那么它会很慢。您正在考虑使用哪个数据库?对我来说 mongodb 在这里看起来是个不错的选择。

    最后你为什么怀疑 1000 条记录?您可以事先在您的数据库上运行一些测试。

    最佳

    【讨论】:

    • 谢谢。单独价格的原因是产品包含每种语言(货币)的价格并且类型相同。每种类型都有一个基于当前语言的标签。有没有办法在某些语言支持下使用元组?
    • 我想获取所有数据一次(每个表至少一个),因此我不会在循环遍历它们时使用新查询来获取产品标签。
    • IMO 正确的方法是以十进制存储价格,然后您应该使用适当的框架实用程序以所需的货币格式显示。
    • 关于 1 个查询:想象一下随着您的数据库增长而传输的大量数据。只查询什么是必要的。减少查询数量不会为您节省太多(此处)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    • 2013-11-02
    • 1970-01-01
    • 2011-09-01
    • 1970-01-01
    • 2012-07-31
    相关资源
    最近更新 更多