私が持っている9.8ギガバイト私が持っているGZIPファイルA.gzおよびその他のファイルがある79メガバイト各行のいくつかのテキストを持っていB.TXT。BのテキストをA.gzでgrepして、新しいファイルに書き込みたい。
最初は、このコマンドを使用しました
zgrep -f B.txt A.gz > C.xml
しかし、このコマンドはハングし、非常に長い間空のC.xmlを作成しました。
それからグーグルした後、私はB.txtが巨大であるため、テキストをバッファに保持するときにハングすることを知りました。
だから私はテキストファイルをそれぞれ20000テキストに分割しました
split -l 20000 -a 4 B.txt B
Baaaa、Baaabなどのファイルを作成しました。
次に、各ファイルを繰り返し処理しました
cd B
for f in B*; do
zgrep -f "$f" ../A.gz >> C.xml
done
それは非常に遅く、まだ実行中です。
これに対するより良いアプローチはありますか?
gzファイルをgunzip圧縮すると、パフォーマンスが向上しますか?
更新
-Fで試してみました
zgrep -F -f "$f" ../A.gz >> C.xml
これは少し速いですが、それでも他のオプションが必要です
私は次のようなxmlを持っています
<root>
<source>source1</source>
<Id>123</Id>
<category>ABC</category>
</root>
<root>
<source>source2</source>
<Id>123</Id>
<category>XYZ</category>
</root>
ここでidは同じ123ですが、カテゴリはABCとXYZで異なります
(入力はABC、DEF、GHI、JKLM、NOPなどの限られたカテゴリのセットです)最初はABCとしてカテゴリを持っているので、カテゴリABCに基づいて、そのID、つまり123を見つけます。これらに属するすべてのIDを書き込み続けます。以下のように、新しいファイル、つまりB.txt(IDのリスト)にカテゴリを入力します
zgrep -E 'ABC|DEF|GHI|JKLM|NOP' A.gz | sed -n 's:.*<Id>\(.*\)</Id>.*:\1:p' | uniq > B.txt
後で、このIDを繰り返し処理して、すべてのxmlをフェッチします。このようにして、ID123に属するカテゴリABCとXYZの両方のxmlタグを取得します。
79MByteのgrep「文字列」を操作するのは面倒です。B.txt
本当に正規表現の行ですか、それとも同じ文字列に固定されていますか?それらが固定文字列である場合、それらはA.gz
行全体で同じように表示されますか?非圧縮の何行がの行A.gz
と一致すると予想されますB.txt
か?
の行がB.txt
実際には正規表現または行の部分文字列であるA.gz
場合、巨大な正規表現を処理するように設計されたHyperScanのようなものを使用せざるを得ない場合があります。ディスク容量がある場合は、解凍A.gz
してHyperScanに処理を任せることができます(HyperScanがシェルを検索しているときに、シェルをその場で解凍することもできます)。試すもう1つの方法は、ripgrepです。
で固定の全行文字列を処理していB.txt
て、圧縮さA.gz
れていないものに比較的小さい(たとえば、100MB程度)一致する行が含まれている場合は、前処理するプログラムを作成する方がよい場合がありますA.gz
。
B.txt
して、ハッシュを覚えておくことができますA.gz
ハッシュの行が以前のハッシュと同じものになっているかどうかを確認します。もしそうなら、あなたC.txt
はさらなる処理の準備ができている行を(例えばに)印刷しますB.txt
は、各行が入っているかどうかをより厳密にチェックしますC.txt
(または、その逆-どのファイルが小さかったかによって異なります)。初期近似フィルタリングを行うためのいくつかのコードは次のようになります。
# Do a quick APPROXIMATE filter of lines in FILENEEDLES that are also in
# FILEHAYSTACK
import sys
def main():
if len(sys.argv) < 2:
print("usage: %s FILENEEDLES FILEHAYSTACK" % sys.argv[0])
exit(1)
first_filename = sys.argv[1]
second_filename = sys.argv[2]
line_hashes = set()
with open(first_filename, "r") as f:
for line in f:
line_hashes.add(hash(line))
with open(second_filename, "r") as f:
for line in f:
if hash(line) in line_hashes:
sys.stdout.write(line)
if __name__ == "__main__":
main()
例えば:
$ echo -e '1\n2\n3' > B.txt
$ echo -e '2\n3\n4\5' | gzip > A.gz
$ ./approxfilter.py B.txt <(gzip -dc A.gz) > candidates.txt
$ cat candidates.txt
2
3
ここで、candidates.txtをチェックして、出力される行がそれらの行と完全に一致するかどうかを確認する必要がありますB.txt
(ただし、これはより小さく、はるかに簡単な問題であり、候補行の数が「少ない」場合は、上記のプログラムを変更してすべてを実行することもできます。 「そして、メモリに保持できる範囲内で十分です)。(質問者は後でコメントで、完全な行の長さの文字列では機能しないため、このアプローチは機能しないことを明らかにしました)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加