【问题标题】:Getting DISTINCT users on Google App Engine在 Google App Engine 上获取 DISTINCT 用户
【发布时间】:2010-01-29 14:09:42
【问题描述】:

如何在 Google App Engine (Python) 上执行此操作:

SELECT COUNT(DISTINCT user) FROM event WHERE event_type = "PAGEVIEW" 
AND t >= start_time AND t <= end_time

长版:

我有一个 Python Google App Engine 应用程序,其中包含生成事件(例如页面浏览量)的用户。我想知道在给定的时间跨度内有多少唯一用户生成了浏览量事件。我最感兴趣的时间跨度是一个星期,在给定的一周内大约有 100 万个这样的事件。我想在 cron 作业中运行它。

我的事件实体如下所示:

class Event(db.Model):
    t = db.DateTimeProperty(auto_now_add=True)
    user = db.StringProperty(required=True)
    event_type = db.StringProperty(required=True)

使用 SQL 数据库,我会做类似的事情

SELECT COUNT(DISTINCT user) FROM event WHERE event_type = "PAGEVIEW" 
AND t >= start_time AND t <= end_time

首先想到的是获取所有 PAGEVIEW 事件并过滤掉重复的用户。比如:

query = Event.all()
query.filter("t >=", start_time)
query.filter("t <=", end_time)
usernames = []
for event in query:
    usernames.append(event.user)
answer = len(set(usernames))

但这行不通,因为它最多只能支持 1000 个事件。接下来发生在我身上的事情是获得 1000 个事件,然后当这些事件用完时获得下一个 1000 个,依此类推。但这也行不通,因为通过一千个查询并检索一百万个实体将需要 30 多秒,这是请求时间限制。

然后我想我应该按用户订购以更快地跳过重复项。但这是不允许的,因为我已经在使用不等式“t >= start_time AND t

显然这不能在 30 秒内完成,因此需要分段。但是寻找不同的项目似乎并没有很好地分解成子任务。我能想到的最好的方法是在每个 cron 作业调用中查找 1000 个页面浏览事件,然后从中获取不同的用户名,并将它们放在像 Chard 这样的实体中。它可能看起来像

class Chard(db.Model):
    usernames = db.StringListProperty(required=True)

因此,每个 chard 中最多有 1000 个用户名,如果有重复项被删除,则更少。大约 16 小时后(这很好),我将拥有所有的甜菜,并且可以执行以下操作:

chards = Chard.all()
all_usernames = set()
for chard in chards:
    all_usernames = all_usernames.union(chard.usernames)
answer = len(all_usernames)

看起来它可能有效,但不是一个漂亮的解决方案。如果有足够多的唯一用户,这个循环可能会花费很长时间。我没有测试它,希望有人能提出更好的建议,所以如果这个循环足够快的话,就不会了。

我的问题有什么更漂亮的解决方案吗?

当然,所有这些独特的用户计数都可以通过 Google Analytics(分析)轻松完成,但我正在构建一个应用特定指标的仪表板,并打算将其作为众多统计数据中的第一个。

【问题讨论】:

  • 滚动周是否重要,也就是说,从任何给定日期开始的过去 7 天,或者您可以按日历周计算它们吗?
  • 您是否考虑过使用 Analytics Feed API 从 Analytics 中获取数据? code.google.com/apis/analytics/docs/gdata/…
  • 我猜你想建议添加一个像“calendar_week”这样的字段,这样我就可以在哪里做 SELECT stuff WHERE calendar_week = some_week?那将是一种解决方案,也许除了时间戳之外我还可以拥有它,所以我以后仍然可以做任何我想要的时间跨度。不过,我很好奇是否还有其他更灵活的解决方案。关于第二点,我真的不想从分析中获取我的数据,因为我需要执行其他任务,而 Analytics 不支持我在数据存储中拥有哪些需要信息。需要一组独特用户的行为直方图等。
  • 第一个问题,我在想你可以创建一个分片计数器,按周记录活动。您将决定是否通过为每个用户保留一个“last_activity”日期字段来增加计数器。当用户有活动时,如果他们的最后一个活动是一周前,您可以增加本周的分片计数器。
  • 借助 Google Analytics Feed 建议,我认为您可以使用 Feed 将数据集成到您的仪表板中,而无需直接访问 Analytics,它可以与收集的数据并存,在您的应用程序本身中管理。我提出这个建议主要是因为您仅使用 AppEngine 资源来处理此类任务的选择将非常有限,并且非常难以实施。

标签: python google-app-engine scaling


【解决方案1】:

从 SDK v1.7.4 开始,现在对 DISTINCT 函数提供实验性支持。

见:https://developers.google.com/appengine/docs/python/datastore/gqlreference

【讨论】:

    【解决方案2】:

    这是一个可能可行的解决方案。它在一定程度上依赖于使用 memcache,因此您的数据总是有可能以不可预测的方式被驱逐。 告诫购买者。

    您将拥有一个名为 unique_visits_today 或类似名称的内存缓存变量。每次用户获得当天的第一次网页浏览时,您都将使用 .incr() 函数来增加该计数器。

    通过查看附加到用户的 last_activity_day 字段来确定这是用户的第一次访问。当用户访问时,您查看该字段,如果是昨天,则将其更新为今天并增加您的内存缓存计数器。

    每天午夜,cron 作业将获取内存缓存计数器中的当前值并将其写入数据存储区,同时将计数器设置为零。你会有这样的模型:

    class UniqueVisitsRecord(db.Model):
        # be careful setting date correctly if processing at midnight
        activity_date = db.DateProperty()
        event_count = IntegerProperty()
    

    然后,您可以简单、轻松、快速地获取与任何日期范围匹配的所有 UnqiueVisitsRecords,并将其 event_count 字段中的数字相加。

    【讨论】:

    • 这取决于你在 memcache 中停留一整天的价值。 memcache 是缓存,不是可靠存储;这只是一个很好的答案,如果你很高兴一直失去你的计数。
    【解决方案3】:

    NDB 仍然不支持 DISTINCT。我编写了一个小实用程序方法,可以在 GAE 中使用 distinct。

    请看这里。 http://verysimplescripts.blogspot.jp/2013/01/getting-distinct-properties-with-ndb.html

    【讨论】:

      【解决方案4】:

      Google App Engine 和更具体的 GQL 不支持 DISTINCT 函数。

      但是您可以使用 Python 的 set 函数,如 this 博客和 this SO 问题中所述。

      【讨论】:

      • 谢谢。我知道那个 SO question 和 blogpost,但由于任务的大小,它们不适用于这种情况。
      猜你喜欢
      • 1970-01-01
      • 2020-09-05
      • 2013-06-17
      • 1970-01-01
      • 2015-11-06
      • 1970-01-01
      • 2012-02-24
      • 2023-03-08
      • 1970-01-01
      相关资源
      最近更新 更多