読者です 読者をやめる 読者になる 読者になる

Igo: GAE版の辞書データ読み込み速度向上

Java library speed

igo-gaeを修正して、辞書データ読み込みを速度を向上させた。
※ igo-gaeの現在のバージョンは0.0.2。

修正内容概要

オリジナルのIgoでは、データ読み込みにはnio系パッケージのjava.nio.channels.FileChannelとjava.nio.MappedByteBufferを使っていた。

// MappedByteBufferを使ったデータ(int列)読み込み例
FileChannel in = new FileInputStream("/path/to/dic-data").getChannel();
MappedByteBuffer buffer = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size());

int[] data = new int[(int)in.size()/4];
buffer.asIntBuffer().get(data);

この方法だとバイナリファイルのデータを高速に読み出すことができる。
ただGoogle App EngineではMappedByteBufferクラスが使用不可となっていたため、初期のigo-gae(ver0.0.1)ではjava.io.DataInputStreamを使った方法で代替していた。

// DataInputStreamを使ったデータ(int列)読み込み例
DataInputSream in = new DataInputStream(new BufferedInputStream(new FileInputStream("/path/to/dic-data")));

int[] data = new int[new File("/path/to/dic-data").length()/4];
for(int i=0; i < data.length; i++) 
  data[i] = in.readInt();

今回のver0.0.2では、データ読み込み部に再びnio系のパッケージを採用。
MappedByteBufferは使えないので、代わりにjava.nio.ByteBufferを使用。
ByteBufferに対して必要な分(= ファイルサイズ)の領域を明示的に確保し、そこに(コンストラクタ内で)あらかじめファイルの全データを読み込んでおくようにした。
こうしておけば、後の使い方はMappedByteBufferとただのByteBufferの間にほとんど差異はない。

// (マッピングなしの)ByteBufferを使ったデータ(int列)読み込み
FileChannel in = new FileInputStream("/path/to/dic-data").getChannel();
ByteBuffer buffer = ByteBuffer.allocateDirect((int)in.size()/4);
in.read(buffer);  // ここでファイルのデータを全て読み込んでおく
buffer.flip(); 

int[] data = new int[(int)in.size()/4];
buffer.asIntBuffer().get(data);

この方法は、初めのMappedByteBufferを使うものに比べると若干速度は落ちるが、DataInputStreamを使う方法比べればだいぶ高速。

現時点のigo-gaeのサンプルWebアプリ(http://igo-morp.appspot.com/)はver0.0.2のソースで動いているが、スピンアップ時間がver0.0.1では5秒前後掛かっていたのが、現在は2.5秒前後、と半分程度に短縮されていた。