对民意调查进行建模的最佳方式是什么?



域名如下:

class Poll(db.Model):
    question = db.StringProperty()
    ...
class Choice(db.Model):
    poll = db.ReferenceProperty(Poll)
    choice = db.StringProperty()
class Vote(db.Model):
    user = db.ReferenceProperty(User)
    choice = db.ReferenceProperty(Choice)

(这实际上不是一个确定的模型,它只是一个伪图)

我需要查询的内容是:

  • 屏幕上每次投票的总票数
  • 屏幕上每个投票的每个选项的投票总数
  • 如果当前用户投票,每次投票

我已经提出了一些其他模式使用共享计数器,列表属性和没有(与我的内在限制)似乎是工作的。哦,当然,它需要超级快:)

你能帮我建立数据模型吗?

谢谢


编辑:感谢@Nick Johnson,我可以更准确地描述我的问题,他建议使用这个模式

class Poll(db.Model):
    question = db.StringProperty(indexed=False, required=True)
    choices = db.StringListProperty(indexed=False, required=True)
    votes = db.ListProperty(int, indexed=False, required=True)
class Vote(db.Model):
    # Vote is a child entity of Poll, so doesn't need an explicit reference to it
    # Vote's key name is the user_id, so users can only vote once
    user = db.ReferenceProperty(User, required=True)
    choice = db.IntegerProperty(required=True)

这样做的问题是,我无法有效地查询显示用户是否对特定的投票进行了投票。此外,我希望这个模式能够抵抗,比如每次投票100万票或其他(也许我永远不会达到那里,但我想瞄准那里)

为了解决这个问题,我正在考虑添加这样一个EntityIndex:

class PollIndex(db.Model):
    # PollIndex is child of Poll
    voters = db.ListProperty(db.Key)
    voters_choices = db.ListProperty()
    # other search parameters

然后当我必须查询民意调查列表时,我只能用2个查询:

# get keys from pollindex where user is not there
# get keys from pollindex where user is there
# grabb all the polls

另一个很酷的事情是,如果选民的大小增加,我可以动态地添加更多的授粉索引

你觉得这个方法怎么样?

答案在某种程度上取决于您对轮询的最大持续更新率的期望。我首先假设它将是非常有限的(典型的每秒1次,峰值高达每秒10次)。

你的设计基本上是好的,除了几个调整:

  • 不要将选择存储为单独的实体,只需将它们存储为民意调查中的列表
  • 保持在Poll实体上的投票总数,以便快速检索

通过这些更改,您的模型看起来像这样:

class Poll(db.Model):
  question = db.StringProperty(indexed=False, required=True)
  choices = db.StringListProperty(indexed=False, required=True)
  votes = db.ListProperty(int, indexed=False, required=True)
class Vote(db.Model):
  # Vote is a child entity of Poll, so doesn't need an explicit reference to it
  # Vote's key name is the user_id, so users can only vote once
  user = db.ReferenceProperty(User, required=True)
  choice = db.IntegerProperty(required=True)
# Here's how we record a vote
def record_vote(poll_key, user, choice_idx):
  # We assume 'user' is an instance of a datastore model, and has a property 'user' that is
  # a users.User object
  poll = Poll.get(poll_key)
  vote = Vote.get_by_key_name(user.user.user_id(), parent=poll)
  if vote:
    # User has already voted
    return
  vote = Vote(key_name=user.user.user_id(), parent=poll, user=user)
  poll.votes[choice_idx] += 1
  db.put([vote, poll])

如果您需要更高的吞吐量,您应该修改Vote记录,使其不是Poll的子记录(并将其键名更改为包含poll ID和用户ID),然后使用Memcache的write-behind计数器或pull队列将结果聚合为poll总数的更新。

最新更新