各行にWordを含むテキストファイルがあります。ファイルのサイズは800GBです。アルファベット順に並べ替える必要があります。
私はWindowssortプログラムを使ってみました:
sort.exe input.txt /o output.txt
ソートを完了するのに十分なメインメモリがありません。
32GBのRAMがあるので、ソートに10GBのメモリを指定してみます。
sort.exe input.txt /o output.txt /M 10000000
私は得ます:
警告:指定されたメモリサイズは、利用可能なページングメモリに縮小されています。
入力レコードが最大長を超えています。最大値を大きくしてください。
私の選択肢は何ですか?
フリーウェアコマンドラインソートユーティリティCMSort を試してください。
複数の一時ファイルを使用して、最後にそれらをマージします。
CMsortは、調整済みメモリーに達するまで入力ファイルのレコードを読み取っています。その後、レコードはソートされて一時ファイルに書き込まれます。これはすべてのレコードが処理されるまで繰り返されます。最後に、すべての一時ファイルは出力ファイルにマージされます。利用可能なメモリが十分であれば、一時ファイルは書き込まれず、マージも必要ありません。
あるユーザーは、130,000,000バイトのファイルをソートしたと報告しています。
自分でコードを微調整したい場合は、 巨大なテキストファイルのソート - CodeProject - "テキストファイル内の行をソートするアルゴリズムで利用可能なサイズを超えるものもあります。記憶」
もう1つの選択肢は、ファイルをデータベースにロードすることです。 E.G MySQLとMySQL Workbench。
データベースは大きなファイルを扱うのに最適な候補です。
入力ファイルに改行で区切られた単語だけが含まれている場合、これは難しいことではありません。
データベースとMySQL Workbenchをインストールした後、これがあなたがする必要があることです。
最初にスキーマを作成します(引数の値を増やすことでこれを変更することはできますが、これは単語が255文字を超えないようにするためです)。最初の列 "idwords"は主キーです。
CREATE SCHEMA `tmp` ;
CREATE TABLE `tmp`.`words` (
`idwords` INT NOT NULL AUTO_INCREMENT,
`mywords` VARCHAR(255) NULL,
PRIMARY KEY (`idwords`));
EGこれですべての単語がテーブルにインポートされます(この手順は完了するまでしばらく時間がかかります。最初は小さい単語のファイルでテストを実行し、フォーマットが同じであることを確認したらこのテストを実行することをお勧めします)。大きい方(テーブルを切り捨てる。IEそれをクリアして完全なデータセットを読み込む)。
LOAD DATA LOCAL INFILE "C:\\words.txt" INTO TABLE tmp.words
LINES TERMINATED BY '\r\n'
(mywords);
このリンクは、ロードに適した形式にするのに役立ちます。 https://dev.mysql.com/doc/refman/5.7/ja/load-data.html
E.G最初の行をスキップする必要がある場合は、次のようにします。
LOAD DATA LOCAL INFILE "H:\\words.txt" INTO TABLE tmp.words
-- FIELDS TERMINATED BY ','
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES
(mywords);
最後にソートしたファイルを保存してください。これはあなたのPCにもよりますがしばらく時間がかかるかもしれません。
SELECT tmp.words.mywords
FROM tmp.words
order by tmp.words.mywords asc
INTO OUTFILE 'C:\\sorted_words.csv';
好きなようにデータを自由に検索することもできます。 E.Gこれはあなたに昇順で最初の50の単語を与えます(0番目または最初の単語から始めます)。
SELECT tmp.words.mywords
FROM tmp.words
order by tmp.words.mywords asc
LIMIT 0, 50 ;
がんばろう
ピート
sort
順序付けされたファイルと順序付けされていないファイルのソートに使用される多くのアルゴリズムがあります。 [ 1 ]。
これらのアルゴリズムはすべて実装されているので、既にテスト済みのプログラムを選択してください。
coreutils (Linuxから。ただしWindowsでも使用可能 [ 2 ])、マルチコアプロセッサで並列実行できるsort
コマンドがあります。通常はそれで十分です。
あなたのファイルがとても大きい場合、処理を分割するのを手伝うことができます(split -l
)、おそらく並列オプション(--parallel
)を使用して、そして結果のソート-m
オプション付きのordered-chunks ( マージソート )。
これを行う多くの方法の1つがここで説明されています (ファイルの分割、単一のチャンクの順序付け、順序付けられたチャンクの結合、一時ファイルの削除)。
注:
各行の単語が(英語のような)限られた語彙からのものであるならば、あなたはTreeMapと記録カウント(ここでmはユニークな値の数です)を使ってO(n + m log m)時間でリストを分類できます。
それ以外の場合は、Javaライブラリ ビッグソーター を使用できます。入力をソートされた中間ファイルに分割し、それらを効率的にマージします(全体のO(nlogn))。ファイルを並べ替えるには、次のようにします。
Sorter.serializerTextUtf8()
.input(inputFile)
.output(outputFile)
.loggerStdOut() // display some progress
.sort();
私は、ランダムに生成された16文字の単語で1.7GBのファイル(100m行)を作成し、142秒で上記のようにソートし、使用している方法のO(n log n)の計算の複雑さに基づいています。私のi5 2.3GHzラップトップPCとSSDをシングルスレッドでソートするには約24時間かかります。
Peter Hに代わる解決策を提供するために、テキストファイルに対するSQLスタイルのコマンドを可能にするプログラム q があります。以下のコマンドは、SQL Workbenchをインストールしたりテーブルを作成したりする必要なしに、同じことを実行します(fileと同じディレクトリにあるPromptコマンドから実行します)。
q "select * from words.txt order by c1"
c1
は列1の省略形です。
重複する単語を除外することができます
q "select distinct c1 from words.txt order by c1"
そして出力を別のファイルに送る
q "select distinct c1 from words.txt order by c1" > sorted.txt