代码之家  ›  专栏  ›  技术社区  ›  Bemmu

在谷歌应用引擎上获得不同的用户

  •  4
  • Bemmu  · 技术社区  · 15 年前

    如何在Google应用程序引擎(python)上执行此操作:

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

    长版本:

    我有一个python google应用引擎应用程序,它的用户可以生成事件,比如页面视图。我想知道在给定的时间跨度内,有多少独特的用户生成了一个页面视图事件。我最感兴趣的时间跨度是一周,在一周内大约有一百万个这样的活动。我想在cron作业中运行这个。

    我的活动实体如下所示:

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

    对于一个SQL数据库,我会做一些类似的事情

    从事件中选择count(distinct user),其中event_type=“pageview”
    和t>=开始时间和t<=结束时间
    

    首先想到的是获取所有页面视图事件并过滤掉重复的用户。类似:

    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>=开始时间和t<=结束时间”的不等式。

    很明显,这在30秒内是不可能完成的,所以它需要被分割。但找到不同的项目似乎并不能很好地划分为子任务。我能想到的最好的方法就是在每个cron jobcall上查找1000个pageview事件,然后从这些事件中获得不同的用户名,并将它们放入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)
    

    这似乎可行,但不是一个很好的解决方案。如果有足够的独特用户,这个循环可能会花费太长时间。我还没有测试它,希望有人能提出更好的建议,所以如果这个循环足够快的话就不行了。

    我的问题有没有更好的解决办法?

    当然,所有这些独特的用户计数都可以通过谷歌分析轻松完成,但我正在构建一个特定于应用程序的指标仪表盘,并希望这是许多统计数据中的第一个。

    4 回复  |  直到 12 年前
        1
  •  1
  •   Adam Crossland    15 年前

    这里有一个可行的解决方案。它在某种程度上依赖于使用memcache,因此始终有可能以不可预知的方式将数据逐出。 买者弃权。

    您可以调用一个memcache变量 今天唯一的访问 或者类似的东西。每次用户拥有当天的第一个页面视图时,您都将使用.incr()函数来递增该计数器。

    确定这是用户的第一次访问是通过查看 最后一个活动日 附加到用户的字段。当用户访问时,您查看该字段,如果它是昨天的,则将其更新到今天,并增加memcache计数器。

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

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

    然后,您可以简单、轻松、快速地获取所有与任何日期范围匹配的unqiuevisits记录,并将这些记录中的数字相加。 事件计数 领域。

        2
  •  4
  •   matt burns    12 年前

    从sdk v1.7.4开始,现在已经有了对distinct函数的实验支持。

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

        3
  •  1
  •   Community CDub    8 年前

    谷歌应用引擎和更具体的 GQL 不支持 DISTINCT 功能。

    但是你可以用蟒蛇的 set 功能如中所述 this 博客和在 this 所以问题。

        4
  •  1
  •   specialscope    12 年前

    ndb仍然不支持distinct。我已经写了一个小的实用方法,能够使用与GAE不同。

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