假设我们1e10
每天大约有几行日志文件,每行包含:一个 ID 号(长度小于 15 位的整数)、一个登录时间和一个注销时间。某些 ID 可能会多次登录和注销。
问题一:
如何统计已登录的ID总数?(每个ID不要统计两次或更多)
我在这里尝试使用哈希表,但我发现我们应该获得的内存可能很大。
问题 2:
计算在线用户人数最多的时间。
我想我们可以把一天的时间分割成86400秒,然后对于日志文件的每一行,在线间隔的每一秒加1。或者我可以按登录时间对日志文件进行排序?
您可以在 *nix shell 中执行此操作。
cut -f1 logname.log | sort | uniq | wc -l
cut -f2 logname.log | sort | uniq -c | sort -r
对于问题 1,忘记 C++ 并使用 *nix 工具。假设日志文件是用空格分隔的,那么给定日志中的唯一登录数由以下公式计算:
$ awk '{print $1}' foo.log | sort | uniq | wc -l
Gnu sort,会很乐意对大于内存的文件进行排序。以下是每件作品的作用:
要使问题 2 有意义:您可能必须记录两件事:用户登录和用户注销。两个不同的活动以及用户 ID。如果此列表按活动的时间排序(登录或注销完成)。您只需使用名为 currentusers 的计数器进行扫描:每次登录时添加 1,每次注销时添加 -1。数量(当前用户)达到的最大值是您感兴趣的值,您可能还会对跟踪它发生的时间感兴趣。
使用分段树来存储连续 id 的间隔。扫描所有登录事件的日志。要插入 id,首先搜索包含该 id 的段:如果存在,则该 id 是重复的。如果它不搜索 id 之后或之前的段。如果它们存在,则删除它们并根据需要合并新的 id,然后插入新的段。如果它们不存在,则将 id 作为 1 个元素的段插入。
插入所有 id 后,通过对树中所有段的基数求和来计算它们的数量。
假如说:
扫描日志并保留c
当前登录用户数的计数器,以及m
找到的最大用户数和相关时间t
。对于每次登录,递增c
,对于每次注销,递减它。在每一步更新m
,t
如果m
低于c
.
对于 1,您可以尝试一次使用小到足以放入内存的文件片段。即代替
countUnique([1, 2, ... 1000000])
尝试
countUnique([1, 2, ... 1000]) +
countUnique([1001, 1002, ... 2000]) +
countUnique([2001, 2002, ...]) + ... + countUnique([999000, 999001, ... 1000000])
2有点棘手。将工作划分为可管理的间隔(如您所建议的那样)是一个好主意。对于每一秒,使用以下检查(伪代码)查找在 taht 秒内登录的人数:
def loggedIn(loginTime, logoutTime, currentTimeInterval):
return user is logged in during currentTimeInterval
将loginIn应用于所有86400秒,然后最大化86400用户计数列表,找到在线用户数量最大的时间。