質問

2つのファイルがあります A-nodes_to_delete そして B-nodes_to_keep. 。各ファイルには、数値 ID を含む行が多数含まれています。

にある数値IDのリストが必要です nodes_to_delete でも入っていない nodes_to_keep, 、例えば alt text .

PostgreSQL データベース内でこれを実行すると、不当に遅くなります。Linux CLIツールを使用してbashでそれを行う巧妙な方法はありますか?

アップデート: これは Python のジョブのように見えますが、ファイルは非常に大きいです。私はいくつかの同様の問題を解決しました uniq, sort そしていくつかの集合論のテクニック。これは、同等のデータベースよりも約 2 ~ 3 桁高速でした。

役に立ちましたか?

解決

COMM のコマンドは、それを行います。

他のヒント

誰かがどのように数ヶ月前にSHに正確にこれを行うには教えてくれた、そして私はしばらくの間、それを見つけることができませんでした...と見ながら、私はあなたの質問につまずきました。ここでは、次のとおりです。

set_union () {
   sort $1 $2 | uniq
}

set_difference () {
   sort $1 $2 $2 | uniq -u
}

set_symmetric_difference() {
   sort $1 $2 | uniq -u
}

使用comm - それは2行ごとにファイルをソート比較します。

。 あなたの質問に

短い答え

このコマンドはkeepNodesの行deleteNodesに固有の行を返しますが、しません。

comm -1 -3 <(sort keepNodes) <(sort deleteNodes)
<時間>

例のセットアップ

レッツ・keepNodesdeleteNodesという名前のファイルを作成し、commコマンドのソートされていない入力としてそれらを使用します。

$ cat > keepNodes <(echo bob; echo amber;)
$ cat > deleteNodes <(echo bob; echo ann;)

デフォルトでは、引数なしCOMMを実行すると、このレイアウトで3列を出力します:

lines_unique_to_FILE1
    lines_unique_to_FILE2
        lines_which_appear_in_both

引数なしで実行COMM、上記の例のファイルを使用します。 3つの列に注意します。

$ comm <(sort keepNodes) <(sort deleteNodes)
amber
    ann
        bob

抑止列出力

抑止カラム1、2または-N 3を有します。列が非表示になっていることに注意してくださいが、空白はアップ縮みます。

$ comm -1 <(sort keepNodes) <(sort deleteNodes)
ann
    bob
$ comm -2 <(sort keepNodes) <(sort deleteNodes)
amber
    bob
$ comm -3 <(sort keepNodes) <(sort deleteNodes)
amber
    ann
$ comm -1 -3 <(sort keepNodes) <(sort deleteNodes)
ann
$ comm -2 -3 <(sort keepNodes) <(sort deleteNodes)
amber
$ comm -1 -2 <(sort keepNodes) <(sort deleteNodes)
bob
ソートは重要です!

あなたが最初のファイルをソートすることなく、COMMを実行すると、それがソートされていないファイルに関するメッセージを表示して優雅に失敗します。

comm: file 1 is not in sorted order

commは特にユースケースのこの種のために設計され、それはソートされた入力を必要とした。

awkそれはセットの違いを見つけるために、まっすぐ進むかなりだと間違いなく、このためのより良いツールである、sort、と申し出さらなる柔軟性を必要としません。

awk 'NR == FNR { a[$0]; next } !($0 in a)' nodes_to_keep nodes_to_delete

おそらく、たとえば、あなたは唯一の非負の数を表すラインの違いを見つけるしたいと思います:

awk -v r='^[0-9]+$' 'NR == FNR && $0 ~ r {
    a[$0]
    next
} $0 ~ r && !($0 in a)' nodes_to_keep nodes_to_delete
あなたはpostgresの中でそれを行うには良い方法を必要とするかもしれない、私はかなりの賭けあなたは、フラット・ファイルを使用してそれを行うためのより高速な方法を見つけることができませんことを。あなたは、内側の両方のID COLSは、それは非常に高速である必要がありますインデックス化されていると仮定して単純結合を行うことができる必要があります。

だから、これは他の回答とは若干異なっています。私は、C ++コンパイラは、正確に「LinuxのCLIツール」であると言うことはできませんが、g++ -O3 -march=native -o set_diff main.cppを実行している(main.cppに以下のコードでは、トリックを行うことができます):

#include<algorithm>
#include<iostream>
#include<iterator>
#include<fstream>
#include<string>
#include<unordered_set>

using namespace std;

int main(int argc, char** argv) {
    ifstream keep_file(argv[1]), del_file(argv[2]);
    unordered_multiset<string> init_lines{istream_iterator<string>(keep_file), istream_iterator<string>()};
    string line;
    while (getline(del_file, line)) {
        init_lines.erase(line);
    }
    copy(init_lines.begin(),init_lines.end(), ostream_iterator<string>(cout, "\n"));
}

使用するように、単に(set_diff B AA Bあるので、しないBnodes_to_keepを実行し、得られた差は、標準出力に印刷されます。

注私がしたことforgone数C ++シンプルなコードを維持するためのベストプラクティスます。

多くの追加の速度の最適化は、(より多くのメモリの価格で)作ることができます。 mmapも大規模なデータセットのために特に有用であろうが、それははるかに関与コードを作ると思います。

あなたは、データ・セットが大であることを述べたので、

、私は一度にnodes_to_deleteラインの読み取りがメモリ消費量を削減するために、良いアイデアかもしれないと思いました。あなたのnodes_to_deleteでdupesがたくさんある場合は、上記のコードで撮影したアプローチは、特に効率的ではありません。また、順序は保持されません。

<時間>

コピーしてbashにペーストしやすい何か(すなわちmain.cppの作成をスキップ):

g++ -O3 -march=native -xc++ -o set_diff - <<EOF
#include<algorithm>
#include<iostream>
#include<iterator>
#include<fstream>
#include<string>
#include<unordered_set>

using namespace std;

int main(int argc, char** argv) {
        ifstream keep_file(argv[1]), del_file(argv[2]);
        unordered_multiset<string> init_lines{istream_iterator<string>(keep_file), istream_iterator<string>()};
        string line;
        while (getline(del_file, line)) {
                init_lines.erase(line);
        }
        copy(init_lines.begin(),init_lines.end(), ostream_iterator<string>(cout, "\n"));
}
EOF
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top