我是 google-app-engine 和 google datastore (bigtable) 的新手,我有一些疑问,其中的顺序可能是设计所需数据模型的最佳方法。
我需要创建一个层次结构模型,类似于产品目录,每个域都有一些子域。目前产品的结构变化小于阅读要求。 Wine 示例:
- 产地(托斯卡纳、普里奥拉特、阿尔萨斯)
- 酒厂(只属于一个产地)
- Wine (仅属于一个酒厂)
所有关系都是不相交且不完整的。此外,为了满足要求,我们可能需要存储每种 Wine 的使用计数器(可能需要交易)
按照文档的顺序似乎有不同的潜在解决方案:
- 祖先管理。使用 parent 关系和交易
- 伪祖先管理。用 db.ListProperty(db.Key) 模拟祖先
- 引用属性。明确指定类之间的关系
但是为了获得 Wine 的预期请求...有时按品种,有时按原产地,有时按酿酒厂...我担心使用这些结构的查询行为(例如关系模型。如果你要求一个家庭的产品......你需要加入产品树中的最终深度限定符并加入自家庭)
也许创建一些重复的信息会更好(按照 google 团队的建议排序:操作是昂贵的,但存储不是,所以重复的内容不应该是主要问题)
其他类似问题的一些回答表明:
- 将所有父 ID 作为层次结构存储在字符串中...就像路径属性一样
- 复制 Drink 实体与树中所有父项之间的关系 ...
有什么建议吗?
嗨,威尔,
正如您在第二个示例中所代表的那样,我们的案例是一种更严格的分层方法。查询是为了检索产品列表,通常只检索一个是不常见的。
我们需要从一个产地、一个酿酒厂或一个品种中检索所有的 Wine (如果我们假设品种是严格层次树的另一个节点,这只是一个例子)
如您所述,一种方法可能是包含路径属性:
- /origin/{id}/winery/{id}/variety/{id}
为了允许我从一个品种中检索 Wine 列表,应用这样的查询:
wines_query = Wine.all()
wines_query.filter('key_name >','/origin/toscana/winery/latoscana/variety/merlot/')
wines_query.filter('key_name <','/origin/toscana/winery/latoscana/variety/merlot/zzzzzzzz')
或者从 Origin 中这样:
wines_query = Wine.all()
wines_query.filter('key_name >','/origin/toscana/')
wines_query.filter('key_name <','/origin/toscana/zzzzzz')
谢谢!
最佳答案
除了问题中提到的查询之外,我不确定您还需要执行哪些类型的查询,但是将数据存储在明确的祖先层次结构中会使您询问的查询很容易失效。
例如,要获取特定产地的所有 Wine :
origin_key = db.Key.from_path('Origin', 123)
wines_query = db.Query(Wine).ancestor(origin_key)
或从特定酒厂获取所有 Wine :
origin_key = db.Key.from_path('Origin', 123)
winery_key = db.Key.from_path('Winery', 456, parent=origin_key)
wines_query = db.Query(Wine).ancestor(winery_key)
并且,假设您将品种存储为 Wine 模型的一个属性,则特定品种的所有 Wine 都非常简单
wines_query = Wine.all().filter('variety =', 'merlot')
这种严格的分层方法的一个可能缺点是它可能强加给您的 URL 方案类型。层次结构看起来像
Origin -> Winery -> Wine
您必须知道 Wine 原产地和酒厂的 key 名称或 ID,才能构建检索该 Wine 的 key 。除非您已经获得了 Wine key 的字符串表示形式。这基本上迫使您以下列形式之一拥有 Wine 的 URL:
/origin/{id}/winery/{id}/wine/{id}
/wine/{作为字符串的不透明且不友好的数据存储 key }
(第一个 URL 当然可以用查询字符串参数替换;重要的是您需要三种不同的信息来识别给定的 Wine 。)
虽然我没有想到这些 URL 方案还有其他替代方案。
关于python - 分层数据建模 - GAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3620147/