web-dev-qa-db-ja.com

ソートされたファイルを効率的に検索

各行に1つの文字列を含む大きなファイルがあります。文字列がファイル内にあるかどうかをすばやく判断できるようにしたいと思います。理想的には、これはバイナリチョップ型アルゴリズムを使用して行われます。

一部のグーグルは、バイナリ検索アルゴリズムを使用して、指定されたプレフィックスで始まるすべての文字列を見つけて出力することを約束する-bフラグを持つlookコマンドを明らかにしました。残念ながら、正しく動作していないようで、ファイル内にあることがわかっている文字列に対してnullの結果を返します(同等のgrep検索によって適切に返されます)。

このファイルを効率的に検索するための別のユーティリティや戦略を知っている人はいますか?

10
Matt

greplookには本質的な違いがあります。

特に明記されていない限り、grepは行内のどこかにパターンを見つけます。 lookの場合、マンページの状態:

look —指定された文字列で行を表示しますbeginning

私はlookを頻繁に使用していませんが、試したささいな例ではうまく機能しました。

多分少し遅い答え:

Sgrepが役立ちます。

Sgrep(sorted grep)は、ソートされた入力ファイルで検索キーに一致する行を検索し、一致する行を出力します。大きなファイルを検索する場合、sgrepは従来のUnix grepよりもはるかに高速ですが、大きな制限があります。

  • すべての入力ファイルは、通常ファイルでソートする必要があります。
  • ソートキーは行の先頭から開始する必要があります。
  • 検索キーは、行の先頭でのみ一致します。
  • 正規表現はサポートされていません。

ここからソースをダウンロードできます: https://sourceforge.net/projects/sgrep/?source=typ_redirect

およびここのドキュメント: http://sgrep.sourceforge.net/

別の方法:

ファイルの大きさはわかりませんが、並行して試す必要があるかもしれません:

https://stackoverflow.com/questions/9066609/fastest-possible-grep

私は常に100 GBを超えるサイズのファイルでgrepを実行しますが、それはうまく機能します。

3
memorybox

必要に応じてreally fast(O(1)fast)ハッシュセットを作成して調べることができます。事前に構築されたハッシュセットをファイルに保存してプローブできる実装を見つけることができませんでしたwithoutファイル全体をメモリに読み込む必要があるので、 自分でロールバックしました

ハッシュセットを構築します(-b/--build):

./hashset.py --build string-list.txt strings.pyhashset

ハッシュセットをプローブします(-p/--probe):

./hashset.py --probe strings.pyhashset \
    'Is this string in my string list?' 'What about this one?'

…または標準入力で検索する文字列を使用:

printf '%s\n' 'Is this string in my string list?' 'What about this one?' |
./hashset.py --probe strings.pyhashset

終了ステータスのみに関心がある場合は、--probe/-qオプションを使用して--quietの出力を静止できます。

if ./hashset.py --quiet --probe strings.pyhashset ...; then
    echo 'Found'
else
    echo 'Not found'
fi

その他のオプションについては、-h/--helpオプションまたは付属のREADMEファイルからアクセスできる使用法の説明を参照してください。

0
David Foerster

sgrepはあなたのために働くかもしれません:

Sudo apt-get install sgrep
sgrep -l '"needle"' haystack.txt

プロジェクトページ http://sgrep.sourceforge.net/ のコメント:

Sgrepはバイナリ検索アルゴリズムを使用します。これは非常に高速ですが、ソートされた入力が必要です。

ただし、挿入については、データベースを使用するよりも優れたソリューションはないと思います: https://stackoverflow.com/questions/10658380/Shell-one-liner-to-add-a-line-to-a- sort-file/33859372#33859372

ファイルを断片にハッシュし、必要な部分だけをgrepできます。

for line in $(cat /usr/share/dict/american-english | tr '[:upper:]' '[:lower:]' | sort | uniq)
do
    prefix=$(echo $line | md5sum - | cut -c 1-2)
    mkdir -p $prefix
    echo $line | gzip >> $prefix/subwords
done

ルックアップは次のようになります。

    prefix=$(echo $Word | md5sum - | cut -c 1-2)
    zgrep -m 1 -w Word $prefix/subwords

これは2つのことを行います。

  1. 圧縮ファイルの読み取りと書き込み。一般的に、ディスク(非常に遅い)ではなくCPU(非常に速い)に負荷をかける方が高速です。
  2. ほぼ等しい分布を得るために物事をハッシュし、各ピースのサイズを減らすために、必要に応じてより短いまたはより長いハッシュを使用できます(ただし、ネストされたサブディレクトリを使用することをお勧めします)
0
Joe