1

我有一个原始数据模型,用户可以插入应该有城市和地区的内容。为与多个城市相关联的文章做准备(例如,在两个或多个城市中提供相同的产品将成为只有一篇带有城市列表的文章,而不是针对该文章所连接的每个城市的重复文章至)。

class Region(db.Model):
    name = db.StringProperty()
    countrycode = db.StringProperty()
    vieworder = db.IntegerProperty() # custom ORDER BY variable to order by population 
    areacode = db.IntegerProperty()
    areacodes = db.ListProperty(int)


class City(db.Model):
    region = db.ReferenceProperty()
    name = db.StringProperty()
    vieworder = db.IntegerProperty()
    areacode = db.IntegerProperty()

所以我可以设法制作存储和视图,但数据模型不好。

class Article(db.Model):
    cities = db.ListProperty(db.Key)
    regions = db.ListProperty(db.Key)

在插入时,它被编码:

if self.request.get('area'):
    city = model.City.get_by_id(long(self.request.get('area')))
    region = model.Region.get(city.region.key())
    article.cities.append(city.key())
    article.regions.append(region.key())
    article.city = unicode(city.name)
    article.region = unicode(region.name)
    article.put()

这会产生冗余并且不是很漂亮(而不是在 1NF 中,因为它在字段中保存了一个列表)。

在此处输入图像描述

在为搜索 API 构建索引时,到目前为止我只使用一个城市,但我计划处理城市列表和区域列表(虽然一个城市永远不可能在两个区域中,所以除了城市列表之外的所有内容实际上都是多余的,但是我节省了冗余以避免在搜索和视图中进行冗长的查找)。我想知道我是否正确使用了引用属性和键,以及使用 NDB 模型是否会更好?

4

2 回答 2

3

@Michael 的另一个答案是一个很大的加分项。

此外,我建议您转到 ndb,db.ReferenceProperty 存在问题,因为您必须跳过障碍以确保有效地获取引用。由于到数据存储的多次往返,使用 mycity.region 进行循环和取消引用非常昂贵。

如果您想使用 db,请查看 Nick Johnson 关于预取引用属性的文章。

http://blog.notdot.net/2010/01/ReferenceProperty-prefetching-in-App-Engine

但正如我所说,我只是转向 ndb,因为你没有在 db 代码上投入太多。

继续对数据进行建模。

从你的数据模型和评论我们知道一个城市只能属于一个地区,

因此,在创建城市时考虑将该地区作为城市的祖先,而不是持有参考或关键财产。然后该区域是键的一部分,如果您使用 ndb,您可以在需要时使用 city.key.parent() 获取父级(城市的区域)。

我认为在文章中存储地区/城市没有任何问题。但是,如果您总是按城市查询,那么将区域作为祖先意味着您可以只存储城市。

唯一潜在的缺点是,如果您将大量城市和地区分配给一篇文章。请记住实体大小限制为 1MB。

我不确定您为什么要在文章中存储城市名称和地区名称,因为您可能有很多城市和地区。您可以轻松地将每个城市和地区的 id 设为名称,然后,如果您需要在文章的城市和地区的摘要列表中使用该名称,则您已经将其放在键中,并且可能会跳过此时获取实体。

我想具体的方法很大程度上取决于与每篇文章相关的预期城市/地区数量以及您的查询的实际结构。

我还会考虑将城市和地区折叠成一个列表属性(或重复属性),因为如果您想列出与 citya 或 regionb 相关的所有文章,您必须执行两个查询。如果它们都存储为单个列表中的键(例如位置),那么您可以只执行一个查询,例如

Article.filter(Article.locations.IN([citya_key, rebionb_key]) 

此查询搜索其位置值(视为列表)至少包含这些值之一的实体。

我将处理您的特定查询用例,然后从那里改进您的模型。

于 2014-03-20T15:10:29.407 回答
3

首先,如果您关心 1NF 并且规范化忘记了数据存储,您需要 Google Cloud SQL (MySQL) 或任何其他关系数据库。维基百科说:

第一范式 (1NF) 是关系数据库中关系的属性

如果您在此“NOSQL”、分层、键值数据存储上构建您的应用程序,则意味着您需要可扩展的性能。连接是昂贵的,磁盘空间不是:重复,非规范化你的数据,这样你就可以快速访问它。忘掉你在 RDBMS 建模中学到的“对与错”吧。你在那里是另一个世界。

在您的情况下,如果您希望您的应用程序扩展,您需要在您的文章中复制您的地区/城市/国家/任何内容,这样您就不必进行多次额外查询。您的用例适合数据存储,因为您的城市不会更改名称。

为了简单起见:对数据进行建模,这样您就可以通过一个查询获得用例所需的一切——而不会破坏数据存储的限制(实体大小、写入吞吐量、配额......)。

于 2014-03-20T13:31:04.993 回答