当前位置: 首页 > 知识库问答 >
问题:

计算最后一分钟内活跃用户的最快/最简单方法是什么?

党博超
2023-03-14

您为 Zynga 工作,并希望计算不同游戏的当前活跃玩家数量。您的 Web 服务器处理来自许多不同游戏的 ping,并且每个用户都有一个唯一的 GUID。必须能够一次查询一个游戏的活跃用户数。活跃用户是那些在最后一刻得到ping的用户。

日志行不断进入 Web 服务器:

10.1.12.13 - - "http://zynga.com/ping?guid=<guid>&game=<gameID>" -

统计活跃用户最快/最简单的方法是什么?请建议一个45分钟的回答与一些代码。

我的版本

// web server interface, every time ping comes in count() will be called
// void count(String gameId, String guid)
// int getNumberActivePlayers(String gameId)

struct Record{
  String gameID;
  String guid;
};

class PingStorage{
private:
  max_heap<long, Record> storage;
public:
  //    O(log(n))
  //  n = total number of elements in storage
  void count(String gameId, String guid){
    long currentTimeStamp = getUnixTimeStamp();
    Record rec ;
    rec.gameId = gameId;
    rec.guid = guid;
    storage.add(currentTimeStamp, rec);
  }
  //N = numner of records in last ,minutes in storage
  //O(N)
  int getNumberActivePlayers(String gameId){
    map<String, Set<string> > game2user;
    long tillTimeStamp = getUnixTimeStampNow() - 60;
    while(true){
      pair<long, Record> rec = storage.getMax(); //O(1)
      if(rec.first <= tillTimeStamp) break;  
      Set<String> temp = game2user[rec.gameid]; //O(1)
      temp.add(rec.userid); //O(log(N)) - O(1)
    }
    return game2user[gameID].size();
  }
};

共有3个答案

邵璞
2023-03-14

编辑:我假设这个问题不是关于“现在有多少用户活跃”的实时答案,而是关于历史值——下午3:25有多少用户处于活跃状态。我将保持旧解决方案低于新解决方案

所以,你想知道现在有多少用户活跃,每个游戏保持一个队列。每当你看到一个新的日志条目,找出它属于哪个游戏,并将其添加到游戏的队列中。每次添加后,清理队列开头的旧条目(清理时超过1分钟的所有条目)。

当询问游戏中的活跃用户数时,对游戏的队列进行同样的清理,并返回队列的深度。

保留一个将游戏映射到队列的哈希,你会得到一个O(N)操作,N是日志中的行数——每行最多处理两次——一次用于添加它,一次用于删除它。您还可以在每次添加和查找时进行额外的比较(当决定队列条目不够旧时),但这是恒定的时间乘以N。所以总的来说是O(N)。

另一个问题的前一个答案是:鉴于没有那么多分钟(每天1440分钟),我会为每场比赛创建一个向量,每分钟有一个时段。

查看日志文件,为每一行获取时间,将其四舍五入到最接近的分钟,并在数组中的适当位置添加1。完成后,您将准确知道每场比赛每分钟有多少活跃用户

复杂性-O(N),其中N是日志文件中的行数。

要支持多个游戏,只需使用哈希将游戏名称映射到其矢量即可。

现在,这假设您只检查整个分钟边界(1:00:00,1:01:00 等)的活动用户。无论如何,这可能是您需要做的。

韶硕
2023-03-14

我的方法是使用一个deque(在本文剩余部分中称为queue),所有GUID都会被推到这个deque,即,它是按年龄排序的。此外,我将使用一个哈希映射,其中包含指向队列中存在的任何GUID条目的指针。

当一个新的GUID被推送到队列时,旧的条目(如果有的话)将在哈希图中查找,并从队列中删除,新的条目将被分配给哈希图。

随着时间的流逝,队列中超过年龄阈值的所有条目都将被弹出(并从哈希图中删除)。

队列的长度(即活动用户数)可以作为单独的变量进行跟踪,以避免每次查询在队列中跳转。

要支持多个游戏,只需为每个gameID添加这样的结构。

复杂度:O(1)插入/删除观察值(给定完美哈希,即没有冲突),O(1)查询,O(n)空间。

段干华皓
2023-03-14

假设这是一个实时解决方案,您可以在O(1)中处理ping请求,在O(1)中生成当前玩家统计数据,并通过牺牲一些准确性来使用O(num_player)空间。关键是将时间离散化。

概述

基本思想是将离散时间间隔表示为对象,并在这些对象中存储以下属性:在此时间间隔内ping的不同玩家的数量,这些玩家自ping以来没有ping过。要查询活动用户数,请计算构成最后一分钟的最后x个时间间隔的加权和。

细节

首先,选择一个可接受的时间分辨率。在这个例子中,我选择了15秒的间隔。

维护五个PingInterval数据结构来表示其中的五个时间间隔(跨越1分钟以上的时间间隔)。PingInterval包含一个属性:计数器。这些PingIntervals在PingMonitor中维护。每次玩家pings时,在PingMonitor中更新一个映射,将每个玩家映射到当前时间间隔。当您执行这个映射时,采取以下步骤,这些步骤将计数保持在PingIntervals内(根据我在概述部分描述的特征)。

  • 如果播放器已映射到某个间隔,并且它是当前间隔,则不执行任何操作。
  • 否则,如果玩家映射到不是当前间隔的间隔,
    • 减少旧区间的计数,
    • 递增当前区间的计数,
    • 并将该玩家映射到该间隔。
    • 递增当前区间的计数,
    • 将玩家映射到当前间隔。

    (如果表示当前时间的 Ping 间隔尚不存在,请将最早的 Ping 间隔设置为 null,以线程安全的方式创建新的 Ping 间隔,然后照常继续。

    当您想要查询活动用户的数量时,请计算最后五个间隔时间间隔的经过时间加权和。例如,如果距离当前时间间隔只有5秒(意味着该间隔的下10秒尚未发生),则计算该值:2/3*4个最新间隔的最旧间隔总和。

    其他想法

    五个间隔非常保守;我们可以大幅增加数字以获得更高的精度(可能是每秒一次),这仍然可以为我们节省大量成本。重要的是,我们的时间现在是离散的时间间隔。这意味着当我们统计活跃用户的数量时,我们不必每次都查看(这等于用户的数量);相反,我们可以查看预定义的x个时间段。

 类似资料:
  • 我已经启动并运行了AngularJS和web.api WAAD身份验证。对于客户端,我使用了很棒的库adal.js。对于后端,我使用Microsoft.OWIN.Security.OAuth。这部分进行得相当顺利。 现在我要实现基于角色的授权(将映射到WAAD组)。组不包括在身份验证令牌中,所以我必须向Azure Graph API请求它们。我看到了各种实现方法,例如使用自定义声明提供程序、向pr

  • 假设您有一个不断收到HTTP请求的服务器。您的老板需要一些统计数据,并要求您计算任何给定时间最后一分钟内的点击数。 你会用什么算法和数据结构来实现这个目标?

  • 问题内容: 在MySQL中,哪种方式计算行数应该更快? 这个: 或者,替代方案: 有人会认为第一种方法应该更快,因为在内部确定类似情况时,这显然是数据库领域,而数据库引擎应该比其他任何人都要快。 问题答案: 当您使用count列索引时,它将是最好的结果。使用 MyISAM 引擎的Mysql 实际上存储行数,每次尝试对所有行进行计数时,它都不会对所有行进行计数。(基于主键的列) 使用PHP计数行不是

  • 问题内容: 反转此ArrayList的最简单方法是什么? 问题答案: 示例(参考):

  • 反转这个ArrayList的最简单方法是什么?

  • 问题内容: 设和为两个集合。我正在寻找一种 非常 快速或优雅的方法来计算它们之间的设置差异(或,取决于您的偏好)。如标题所示,这两组存储和存储为Javascript数组。 笔记: 壁虎特技可以 我更喜欢本机函数(但是如果速度更快,我可以使用轻量级库) 我看过但未测试JS.Set(请参阅上一点) 编辑: 我注意到有关包含重复元素的集合的评论。当我说“设置”时,我指的是数学定义,这意味着(除其他外)它