辞書アプリの改良:部分一致(2)
関連エントリ
StarDictの辞書アプリ - Random Note
辞書アプリの改良 - Random Note
辞書アプリの改良:初期化処理の高速化(1) - Random Note
辞書アプリの改良:初期化処理の高速化(2) - Random Note
辞書アプリの改良:コマンド化 - Random Note
辞書アプリの改良:部分一致(1) - Random Note
メタインデックス作成ツールのソース
辞書アプリの改良:部分一致(1) - Random Noteで定義したメタインデックス作成ツールのソースはこんな感じ。
しかし、ちょっとメタインデックスの形式に重複が多すぎる。
辞書インデックスファイル2.9MB、辞書ファイル5.3MBのテストデータのメタインデックスファイルは10MB。
うーん。形式を変更した方がいいかもしれない。ま、あとで考えよう。
それと、このソースはデフォルトのヒープサイズでは厳しい。これも後で考える。
def indexes = loadCompleteIndex() List metaList = [] int i=0 for (idx in indexes) { metaList.addAll(idx.toMetaIndexList()) i++ if (i%10000 == 0) println ("parsing:" + (i*100/indexes.size()) + "%") } Collections.sort(metaList) def os = new BufferedOutputStream(new FileOutputStream("test.meta")) i = 0 for (m in metaList) { os.write(m.toBytes()) i++ if (i%10000 == 0) println ("writing:" + (i*100/metaList.size()) + "%") } os.close() def loadCompleteIndex(indexOffset = 0, indexLength = -1) { if (indexOffset < 0) indexOffset = 0 RandomAccessFile randomFile = new RandomAccessFile("test.idx", "r") if (indexLength == -1) indexLength = randomFile.length() def buf = new byte[indexLength] randomFile.seek(indexOffset) randomFile.read(buf) randomFile.close() def i=0 int offset = 0 int count = 0 def indexes = new ArrayList(); while (i<buf.length) { if (buf[i] == 0) { def idx = new Index(buf, offset, i-offset+9) if (idx.word.length() > 0) indexes.add(idx) offset = i+9 i = i+8 count++ } i++ if (i%10000 == 0) println ("loading:" + (i*100/(indexLength)) + "%") } return indexes } class BaseIndex { def word def offset def length def cut(bytes, o, l) { def i=0 def buf = new byte[l] while (i < l) { buf[i] = bytes[i+o] i++ } return buf } def byte2int(byte[] bytes) { def result = 0 def i = 0 for (b in bytes) { result += (b & 0xff) * (int)(Math.pow(256, bytes.length-i-1)) i++ } return result } byte[] int2byte(intVal) { byte[] b = new byte[4]; b[0] = ((intVal & 0xFF000000) /(256*256*256)) b[1] = ((intVal & 0x00FF0000) /(256*256)) b[2] = ((intVal & 0x0000FF00) /256) b[3] = intVal & 0x000000FF return b } int startsWith(String string) { int i=0 while (i<word.length() && i<string.length()) { if (word.charAt(i) != string.charAt(i)) return word.charAt(i) - string.charAt(i) i++ } return word.length() < string.length() ? -1 : 0 } String toString() { return "{word: ${word},\toffset:${offset},\tlength:${length}}" } String normalize(String value) { return value.toLowerCase() } } class MetaIndex extends BaseIndex implements Comparable { public static final int INDEX_LENGTH = 24 public static final int INDEX_KEY_LENGTH = 12 public static final int INDEX_KEY_CHAR_LENGTH = 2 int wordOffset = 0 def MetaIndex(byte[] buf) { word = new String(buf, 0, INDEX_KEY_LENGTH, "UTF-8").trim() // 余計なバイト(0)をtrimで削除 offset = byte2int(cut(buf, INDEX_KEY_LENGTH, 4)) length = byte2int(cut(buf, INDEX_KEY_LENGTH+4, 4)) } def MetaIndex(String w, int o, int l, int wo) { word = w offset = o length = l wordOffset = wo } int compareTo(MetaIndex target) { if (word != target.word) return word.compareTo(target.word) if (offset != target.offset) return offset - target.offset if (wordOffset != target.wordOffset) return wordOffset - target.wordOffset return 0 } int compareTo(Object target) { if (target instanceof MetaIndex) return compareTo((MetaIndex)target) return -1 } byte[] toBytes() { byte[] buf = new byte[INDEX_LENGTH] Arrays.fill(buf, (byte)0) byte[] w = word.getBytes("UTF-8") byte[] o = int2byte(offset) byte[] l = int2byte(length) byte[] wo = int2byte(wordOffset) int i=0 for (b in w) { buf[i] = b i++ } i = 12 for (b in o) { buf[i] = b i++ } for (b in l) { buf[i] = b i++ } for (b in wo) { buf[i] = b i++ } return buf } } class Index extends BaseIndex { int indexOffset = 0 int indexLength = 0 def Index(byte[] buf, int o, int l) { word = new String(buf, o, l-9, "UTF-8").trim() offset = byte2int(cut(buf, o+l-8, 4)) length = byte2int(cut(buf, o+l-4, 4)) indexOffset = o indexLength = l } def toMetaIndexList() { List list = [] def val = normalize(word) int i=0 while (i <val.length()-MetaIndex.INDEX_KEY_CHAR_LENGTH -1) { list.add(new MetaIndex(val.substring(i, i+MetaIndex.INDEX_KEY_CHAR_LENGTH), indexOffset, indexLength, i)) i++ } if (val.length() == 1) list.add(new MetaIndex(val, indexOffset, indexLength, 0)) return list } }
メモ
- メタインデックスの形式を考え直す
- メタインデックス作成ツールの必要メモリサイズを減らす