让我们为您的网站构建一个分析程序,每次访问时都会记录该页面的地址,因此您的log.txt可能是
x.com/a
x.com/b
x.com/a
x.com/c
x.com/a
没有计数器,它只是一个日志文件,并且没有使用sql,因为这有数千个元素是你的一千个左右的唯一域名地址(x.com/a x.com/b),什么是通过此列表并吐出前10名网址的最有效方式。
我最好的解决方案是通过日志文件,然后如果哈希表中不存在该域,则将其添加为键,并递增它的值;然后在散列中搜索最大的10个值。
我不相信这是最好的解决方案,不仅仅是因为空间复杂性(如果独特域从几千到几百万,会发生什么),而且因为我需要在哈希表上进行另一次搜索找到最大的值。
答案 0 :(得分:2)
即使是数千或数百万条目 - 您的方法也很好 - 它的运行时间平均线性(O(n)
) - 所以它并没有那么糟糕。
但是,如果您想要更高的可伸缩性,可以使用map-reduce方法。
map(file):
for each entry in file:
emitIntermediate(getDomainName(entry),"1"))
reduce(domain,list):
emit(domain,size(list))
以上内容将有效地为您提供(domain,count)
tupples列表,您只需选择前10名。
选择前10名可以使用map-reduce(分布式)排序来实现可伸缩性 - 或者使用最小堆(在保持堆中遇到的前10个元素时进行迭代)。第二部分在this thread
中详细解释关于空间复杂性:如果您使用的是64位系统,您可以将其用作RAM,并让操作系统尽其所能(通过在需要时将元素交换到磁盘),您不太可能需要更多那么你在64位机器上的Virtual Memory的数量。另一种方法是使用针对文件系统优化的哈希表(或B+ tree)并对其执行相同的算法。
但是,如果情况确实如此 - 并且数据不适合RAM,并且您无法使用map-reduce,我怀疑排序和迭代 - 尽管O(nlogn)
将会{更高效(使用外部排序) - 因为DISK ACCESSES的数量将被最小化,并且磁盘访问比RAM访问慢得多。
答案 1 :(得分:1)
我建议每次检查文件都是错误的方法。一个更好的解决方案可能是解析文件并将数据推送到数据库(ravendb,或者其他no-sql应该是最简单的)。在那里,即使数据量非常大,查询数据也变得微不足道。
答案 2 :(得分:1)