【问题标题】:Calculate event rate per second计算每秒事件率
【发布时间】:2019-01-07 09:11:08
【问题描述】:

我有一个包含数百万个事件的游戏文件,文件大小可以> 10gb

每一行都是一个游戏动作,比如:

player 1, action=kill, timestamp=xxxx(ms granularity)
player 1, action=jump, timestamp=xxxx
player 2, action=fire, timestamp=xxxx

对于此数据集,每个操作都是唯一且有限的。

我想对此文件执行分析,例如每秒事件总数,同时跟踪该秒内的单个操作数。

我的半伪代码计划:

lastReadGameEventTime = DateTime.MinValue;

while(line=getNextLine() != null)
{
   parse_values(lastReadGameEventTime, out var timestamp, out var action);
   if(timestamp ==  MinValue)
   {
      lastReadGameEventTime = timestamp;
   }
   else if(timestamp.subtract(lastReadGameEventTime).TotalSeconds > 1)
   {
      notify_points_for_this_second(datapoints);
      datapoints = new T();
   }

   if(!datapoints.TryGetValue(action, out var act))
      act = new Dictionary<string,int>();
      act[action] = 0;
   else
      act[action]++;
}
  lastReadGameEventTime = parse_time(line)

我担心这太天真了。我在想也许可以计算整分钟并获得每秒的平均值。但我当然会错过游戏事件高峰。 如果我想计算 5 天的平均值,它会进一步降低结果集。 有什么聪明的主意吗?

【问题讨论】:

  • 将其加载到数据库中,并使用 SQL,不要为此重新创建特定于场景的数据库。在例如 oracle 中:SELECT TRUNC('SS', eventtime), COUNT(*) FROM events GROUP BY TRUNC('SS', eventtime) - 每秒的事件数。每天/每周/每月等只需更改 SS
  • 您想对时间进行分组。因此,您需要秒、分钟、小时、天的平均值和最大值。
  • 一个数据库会很好,但我也可以实时执行此分析.. 就像在套接字中一样

标签: c# algorithm rate


【解决方案1】:

您在这里问了几个不同的问题。都是相关的。您的要求并不详细,但我想我可以为您指明正确的方向。我将假设您想要的只是过去某个时期每秒的事件数。所以我们所需要的只是在此期间每秒保存一个整数(事件计数)。

一天有 86,400 秒。假设您需要 10 天的信息。您可以构建一个大小为 864,000 的循环缓冲区来保存 10 天的计数:

const int SecondsPerDay = 86400;
const int TenDays = 10 * SecondsPerDay;

int[] TenDaysEvents = new int[TenDays];

所以你总是有最后 10 天的计数。

假设您有一个事件处理程序可以读取您的套接字数据并将信息传递给一个函数,您可以轻松地更新您的数据:

DateTime lastEventTime = DateTime.MinValue;
int lastTimeIndex = 0;

void ProcessReceivedEvent(string event)
{
    // here, parse the event string to get the DateTime
    DateTime eventTime = GetEventDate(event);
    if (lastEventTime == DateTime.MinValue)
    {
        lastTimeIndex = 0;
    }
    else if (eventTime != lastEventTime)
    {
        // get number of seconds since last event
        var elapsedTime = eventTime - lastEventTime;
        var elapsedSeconds = (int)elapsedTime.TotalSeconds;

        // For each of those seconds, set the number of events to 0
        for (int i = 1; i <= elapsedSeconds; ++i)
        {
            lastTimeIndex = (lastTimeIndex + 1) % TenDays; // wrap around if we get past the end
            TenDaysEvents[lastTimeIndex] = 0;
        }
    }
    // Now increment the count for the current time index
    ++TenDaysEvents[lastTimeIndex];
}

这将始终将过去 10 天的数据保存在内存中,并且易于更新。报告有点困难,因为开始可能在数组的中间。也就是说,如果当前索引是 469301,那么开始时间是 469302。它是一个循环缓冲区。报告此问题的简单方法是将循环缓冲区复制到另一个数组或列表,起点位于新集合中的位置 0,然后报告该问题。或者,您可以编写一个自定义枚举器,从当前位置倒数并从那里开始。这不会特别难创建。

上面的美妙之处在于您的数组保持静态。您分配一次,然后重新使用它。不过,您可能想要添加额外的 60 个条目,以便在当前时间和 10 天前的时间之间有一些“缓冲区”。这将防止 10 天前的数据在查询期间被更改。添加额外的 300 项,给自己 5 分钟的缓冲时间。

另一种选择是创建条目的链接列表。再次,每秒一个。这样,您将项目添加到列表的末尾,并从前面删除较旧的项目。每当事件进入新的一秒时,将事件条目添加到列表的末尾,然后从列表的前面删除超过 10 天(或任何阈值)的条目。您仍然可以按照另一个答案中的建议使用 LINQ 报告事物。

您也可以使用混合动力车。随着每一秒的流逝,将一条记录写入数据库,并将最后一分钟、一小时或其他任何内容保存在内存中。这样一来,您就可以在内存中获得最新数据,以便快速报告和实时更新,但您也可以使用数据库报告自您第一次开始收集数据以来的任何时期。

无论您决定什么,您可能都应该保留某种数据库,因为您无法保证您的系统不会出现故障。事实上,您几乎可以保证您的系统在某个时候出现故障。丢失数据或不得不扫描数 TB 的日志数据以重新构建您随时间收集的数据并不好玩。

【讨论】:

  • 感谢吉姆的详细回答。这听起来像是我需要的指导,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-17
  • 2020-07-23
  • 2012-09-21
  • 1970-01-01
  • 2021-04-29
  • 2022-10-13
  • 1970-01-01
相关资源
最近更新 更多