【问题标题】:Fast string search in a very large file在非常大的文件中快速搜索字符串
【发布时间】:2016-10-08 04:49:46
【问题描述】:

在包含字符串的文件中搜索行的最快方法是什么。我有一个包含要搜索的字符串的文件。这个小文件(smallF)包含大约 50,000 行,看起来像:

stringToSearch1
stringToSearch2
stringToSearch3

我必须在一个更大的文件(大约 1 亿 行)中搜索所有这些字符串。如果此较大文件中的任何行包含搜索字符串,则打印该行。

到目前为止我想出的最好的方法是

grep -F -f smallF largeF

但这不是很快。 smallF 中只有 100 个搜索字符串,大约需要 4 分钟。对于超过 50,000 个搜索字符串,这将花费大量时间。

有没有更有效的方法?

【问题讨论】:

  • 没有。这是最有效的方法,除非您可以并行搜索,或者编写一个特殊用途的程序。
  • fgrep 而不是 grep -F 应该会快一点...
  • @Jahid:来自 GNU grep 的手册页:“fgrep 与 grep -F 相同。
  • @Jahid 澄清一下这是/usr/bin/fgrep#!/bin/sh exec grep -F "$@"的内容

标签: linux bash grep


【解决方案1】:

我曾经注意到使用-E 或多个-e 参数比使用-f 更快。请注意,这可能不适用于您的问题,因为您要在较大的文件中搜索 50,000 个字符串。但是,我想向您展示可以做什么以及可能值得测试的内容:

这是我注意到的细节:

有 1.2GB 的文件填充随机字符串。

>ls -has | grep string
1,2G strings.txt

>head strings.txt
Mfzd0sf7RA664UVrBHK44cSQpLRKT6J0
Uk218A8GKRdAVOZLIykVc0b2RH1ayfAy
BmuCCPJaQGhFTIutGpVG86tlanW8c9Pa
etrulbGONKT3pact1SHg2ipcCr7TZ9jc
.....

现在我想使用不同的 grep 方法搜索字符串“ab”、“cd”和“ef”:

  1. 使用不带标志的 grep,一次搜索一个:
    grep "ab" strings.txt > m1.out  
    2,76s user 0,42s system 96% cpu 3,313 total
    
    grep "cd" strings.txt >> m1.out  
    2,82s user 0,36s system 95% cpu 3,322 total
    
    grep "ef" strings.txt >> m1.out  
    2,78s user 0,36s system 94% cpu 3,360 total

因此,搜索总共需要将近 10 秒

  1. 在 search.txt 中使用带有 -f 标志的 grep 和搜索字符串

     >cat search.txt
      ab
      cd
      ef
    
     >grep -F -f search.txt strings.txt > m2.out  
     31,55s user 0,60s system 99% cpu 32,343 total
    

由于某些原因,这需要将近 32 秒

  1. 现在使用-e 的多种搜索模式

     grep -E "ab|cd|ef" strings.txt > m3.out  
     3,80s user 0,36s system 98% cpu 4,220 total
    

     grep --color=auto -e "ab" -e "cd" -e "ef" strings.txt > /dev/null  
     3,86s user 0,38s system 98% cpu 4,323 total
    

使用-E 的第三种方法只用了4.22 秒 来搜索文件。

现在让我们检查结果是否相同:

cat m1.out | sort | uniq > m1.sort  
cat m3.out | sort | uniq > m3.sort
diff m1.sort m3.sort
#

diff 不产生输出,这意味着找到的结果是相同的。

也许想试一试,否则我建议您查看线程“Fastest possible grep”,请参阅 Cyrus 的评论。

【讨论】:

    【解决方案2】:

    注意:我知道以下不是基于 bash 的解决方案,但鉴于您的搜索空间很大,需要并行解决方案。


    如果您的机器有多个内核/处理器,您可以在Pythran 中调用以下函数来并行化搜索:

    #!/usr/bin/env python
    
    #pythran export search_in_file(string, string)
    def search_in_file(long_file_path, short_file_path):
        _long = open(long_file_path, "r")
    
        #omp parallel for schedule(guided)
        for _string in open(short_file_path, "r"):
            if _string in _long:
                print(_string)
    
    if __name__ == "__main__":
        search_in_file("long_file_path", "short_file_path")
    

    注意:在幕后,Pythran 采用 Python 代码并尝试积极地将其编译成速度非常快的 C++。

    【讨论】:

      【解决方案3】:

      您可能想试试siftag。特别是 Sift 列出了一些与 grep 相比相当令人印象深刻的基准。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-08-23
        • 2014-08-07
        • 2017-04-06
        • 2013-01-20
        • 2014-03-17
        • 2013-01-06
        • 1970-01-01
        相关资源
        最近更新 更多