辞書アプリの改良:部分一致(2)

メタインデックス作成ツールのソース

辞書アプリの改良:部分一致(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
	}
}

メモ

  • メタインデックスの形式を考え直す
  • メタインデックス作成ツールの必要メモリサイズを減らす