0

私は1つのファイルを持っています

base.txt
5071111111
5071111112
5071111113
5071111114
..... around 15 lakh numbers

そして別のファイル

status.txt
5071111112,sended
5071111113,failed
..... 

実際のシナリオは、メッセージを送信するための携帯電話番号を含むベース ファイルと、status.txt に格納されている各番号のメッセージのステータスを含むその他のファイルがあります。

今私の仕事は、2つのファイルをマージし、共通ファイルを次のように保持することです

merged.txt
5071111111
5071111112,sended
5071111113,failed
5071111114
....... and so on

status.txt から 1 つの数字、つまり「5071111112,sended」を取得し、base.txt と比較する通常の解決策を試しました。数字が見つからない場合は、その数字を merged.txt にコピーし、数字が見つかった場合は、その更新されたコンテンツをコピーします。 merged.txt の番号。

これで、merged.txt がベース ファイルとして機能します。

また、status.txt ファイルは定期的に入ってくるので、比較して新しい merging.txt ファイルを作成し、以前のものを削除して新しいファイルの名前を変更するプロセスが延々と続きます。

RandomAccessFile クラスも試しましたが、ここで説明されている問題と同様のデータ切り捨ての問題に直面しています。 リンク

Stackoverflow に投稿された回答はほとんど読んでいませんが、多くは上記の方法を提案しています。他に解決策はありますか。

4

5 に答える 5

1

この問題に対処するにはいくつかの方法がありますが、それらは Java 固有のものではありません (これは人々が回避しているものです)。これらは CS に関する質問です。

あなたがする必要があるのは、セット「A」とセット「B」の共通部分を見つけることです。Java 2 では、準備が整ったクラス (HashSet と TreeSet) でこれを行うことができます。これらは両方とも、同等の Map タイプによってサポートされています。

この問題に対処するには、次の 2 つの方法があります。

1) ファイルをバイナリ検索ツリーのチャンクにソートします(これは、ソートされたツリーのサブツリーもソートされることを意味します)。この場合、より小さなソートのために処理できると思われるメモリ空間を使用して、ソートされたサブツリーを作成します (一般に、メモリ空間はファイル内のエントリ数のモジュラスになります)。ソートの中間結果を一時ファイルに書き込むことができます。

2)ブルーム フィルターを使用して、考慮される要素の数を大幅に減らします。スーパー セットのブルーム フィルターを作成します (この場合、ステータス コードのないファイルになります)。次に、フィルターを使用して、他のセットに決して含まれない要素を確実に削除します。

明確なスーパー セットがない場合は、クロス フィルタリングを適用して、セット「A」のブルーム ビットのセットを作成し、「A」に確実に含まれていないブルーム ビットを「B」から削除してから、このプロセスを逆にすることができます。 .

最終的に得られるのは、「おそらく」交差する 2 つの劇的に小さいセットです。この時点で、おそらく setA.retainAll(setB) を使用して共通要素を生成できます。

セットが扱いにくい場合は、以下の #1 または #3 を適用する前に #2 を使用できます。

3) cassandra といくつかの virts を使用してmap-reduce ジョブをセットアップします。いくつかの EC2 インスタンスをセットアップするか、社内の virt を使用できます。あなたの仕事ははるかに速く完了します。

于 2013-05-03T18:13:44.130 に答える
0

ファイルが極端に大きくない場合は、ファイルを読み取って、その数をマップに入れることができます。

Map<String(Phonenumber), String(Status)>

次に、2 番目のファイルを 1 行ずつ読み、ステータスをマップに入れます。

完了したら、Map を繰り返し処理し、それをマージされたファイルに書き込みます。

for(Entry<String, String>e  : map.entrySet())
  write(e.getvalue());

ただし、すべてをメモリにロードできる場合は簡単に実行できるため、これらのファイルが実際にどれだけ大きいかによって異なります。ギガバイトについて話している場合、機能しない可能性があります。

cygwin をインストールして unix シェル コマンドを使用できるようにするオプションがある場合は、次のようにします (または、それらを 1 つのファイルにまとめて並べ替えることができる場合)。

sort -u base status > temporary

このようにして、すべての数字が互いにすぐ後にあることが保証されます。次に、各行を読み取る小さな Java スクリプトを作成します。メモリ内の番号を保持し、さらにステータス メッセージが来たら、それらを追加します。次の番号が前と同じでない場合、最終結果となるマージされたファイルに書き込みます。

于 2013-05-03T16:55:20.690 に答える
0

2 つの入力ストリームを作成し、base.txt と status.txt の最初の行を読み取り、それらを比較します。

ループ:

-数値が等しい場合 (status.txt でサブストリングを作成し、それを base.txt と比較します)、base.txt から行を書き込み、両方の行を解放します。

-それらが等しくない場合は、番号が小さい方を書き、それを実現します

次の行を読む

これは、番号順に並べられている場合にのみ機能します (それ以外の場合は、最初に並べ替える必要があります)。

実行時間が問題にならない場合は、簡単にバブル ソートを実装して行ごとに実行できます ;)

于 2013-05-03T16:57:59.203 に答える
0

あなたの投稿の助けを借りて、1つのソリューションを考えて実装し、望ましい結果を得ました. それが良い解決策かどうかを確認したいだけです。

最初のステップで、base.txt ファイルをソートしています

2 番目のステップでは、約 10,00,000 の数値を含む base.txt ファイルを多くのファイルに分割し、各ファイルに 1,00,000 の数値を含めます (完全な 10,00,000 の数値を取得する代わりに、次のことを考慮してファイルを分割しています)。 HashMap などを使用してメモリに書き込むと、メモリ不足エラーになる場合があります)。

ベースファイルがチャンクに分割された後。分割ファイル内に存在する番号を追跡する 1 つのインデックス ファイルを維持しています。

limit                 file-name
1-1,00,000            split0.txt
1,00,001-2,00,000     split1.txt

ここで、status.txt ファイルの読み取りを開始し、そこからマージする必要がある番号を 1 つ選択します。インデックス ファイルの助けを借りて、どのファイルを選択して更新する必要があるかを正確に知ることができます。

現在、チャンクを含むファイルには約 1,00,000 の数値が含まれているため (たとえば、 split4.txt )、それを hashMap に取り込み、正しいレコードを更新して、そのファイルに hashMap を再度書き込みます。

このソリューションを使用して目的の結果を得ています。確認したいのですが、それが正しいアプローチであるか、何か不足しています。

ありがとう

于 2013-05-05T19:17:16.790 に答える