问题:有一个大文件日志,日志内容包含 访问时间 和 访问 IP,问如何统计每分钟访问次数超过 100 次的 IP ?
keyword:日志、大文件、访问频率
题目并没有说明的内容:
日志时间跨度:这么大个文件是一天日志还是一分钟日志,还是说其它时间跨度
分钟切分粒度:假如在 00 分后半分钟访问 50 次,01 分钟前半分钟访问 51 次,算不算“访问次数超过 100 次”
那就按照最极端的情况来考虑:这个文件是两分钟的日志文件,体积极大,需要任意 60 秒时间段内访问次数不超过 100.
按照这种极端情况考虑的话,前面的“以分钟切片单位,用字典记录用户访问,每分钟清除一遍字典”之类的方法就不适用了,因为使用的内存量是跟用户量成正比的:假如日志中,有极多用户,每个用户只访问一遍,那字典需要的内存比文件本身一半(假定两分钟的日志)还要大,显然会炸内存。
我个人认为,在大文件的前提下,只能按照用户进行切片,而不是时间为单位切片,因为每分钟的数据量在这个场景上没有上限,但是用户的数据上限是 100。而且使用用户 IP 作为切片的 Key,可以上 Hadoop、Spark 等分布式计算框架。(时间作为 key 也可以上分布式,不过可能切片太大,计算量集中到单机)。
当本地操作时,时间 O(n),内存占用 O(1),硬盘占用 O(n);用分布式框架时,时间 O(n),内存 O(n),硬盘 O(1)
在加个极端条件:这个大文件是 1 个用户在 2 分钟内疯狂访问生成的几十 G 的日志。检查可知,就算是这种情况,按照用户切片,最多只需要记录 100 次访问记录。
最后,我是云编程玩家,以下是伪代码:
def map2file(log):
with open(log['ip]) as file:
if file.first_line != 'Hit':
file.append(log)
check(file)
def check(file):
while last_line.time - first_line.time > 60:
delete(first_line)
if file.num_of_line >= 100:
delete_all_lines()
file.append("Hit")
if __name__ == '__main__':
with open('file') as logs:
for log in logs:
map2file(log)
result = []
for file in working_dir:
result.append(
file.name)
(其实就是把那个字典记录在文件系统里面
(是不是觉得我扯了这么多花里胡哨的,10 行代码 9 行 error
(总感觉我哪里搞错了但是没找出来,有错误请把我往死里锤(反正不可能真的顺着网线砍我(