mirror of https://github.com/apache/lucene.git
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:
parent
2f159c4059
commit
995c5b9ef1
|
@ -142,6 +142,9 @@ New Features
|
|||
* LUCENE-3305: Added Kuromoji morphological analyzer for Japanese.
|
||||
(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
|
||||
BlockJoinQuery to ToParentBlockJoinQuery, so that you can now do
|
||||
joins in both parent to child and child to parent directions.
|
||||
|
|
|
@ -54,11 +54,13 @@ public class Viterbi {
|
|||
|
||||
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();
|
||||
|
||||
|
@ -137,7 +139,7 @@ public class Viterbi {
|
|||
char[] surfaceForm = node.getSurfaceForm();
|
||||
int offset = node.getOffset();
|
||||
int length = node.getLength();
|
||||
if (length > SEARCH_MODE_LENGTH_KANJI) {
|
||||
if (length > SEARCH_MODE_KANJI_LENGTH) {
|
||||
boolean allKanji = true;
|
||||
// check if node consists of only kanji
|
||||
for (int pos = 0; pos < length; pos++) {
|
||||
|
@ -148,9 +150,9 @@ public class Viterbi {
|
|||
}
|
||||
|
||||
if (allKanji) { // Process only Kanji keywords
|
||||
pathCost += (length - SEARCH_MODE_LENGTH_KANJI) * SEARCH_MODE_PENALTY;
|
||||
} else if (length > SEARCH_MODE_LENGTH) {
|
||||
pathCost += (length - SEARCH_MODE_LENGTH) * SEARCH_MODE_PENALTY;
|
||||
pathCost += (length - SEARCH_MODE_KANJI_LENGTH) * SEARCH_MODE_KANJI_PENALTY;
|
||||
} else if (length > SEARCH_MODE_OTHER_LENGTH) {
|
||||
pathCost += (length - SEARCH_MODE_OTHER_LENGTH) * SEARCH_MODE_OTHER_PENALTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
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
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -30,6 +17,19 @@ import org.apache.lucene.util._TestUtil;
|
|||
* 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 {
|
||||
private final Segmenter segmenter = new Segmenter(Mode.EXTENDED);
|
||||
private final Analyzer analyzer = new Analyzer() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
サプライズギフト サプライズギフト
|
Loading…
Reference in New Issue