【问题标题】:grep -f alternative for huge filesgrep -f 大文件的替代方案
【发布时间】:2016-08-03 04:56:26
【问题描述】:
grep -F -f file1  file2

file1 为 90 Mb(250 万行,每行一个字)

file2 为 45 Gb

该命令实际上不会产生任何东西,无论我让它运行多久。显然,这超出了 grep 的范围。

似乎 grep 无法处理来自 -f 选项的那么多查询。但是,以下命令确实会产生所需的结果:

head file1  >  file3
grep -F -f file3   file2

考虑到文件大小,我怀疑 sed 或 awk 是否是合适的替代方案。

我不知所措……请帮忙。学习一些sql 命令值得吗?这简单吗?谁能指出我正确的方向?

【问题讨论】:

  • 你能用split命令把file1分成几块吗?
  • SQL 命令通常不会帮助您处理原始文件。
  • @DanPichelman 如果他将模式文件分成 100 份,他必须与 45G 怪物一起玩 100 次..这没关系...**并且**他必须删除重复的匹配行.因为 grep -f 执行“OR”....我不知道它是否更快。
  • 你在什么操作系统上运行?我对grep -F -f listFile 的体验是您会收到一条错误消息,上面写着listFile too big(或类似的)。嗯...其他读者...-f listFile 不是一个排序文件吗? ?此外,虽然 SQL 可以解决这个问题,但安装 SQL、cfged 等需要很长的设置时间。如果您制作一个定期运行的生产流程,可能值得花时间投资,但可能不在您的项目时间表。祝你好运!
  • 你可以只做 cat file2,因为如果你从一个文件中 grep 出 250 万个单词,最终几乎所有的行都会显示出来 :)

标签: unix scripting grep large-files


【解决方案1】:

尝试使用 LC_ALL=C 。它将搜索模式从 UTF-8 转换为 ASCII,其速度是原始速度的 140 倍。我有一个 26G 的文件,这需要我大约 12 个小时才能完成到几分钟。 来源:Grepping a huge file (80GB) any way to speed it up?

所以我要做的是:

LC_ALL=C fgrep "pattern" <input >output

【讨论】:

    【解决方案2】:

    我认为没有简单的解决方案。

    假设您编写了自己的程序来执行您想要的操作,并且最终会出现一个嵌套循环,其中外部循环遍历 file2 中的行,而内部循环遍历 file1(反之亦然)。迭代次数随着size(file1) * size(file2) 的增加而增加。当两个文件都很大时,这将是一个非常大的数字。使用head 缩小一个文件显然可以解决这个问题,但代价是不再给出正确的结果。

    一种可能的出路是索引(或排序)其中一个文件。如果您遍历 file2 并且对于每个单词,您可以确定它是否在模式文件中,而不必完全遍历模式文件,那么你会好得多。这假设您进行逐字比较。如果模式文件不仅包含完整的单词,还包含子字符串,那么这将不起作用,因为对于 file2 中的给定单词,您将不知道在 file1 中查找什么。

    学习 SQL 肯定是个好主意,因为学习一些东西总是好的。它会悬停,不能解决您的问题,因为 SQL 将遭受上述相同的二次效应。如果索引适用于您的问题,它可能会简化索引。

    您最好的选择可能是退后一步,重新考虑您的问题。

    【讨论】:

      【解决方案3】:

      你可以试试ack。他们说它比 grep 快。

      你可以试试parallel

      parallel --progress -a file1 'grep -F {} file2'
      

      Parallel 还有许多其他有用的开关来加快计算速度。

      【讨论】:

        【解决方案4】:

        Grep 无法处理这么多查询,而且在那个量下,修复grep -f bug 也无济于事,这使得它变得如此缓慢。

        file1 和 file2 是否都由每行一个单词组成?这意味着您正在寻找精确匹配,我们可以通过 awk 快速完成:

        awk 'NR == FNR { query[$0] = 1; next } query[$0]' file1 file2
        

        NR(记录数,行号)仅等于第一个文件的 FNR(文件特定记录数),我们在其中填充哈希,然后移至下一行。第二个子句检查其他文件的行是否与保存在我们哈希中的行匹配,然后打印匹配的行。

        否则,您将需要迭代:

        awk 'NR == FNR { query[$0]=1; next }
             { for (q in query) if (index($0, q)) { print; next } }' file1 file2
        

        我们不仅要检查哈希,还必须遍历每个查询,看看它是否与当前行匹配 ($0)。这很多慢了,但不幸的是这是必要的(尽管我们至少匹配纯字符串而不使用正则表达式,所以它可能会更慢)。当我们有匹配时,循环停止。

        如果您真的想将查询文件的行作为正则表达式进行计算,您可以使用$0 ~ q 而不是更快的index($0, q)。请注意,这使用POSIX extended regular expressions,与grep -Eegrep 大致相同,但没有bounded quantifiers ({1,7}) 或GNU extensions 用于word boundaries (\b) 和shorthand character classes (@987654 @,\w 等)。

        只要哈希值不超过 awk 可以存储的值,这些应该可以工作。这可能低至 2.1B 条目(基于最高 32 位有符号整数的猜测)或与您的可用内存一样高。

        【讨论】:

          猜你喜欢
          • 2012-07-14
          • 2015-01-02
          • 1970-01-01
          • 1970-01-01
          • 2014-10-12
          • 2019-04-30
          • 2013-08-03
          • 1970-01-01
          • 2012-04-28
          相关资源
          最近更新 更多