App Engine Python中的父子关系(Bigtable)

9 投票
2 回答
2806 浏览
提问于 2025-04-16 12:39

我还在学习大表和NoSQL的数据建模,想请教一下大家的意见。如果我经常需要处理多个父级下的子级数据,是否应该避免使用父子关系来建模?

举个例子,假设我在建立一个博客,很多作者会在上面发帖,每个帖子都有标签。那么我可能会这样设置:

class Author(db.Model): 
  owner = db.UserProperty()

class Post(db.Model): 
  owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
  tags = db.StringListProperty() 

根据我的理解,这样会创建一个以作者为父级的实体组。如果我主要是根据标签来查询帖子,这样会导致效率低下吗?因为我预计会涉及到多个作者的帖子。

我知道在列表属性上进行查询可能效率不高。假设每个帖子平均有3个标签,但最多可能有7个。我预计我的标签总数会在几百个左右。把模型改成这样会有什么好处吗?

class Author(db.Model): 
  owner = db.UserProperty()

class Post(db.Model): 
  owner = db.ReferenceProperty(Author, 
    collection_name='posts') 
  tags = db.ListProperty(db.Key)

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

或者我这样做会更好?

class Author(db.Model): 
  owner = db.UserProperty()

class Post(db.Model): 
  owner = db.ReferenceProperty(Author, 
    collection_name='posts')

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

class PostTag(db.Model): 
  post = db.ReferenceProperty(Post, 
    collection_name='posts') 
  tag = db.ReferenceProperty(Tag, 
    collection_name='tags') 

最后一个问题……如果我最常用的场景是根据多个标签来查询帖子,比如“找到所有带有标签{'苹果', '橙子', '黄瓜', '自行车'}的帖子”,这几种方法中哪一种更适合用来查询包含某些标签的帖子呢?

谢谢,知道这问题有点多。:-)

2 个回答

2

我会选择最后一种方法,因为它可以直接根据标签获取帖子列表。

第一种方法基本上让我们无法保持一个标准的标签集合。换句话说,想要回答“系统中当前有哪些标签”这个问题是非常费力的。

第二种方法解决了这个问题,但正如我提到的,它并不能帮助你根据标签来获取帖子。

实体组有点神秘,但简单来说,第一种方法并不会创建实体组,实体组仅在进行事务性数据库操作时是“必要的”,有时在优化数据读取时也有用,但在小型应用中可能并不需要。

需要提到的是,无论你选择哪种方法,都需要配合一个聪明的缓存策略才能发挥好效果。GAE应用非常喜欢缓存。要好好了解memcache的API,并学习如何在memcache和数据存储上进行批量读写操作。

5

像第一种或第二种方法非常适合用于App Engine。可以考虑以下设置:

class Author(db.Model): 
  owner = db.UserProperty()

class Post(db.Model): 
  author = db.ReferenceProperty(Author, 
    collection_name='posts') 
  tags = db.StringListProperty()

class Tag(db.Model): 
  post_count = db.IntegerProperty()

如果你使用字符串标签(不区分大小写)作为标签实体的名称,你就可以高效地查询带有特定标签的帖子,或者列出某个帖子的标签,甚至获取标签的统计信息:

post = Post(author=some_author, tags=['app-engine', 'google', 'python'])
post_key = post.put()
# call some method to increment post counts...
increment_tag_post_counts(post_key)

# get posts with a given tag:
matching_posts = Post.all().filter('tags =', 'google').fetch(100)
# or, two tags:
matching_posts = Post.all().filter('tags =', 'google').filter('tags =', 'python').fetch(100)

# get tag list from a post:
tag_stats = Tag.get_by_key_name(post.tags)

第三种方法在进行大多数基本操作时需要额外的查询或获取数据,如果你想查询多个标签,这会更加困难。

撰写回答