【问题标题】:find most often seen string from a log file从日志文件中查找最常见的字符串
【发布时间】:2010-06-22 23:27:18
【问题描述】:

我想在一个巨大的日志文件中找到最常见的字符串。有人可以帮助我如何做到这一点。一种方法是散列每个字符串并计算最大值,但效率不高。有没有更好的方法来做到这一点。

感谢和问候,

鼠标。

【问题讨论】:

  • 我没有看到任何其他方法可以计算每个单词并将单词和计数器放入列表中。如果结构变得太大,您可以考虑将文件分成较小的部分,在那里进行计数并进行第二轮计数
  • 为什么我们必须问每个问题是否都是作业?下车。
  • @greg 这不是家庭作业。我现在不在任何学校。

标签: c++ c data-structures


【解决方案1】:

如果你用字符串表示行,那么在任何类 unix 的 shell 上你应该能够执行以下操作:

sort logfile.txt | uniq -c

这假定您在每一行上没有真正独特的东西 - 例如时间戳,并且文件足够小,可以以这种方式合理处理。

当然,这不会“直接”使用 C 或 C++,但考虑到工具本身很可能是在其中一个中编码的,那么它应该算:-)

【讨论】:

【解决方案2】:

如果性能很关键,您可能需要查看trieRadix tree


如果您只是想知道其中一个字符串出现的次数是否超过 50%(让我们称该字符串为多数字符串),您可以执行以下操作(看看我是否能做到这一点):

  1. 获取第一个字符串并假设它是多数字符串并将其出现次数设置为 1;

  2. 获取下一个字符串

  3. 如果它与当前的多数候选增量相同,则为出现次数

  4. 否则减少出现次数

  5. 如果出现次数达到 0,则用当前字符串替换多数候选

  6. 只要您有要读取的字符串,就从 2 开始重复

  7. 如果最后出现计数大于 0,则重新扫描日志并计算候选的实际出现次数,以检查它是否真的是多数字符串。

    所以你必须检查日志两次。

注意:这是不久前 ACM 编程竞赛中使用的一个问题,可在 here 获取。

【讨论】:

  • 50% 是一个很大的假设,我想知道是否有可能以某种方式将方法调整为任意百分比(使用更多空间)。
  • @Matthieu M.:问题中使用的定义是:“N 个数的非空序列的多数数恰好是在序列中出现 N/2 次以上的数。” “超过 50%”只是我试图记住它......这是一个非常大的假设,但据我所知,这是你可以在线性时间内得到答案的唯一方法(你会通过日志文件最多两次)。另一方面,try 和 Radix 树都提供了相当好的性能(以使用更多空间为代价)。
【解决方案3】:

除非哈希算法很昂贵(我一直认为它们很便宜),否则哈希不会同时具有内存效率(平均哈希长度可能比平均行或字长短,以字节为单位,假设 8 -bit ASCII),并且更快的字典查找?

不想使用哈希的原因是什么?

【讨论】:

    【解决方案4】:

    “巨大”有多大?什么是“字符串”? Unix 命令行工具非常好

    tr -s ' \011' '\012' < /var/log/messages | sort | uniq -c | sort -rn | head -20
    

    生产

        786 --
        635 labrador
        635 Jun
        393 MARK
        236 kernel:
        163 17
        153 usb
        136 22
        118 21
        113 USB
         74 device
         73 20
         73 19
         72 18
         57 5-1:
         51 address
         43 speed
         36 New
         34 0
         33 using
    

    在编写和调试 C 程序所需的时间中,您可以运行大量的 shell 脚本。

    【讨论】:

    • +1 for the remark :) 当然,如果您反复需要执行该任务,您可能有兴趣加快它的速度。
    【解决方案5】:

    假设您的意思是按行或按单词(或有其他分隔符),您可以遍历,获取每个“字符串”并将其放入数据结构中。每次再次找到相同的字符串时,都会在数据结构中增加该字符串的值。

    stl map 可以做到这一点。字符串将是键,与键关联的值将是找到该字符串的次数。你也可以使用 stl multiset。您只需计算具有相同键的项目数。

    【讨论】:

    • 天哪,不要重复搜索字符串。这将是 ATROCIOUS 的表现。
    • @Stefan 我认识到这一点——(我自己永远不会实现这样的技术)。然而,Mousey 的帖子似乎并没有表明他在寻找表现。
    • 不是粗鲁,而是“一种方法是散列每个字符串并计算最大值,但效率不高。有没有更好的方法来做到这一点。”我假设更好意味着更有效,因为他说由于效率而散列不足
    • @Stefan 抱歉,当我阅读原帖时,我以为他说他不能使用散列,但没有说明原因。我现在看到我误读并修改了我的答案。
    【解决方案6】:

    我认为最好的方法是进行一次扫描,计算单词并在地图中逐字累积计数。

    如果您的日志文件使用特定语言,您可能希望忽略“the”、“a”等常用词。您可能还想加入stemming algorithm

    【讨论】:

      【解决方案7】:

      如果“字符串”是指“单词”,那么我能想到的最有效的方法是在阅读重复单词时对其进行计数,而不是存储然后计数。

      【讨论】:

      • 不存储在哈希中怎么办?
      • 您是假设整个文件都缓存在内存中,还是每次迭代都返回磁盘?在你的方法中,你仍然需要保留一个已经计算过的单词列表,不是吗?
      【解决方案8】:

      如果你在谈论日志文件中的任何随机子字符串,这个问题在多项式时间内是无法解决的。如果它确实是一个巨大的日志文件,我相信你是 SOL

      但是,如果您在谈论文件中的任何特定单词,则必须对您的单词进行引用计数。这需要某种地图。

      如果您在谈论文件中的任何特定行,则必须引用您的行数。这需要某种地图。

      无论哪种方式,您都需要使用某种引用计数。

      【讨论】:

        【解决方案9】:

        可能我的答案并不完全正确。但是 perl 是为这些目的而制作的。在 perl 中,这很容易。大多数情况下,perl 代码可以在六行内完成。

        【讨论】:

          猜你喜欢
          • 2015-10-26
          • 2015-11-29
          • 2019-07-16
          • 1970-01-01
          • 2014-09-24
          • 2012-12-08
          • 2014-12-14
          • 2011-02-03
          • 2014-05-24
          相关资源
          最近更新 更多