- - PR -
ランダムアクセスファイルを使ってバイナリサーチ
1
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2004-10-07 00:03
今100メガ以上のテキストファイルがあり、これから効率よくデータを抽出しようとしています。このファイルには各行にナンバーが昇順で振ってあります。
No. Data1 Data2 1 AAAA DDDDDD 2 BBBB XXXXX といった感じのファイルです。 あるナンバーを持つデータをこのファイルから抜き出すということを、約10万回繰り返し行うので、効率を考えて、ランダムアクセスファイルを用いて、バイナリサーチをして、求めるデータを抜き出そうとしました。 ところが、 比較的、小さいナンバーを検索しているうちはいいのですが、大きいナンバーを検索していると、フリーメモリーの現象量が大きくなって来ています(すぐにフリーメモリーの量が少なくなってしまいます)。そのせいなのかはわからないのですが、途中でぴたっとプログラムが止まってしまいます。でもメモリエラーはでません。 ちょっと困っています。 そこで質問なのですが、ランダムアクセスファイルは、あまりメモリを消費しないで直アクセスができると思っていたのですが、seek(long byte)で大きなバイト数を指定した場合というのは、やはりメモリの消費が大きいのでしょうか? あと、自分なりの解決法として、数が大きい場合は降順に並べ直したファイルに対して検索をかけるようにしようと考えているのですが、もしみなさんでしたら、このような大きなファイルにアクセスする場合には、どのように対処されますか? お知恵をお貸しいただければ幸いです。 | ||||||||||||
|
投稿日時: 2004-10-07 00:09
Dreamさん、こんにちは。
私なら RDBを使用します。 | ||||||||||||
|
投稿日時: 2004-10-07 00:09
ソートして検索するのであれば、2分検索アルゴリズムでやれば、かなり高速で検索できます
さて表題の件ですが、自分ならDBに保存してSELECT文で検索します。 | ||||||||||||
|
投稿日時: 2004-10-07 00:21
そうですね。
RDBを忘れてました。解決しそうで、安心しました。 どうもありがとうございました。 あと、まだ気になるのですが、 ランダムアクセスファイルはseek()で大きなバイト数を与えるのを繰り返すと、効率はよくないものなんでしょうか? | ||||||||||||
|
投稿日時: 2004-10-07 08:03
unibon です。こんにちわ。
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/io/RandomAccessFile.html#seek(long) を使われているのですよね? 確かめてはいませんが、seek でメモリが大量に消費されるとは思えません。プログラムの他の個所が原因ではないでしょうか。なお、止まったところで、もし Windows ならば Ctrl + Break を押すと、その瞬間のスタックトレースが表示されますので、糸口になる可能性もあります。
テキストファイルのまま、今のやりかたでやるのもアリだと思います。なお、降順にしたほうが良いのはあくまでも数が大きい場合だけですから、根本的な解決策にはならないような気もします(出現する値の頻度次第ですけど)。 ファイル容量にもよりますが、100MB程度ならば、メモリーにぜんぶまるごと読み込んでしまってから、メモリー上で検索しても良いのではないでしょうか。でも1GB位になると大きすぎてやはり難しいですね。 (Java は起動時のオプションで -Xmx を指定すれば使用可能なヒープメモリーを増やせます。) | ||||||||||||
|
投稿日時: 2004-10-07 09:13
こんにちは、さくらばです。
RandomAccessFile とはいえども、ファイルにはシーケンシャルにしかアクセスできない のですから、seek で大きな数字をいれたら時間がかかってしまうのは当然だと思います。
そんなときには MemoryMappedFile を使うのが常套手段です。 java.nio.channels.FileChannel#map メソッドでファイルをマップすることができます。 マップする領域もヒープではなく、JNI で直接メモリを確保するので、ヒープ領域の サイズを気にすることもありません。 また、マップした後は java.nio.ByteBuffer として扱えるので、RandomAccessFile に 比べたら検索のスピードは段違いです。 | ||||||||||||
|
投稿日時: 2004-10-07 13:38
unibon です。こんにちわ。
これは違うと思います。やはり RandomAccessFile はシーケンシャルアクセスではなくランダムアクセスのはずです。 確かめるためにフロッピーディスクに1MBほどの大きさのファイルを入れて、seek(そのファイルの容量 - 10) したあと、read(10バイト)してみましたが、5秒ほどで読み込めました。ファイルをシーケンシャルで読んでたら数十秒はかかるはずです。 | ||||||||||||
|
投稿日時: 2004-10-07 17:47
こんにちは、さくらばです。
ちょっと勇み足でした。すいません。 Java では FileInputStream クラスでも、RandomAccessFile クラスでも、JNI の部分で はモードが違うだけで同じシステムコールを呼び出しています。ですから、OS がファイ ルに対してランダムアクセスができるのであれば、ランダムアクセスになっていると思 います。 逆にいえば、Java のアプリケーションではどのようにランダムアクセスが実現されてい るかは気にしなくてもいいということだと思います。でも、実現方法によって実行時間 が全然違うのですから、本当は気になるところでもありますね。 ところで、本題の方の
に関してですが、これだけだとどこに原因があるかはよく分かりません。できれば追試が できるようなコードを示していただけるといいのですが... |
1