LUCENE-3730: improve Kuromoji search mode heuristics

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1239061 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2012-02-01 11:03:17 +00:00
parent 2f159c4059
commit 995c5b9ef1
5 changed files with 239 additions and 22 deletions

View File

@ -142,6 +142,9 @@ New Features
* LUCENE-3305: Added Kuromoji morphological analyzer for Japanese. * LUCENE-3305: Added Kuromoji morphological analyzer for Japanese.
(Christian Moen, Masaru Hasegawa, Simon Willnauer, Uwe Schindler, Mike McCandless, Robert Muir) (Christian Moen, Masaru Hasegawa, Simon Willnauer, Uwe Schindler, Mike McCandless, Robert Muir)
* LUCENE-3730: Refine Kuromoji search mode (Mode.SEARCH) decompounding
heuristics. (Christian Moen via Robert Muir)
* LUCENE-3685: Add ToChildBlockJoinQuery and renamed previous * LUCENE-3685: Add ToChildBlockJoinQuery and renamed previous
BlockJoinQuery to ToParentBlockJoinQuery, so that you can now do BlockJoinQuery to ToParentBlockJoinQuery, so that you can now do
joins in both parent to child and child to parent directions. joins in both parent to child and child to parent directions.

View File

@ -54,11 +54,13 @@ public class Viterbi {
private static final int DEFAULT_COST = 10000000; private static final int DEFAULT_COST = 10000000;
private static final int SEARCH_MODE_LENGTH_KANJI = 3; private static final int SEARCH_MODE_KANJI_LENGTH = 2;
private static final int SEARCH_MODE_LENGTH = 7; private static final int SEARCH_MODE_OTHER_LENGTH = 7; // Must be >= SEARCH_MODE_KANJI_LENGTH
private static final int SEARCH_MODE_PENALTY = 10000; private static final int SEARCH_MODE_KANJI_PENALTY = 3000;
private static final int SEARCH_MODE_OTHER_PENALTY = 1700;
private static final char[] BOS = "BOS".toCharArray(); private static final char[] BOS = "BOS".toCharArray();
@ -137,7 +139,7 @@ public class Viterbi {
char[] surfaceForm = node.getSurfaceForm(); char[] surfaceForm = node.getSurfaceForm();
int offset = node.getOffset(); int offset = node.getOffset();
int length = node.getLength(); int length = node.getLength();
if (length > SEARCH_MODE_LENGTH_KANJI) { if (length > SEARCH_MODE_KANJI_LENGTH) {
boolean allKanji = true; boolean allKanji = true;
// check if node consists of only kanji // check if node consists of only kanji
for (int pos = 0; pos < length; pos++) { for (int pos = 0; pos < length; pos++) {
@ -148,9 +150,9 @@ public class Viterbi {
} }
if (allKanji) { // Process only Kanji keywords if (allKanji) { // Process only Kanji keywords
pathCost += (length - SEARCH_MODE_LENGTH_KANJI) * SEARCH_MODE_PENALTY; pathCost += (length - SEARCH_MODE_KANJI_LENGTH) * SEARCH_MODE_KANJI_PENALTY;
} else if (length > SEARCH_MODE_LENGTH) { } else if (length > SEARCH_MODE_OTHER_LENGTH) {
pathCost += (length - SEARCH_MODE_LENGTH) * SEARCH_MODE_PENALTY; pathCost += (length - SEARCH_MODE_OTHER_LENGTH) * SEARCH_MODE_OTHER_PENALTY;
} }
} }
} }

View File

@ -1,18 +1,5 @@
package org.apache.lucene.analysis.kuromoji; package org.apache.lucene.analysis.kuromoji;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.BaseTokenStreamTestCase;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.kuromoji.Segmenter.Mode;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.util.UnicodeUtil;
import org.apache.lucene.util._TestUtil;
/** /**
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
@ -30,6 +17,19 @@ import org.apache.lucene.util._TestUtil;
* limitations under the License. * limitations under the License.
*/ */
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.BaseTokenStreamTestCase;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.kuromoji.Segmenter.Mode;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.util.UnicodeUtil;
import org.apache.lucene.util._TestUtil;
public class TestExtendedMode extends BaseTokenStreamTestCase { public class TestExtendedMode extends BaseTokenStreamTestCase {
private final Segmenter segmenter = new Segmenter(Mode.EXTENDED); private final Segmenter segmenter = new Segmenter(Mode.EXTENDED);
private final Analyzer analyzer = new Analyzer() { private final Analyzer analyzer = new Analyzer() {

View File

@ -0,0 +1,72 @@
package org.apache.lucene.analysis.kuromoji;
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.BaseTokenStreamTestCase;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.kuromoji.Segmenter.Mode;
import org.apache.lucene.util.IOUtils;
public class TestSearchMode extends BaseTokenStreamTestCase {
private final static String SEGMENTATION_FILENAME = "search-segmentation-tests.txt";
private final Segmenter segmenter = new Segmenter(Mode.SEARCH);
private final Analyzer analyzer = new Analyzer() {
@Override
protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
Tokenizer tokenizer = new KuromojiTokenizer(segmenter, reader);
return new TokenStreamComponents(tokenizer, tokenizer);
}
};
/** Test search mode segmentation */
public void testSearchSegmentation() throws IOException {
InputStream is = TestSearchMode.class.getResourceAsStream(SEGMENTATION_FILENAME);
if (is == null) {
throw new FileNotFoundException("Cannot find " + SEGMENTATION_FILENAME + " in test classpath");
}
try {
LineNumberReader reader = new LineNumberReader(new InputStreamReader(is, IOUtils.CHARSET_UTF_8));
String line = null;
while ((line = reader.readLine()) != null) {
// Remove comments
line = line.replaceAll("#.*$", "");
// Skip empty lines or comment lines
if (line.trim().isEmpty()) {
continue;
}
if (VERBOSE) {
System.out.println("Line no. " + reader.getLineNumber() + ": " + line);
}
String[] fields = line.split("\t", 2);
String sourceText = fields[0];
String[] expectedTokens = fields[1].split("\\s+");
assertAnalyzesTo(analyzer, sourceText, expectedTokens);
}
} finally {
is.close();
}
}
}

View File

@ -0,0 +1,140 @@
###
### Tests for Kuromoji's search mode heuristic
###
### In search-mode, Kuromoji uses a heuristic to do extra splitting of words
### to get a decompounding effect useful for search. This file includes tests
### for this heuristic and demonstrates its usefulness, but also weaknesses.
###
### This file's format is as follows:
### <text><tab><token1> <token2> ... <token>
###
### This file should use UTF-8 encoding and there is one test per line. The
### text to be segmented and its expected surface form token sequence is
### separated by a tab ('\t'). Tokens are separated by a half-width space.
### Whitespace lines and lines starting with a '#' are ignored. Comments
### are not allowed on entry line.
###
### NOTE: These tests depends on IPADIC
###
### Revision history:
### - 2012-01-29: Initial version
###
##
## Organizations
##
# Kansai Internationl Airport
関西国際空港 関西 国際 空港
# Narita Airport
成田空港 成田 空港
# Haneda Airport
羽田空港 羽田 空港
# Nara Institute of Science and Technology
奈良先端科学技術大学院大学 奈良 先端 科学 技術 大学院 大学
# Tokyo University
東京大学 東京 大学
# Kyoto University
京都大学 京都 大学
# Kyoto University Baseball Club
京都大学硬式野球部 京都 大学 硬式 野球 部
##
## Katakana titles
##
# Senior Software Engineer
シニアソフトウェアエンジニア シニア ソフトウェア エンジニア
# Software Engineer
ソフトウェアエンジニア ソフトウェア エンジニア
# Senior Project Manager
シニアプロジェクトマネジャー シニア プロジェクト マネジャー
# Project Manager
プロジェクトマネジャー プロジェクト マネジャー
# Senior Sales Engineer
シニアセールスエンジニア シニア セールス エンジニア
# System Architect
システムアーキテクト システム アーキテクト
# Senior System Architect
シニアシステムアーキテクト シニア システム アーキテクト
# System Administrator
システムアドミニストレータ システム アドミニストレータ
システムアドミニストレーター システム アドミニストレーター
# Senior System Administrator
シニアシステムアドミニストレーター シニア システム アドミニストレーター
##
## Company names (several are fictitious)
##
# SoftBank Mobile
ソフトバンクモバイル ソフトバンク モバイル
# Alpine Materials
アルパインマテリアルズ アルパイン マテリアルズ
# Sapporo Holdings
サッポロホールディングス サッポロ ホールディングス
# Yamada Corporation
ヤマダコーポレーション ヤマダ コーポレーション
# Canon Semiconductor equipement NOTE: Semiconductor becomes semi + conductor
キヤノンセミコンダクターエクィップメント キヤノン セミ コンダクター エクィップメント
# Orental Chain
オリエンタルチエン オリエンタル チエン
# Ally Projects Japan NOTE: Becomes one token as プロジェクツ is not in IPADIC
アーリープロジェクツジャパン アーリープロジェクツジャパン
# Peter Pan Corporation
ピーターパンコーポレーション ピーター パン コーポレーション
# AIM Create
エイムクリエイツ エイムクリエイツ
# Mars Engineering
マースエンジニアリング マース エンジニアリング
# Fuji Protein Technology
フジプロテインテクノロジー フジ プロテイン テクノロジー
##
## Person names
##
# Michael Jackson
マイケルジャクソン マイケル ジャクソン
# Steve Jobs
スティーブジョブズ スティーブ ジョブズ
# Harry Potter NOTE: Becomes one token (short word)
ハリーポッター ハリーポッター
# Bill Gates NOTE: Becomes one token (short work)
ビルゲイツ ビルゲイツ
# Sean Connery NOTE: Becomes one token (okay)
ショーンコネリー ショーンコネリー
##
## Other nouns
##
# Holdings
ホールディングス ホールディングス
# Engineering
エンジニアリング エンジニアリング
# Software Engineering
ソフトウェアエンジニアリング ソフトウェア エンジニアリング
# Shopping center
ショッピングセンター ショッピング センター
# Game center (arcade) NOTE: One token because of short word
ゲームセンター ゲームセンター
# Christmas shopping
クリスマスショッピング クリスマス ショッピング
# Download file
ダウンロードファイル ダウンロード ファイル
# Technology
テクノロジー テクノロジー
# Lillehammer Olympics
リレハンメルオリンピック リレハンメル オリンピック
##
## Problematic terms
##
# JT Engineering NOTE: Becomes J Tien ginia ring (substrings are in IPADIC)
ジェイティエンジニアリング ジェイ ティエン ジニア リング
# Anchovy pasta NOTE: Become Anch yvipasta
アンチョビパスタ アンチ ョビパスタ
# Surprise gift NOTE: Becomes one token (surprise not in IPADIC)
サプライズギフト サプライズギフト