在App Engine DB中选择多对多技术

时间:2011-08-04 14:47:21

标签: python google-app-engine database-design django-models

我的App Engine应用程序中会有“文章”和“标签”。

有两种技术可以实现(感谢Nick Johnson's article):

# one entity just refers others
class Article(db.Model):
  tags = db.ListProperty(Tag)

# via separate "join" table
class ArticlesAndTags(db.Model):
  article = db.ReferenceProperty(Article)
  tag = db.ReferenceProperty(Tag)

根据以下任务,我应该选择哪一个?

  • 创建标签云(经常),
  • 按标签选择文章(很少)

4 个答案:

答案 0 :(得分:2)

由于appengine的map reduce(也不是类似查询的SQL组)缺少'reduce'功能,标签云很难有效地实现,因为你需要手动计算你拥有的所有标签。您使用哪种实现方式,我建议标签云使用单独的模型TagCounter来跟踪您拥有的标签数量。否则,如果您有很多标签查询,那么标签查询可能会变得昂贵。

class TagCounter:
   tag = db.ReferenceProperty(Tag)
   counter = db.IntegerProperty(default=0)

每当您选择更新文章上的标签时,请确保相应地从此表中递增和递减。

至于通过标签选择文章,第一个实现就足够了(第二个是过于复杂的imo)。

class Article(db.Model):
  tags = db.ListProperty(Tag)

  @staticmethod
  def select_by_tag(tag):
    return Article.all().filter("tags", tag).run()

答案 1 :(得分:2)

我在GAEcupboard上创建了一个巨大的标签云 * ,选择了第一个解决方案:

class Post(db.Model):
   title = db.StringProperty(required = True)
   tags = db.ListProperty(str, required = True)

标记类有一个计数器属性,每次创建/更新/删除新帖子时都会更新。

class Tag(db.Model):
    name = db.StringProperty(required = True)
    counter = db.IntegerProperty(required = True)
    last_modified = db.DateTimeProperty(required = True, auto_now = True)

将标签组织在ListProperty中,很容易提供向下钻取功能,允许用户编写不同的标签来搜索所需的文章:

实施例: http://www.gaecupboard.com/tag/python/web-frameworks

使用以下方式完成搜索:

posts =  Post.all()
posts.filter('tags', 'python').filter('tags', 'web-frameworks')
posts.fetch()

根本不需要任何自定义索引。

好吧,它太大了,我知道:)

答案 2 :(得分:1)

在app-engine中创建标记云非常困难,因为数据存储区不支持通常用于表达的GROUP BY构造;它也不提供按列表属性的长度排序的方法。

其中一个关键见解是,您必须经常显示标签云,但除非有新文章,否则您不必创建一个,或者文章得到重新标记,因为在任何情况下你都会得到相同的标签 - clout;实际上,标签云对于每篇新文章都没有太大变化,云中的标签可能会变得稍大或稍微小一点,但不会太多,而且不会影响其有用性。

这表明标签云应该定期创建,缓存和显示,就像静态内容一样。您应该考虑在Task Queue API中执行此操作。

另一个按标签列出文章的查询将完全不受你所展示的第一个技术支持;倒置它,使用包含文章ListProperty 的标记模型支持查询,但是当流行标记必须以高速率添加时,将遭受更新争用。使用关联模型的另一种技术既不会受到这些问题的影响,也会使列出查询的文章变得更加方便。

我处理这个问题的方法是从ArticlesAndTags模型开始,但是在模型中添加一些额外的数据以获得有用的排序;文章日期,文章标题,对于您正在制作的特定类型的网站有什么意义。你还需要一个单调的序列(比如一个时间戳),这样你就可以知道 应用的标签。

使用仅包含数字文章计数的标记实体以及对ArticlesAndTags模型中使用的相同时间戳的引用,将支持标记云查询。

然后,任务队列可以查询比最旧的标签更新的1000个最旧的ArticlesAndTag,将每个标签的频率相加并将其添加到标签中的计数。标记删除可能很少,他们可以立即更新标记模型而不会产生太多争用,但如果这个假设结果是错误的,那么 delete 事件也应该添加到ArticlesAndTags中。

答案 3 :(得分:0)

您似乎没有非常具体/复杂的要求,所以我认为这两种方法都不会显示出显着的好处,或者说,优点或缺点完全取决于您习惯的方式,您希望的方式构建代码,以及如何实现缓存和计数机制。

我想到的事情是:

- ListProperty方法使数据模型看起来更自然。

- AtriclesAndTags方法意味着您必须查询关系,然后 Articlesü.. ),而不是做Article.all().filter('tags =', tag)