這篇文章的內容質(zhì)量不是很高,您可以在這里找到更新后的版本。Solo L正在努力提高這里所提供的內容的質(zhì)量。如果由于內容的質(zhì)量問(wèn)題給您造成了影響,我在此真誠的表示歉意!
眾所周知,英文是以詞為單位的,詞和詞之間是靠空格隔開(kāi),而中文是以字為單位,句子中所有的字連起來(lái)才能描述一個(gè)意思。例如,英文句子I am a student,用中文則為:“我是一個(gè)學(xué)生”。計算機可以很簡(jiǎn)單通過(guò)空格知道student是一個(gè)單詞,但是不能很容易明白“學(xué)”、“生”兩個(gè)字合起來(lái)才表示一個(gè)詞。把中文的漢字序列切分成有意義的詞,就是中文分詞,有些人也稱(chēng)為切詞。我是一個(gè)學(xué)生,分詞的結果是:我 是 一個(gè) 學(xué)生。
現有的分詞技術(shù)可分為三類(lèi):
基于字符串匹配的分詞
基于理解的分詞
基于統計的分詞
這篇文章中使用的是基于字符串匹配的分詞技術(shù),這種技術(shù)也被稱(chēng)為機械分詞。它是按照一定的策略將待分析的漢字串與一個(gè)“充分大的”詞庫中的詞條進(jìn)行匹配。若在詞庫中找到某個(gè)字符串則匹配成功(識別出一個(gè)詞)。按照掃描方向的不同,串匹配分詞方法可以分為正向匹配和逆向匹配;按照不同長(cháng)度優(yōu)先匹配的情況,可以分為最大(最長(cháng))匹配和最?。ㄗ疃蹋┢ヅ?;按照是否與詞性標注過(guò)程相結合,又可以分為單純分詞法和分詞與標注結合法。常用的幾種機械分詞方法如下:
正向最大匹配法(由左到右的方向)
逆向最大匹配法(由右到左的方向)
這個(gè)實(shí)現了機械分詞中正向最大匹配法的Lucene分詞器包括兩個(gè)類(lèi),CJKAnalyzer和CJKTokenizer,他們的源代碼如下:
package org.solol.analysis;
import java.io.Reader;
import java.util.Set;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.StopFilter;
import org.apache.lucene.analysis.TokenStream;
/**
* @author solo L
*
*/
public class CJKAnalyzer extends Analyzer {//實(shí)現了Analyzer接口,這是lucene的要求
public final static String[] STOP_WORDS = {};
private Set stopTable;
public CJKAnalyzer() {
stopTable = StopFilter.makeStopSet(STOP_WORDS);
}
@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
return new StopFilter(new CJKTokenizer(reader), stopTable);
}
}package org.solol.analysis;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.TreeMap;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.Tokenizer;
/**
* @author solo L
*
*/
public class CJKTokenizer extends Tokenizer {
//這個(gè)TreeMap用來(lái)緩存詞庫
private static TreeMap simWords = null;
private static final int IO_BUFFER_SIZE = 256;
private int bufferIndex = 0;
private int dataLen = 0;
private final char[] ioBuffer = new char[IO_BUFFER_SIZE];
private String tokenType = "word";
public CJKTokenizer(Reader input) {
this.input = input;
}
//這里是lucene分詞器實(shí)現的最關(guān)鍵的地方
public Token next() throws IOException {
loadWords();
StringBuffer currentWord = new StringBuffer();
while (true) {
char c;
Character.UnicodeBlock ub;
if (bufferIndex >= dataLen) {
dataLen = input.read(ioBuffer);
bufferIndex = 0;
}
if (dataLen == -1) {
if (currentWord.length() == 0) {
return null;
} else {
break;
}
} else {
c = ioBuffer[bufferIndex++];
ub = Character.UnicodeBlock.of(c);
}
//通過(guò)這個(gè)條件不難看出這里只處理了CJK_UNIFIED_IDEOGRAPHS,
//因此會(huì )丟掉其它的字符,如它會(huì )丟掉LATIN字符和數字
//這也是該lucene分詞器的一個(gè)限制,您可以在此基礎之上完善它,
//也很歡迎把您完善的結果反饋給我
if (Character.isLetter(c)
&& ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
tokenType = "double";
if (currentWord.length() == 0) {
currentWord.append(c);
} else {
//這里實(shí)現了正向最大匹配法
String temp = (currentWord.toString() + c).intern();
if (simWords.containsKey(temp)) {
currentWord.append(c);
} else {
bufferIndex--;
break;
}
}
}
}
Token token = new Token(currentWord.toString(), bufferIndex
- currentWord.length(), bufferIndex, tokenType);
currentWord.setLength(0);
return token;
}
//裝載詞庫,您必須明白它的邏輯和之所以這樣做的目的,這樣您才能理解正向最大匹配法是如何實(shí)現的
public void loadWords() {
if (simWords != null)return;
simWords = new TreeMap();
try {
InputStream words = new FileInputStream("simchinese.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(words,"UTF-8"));
String word = null;
while ((word = in.readLine()) != null) {
//#使得我們可以在詞庫中進(jìn)行必要的注釋
if ((word.indexOf("#") == -1) && (word.length() < 5)) {
simWords.put(word.intern(), "1");
if (word.length() == 3) {
if (!simWords.containsKey(word.substring(0, 2).intern())) {
simWords.put(word.substring(0, 2).intern(), "2");
}
}
if (word.length() == 4) {
if (!simWords.containsKey(word.substring(0, 2).intern())) {
simWords.put(word.substring(0, 2).intern(), "2");
}
if (!simWords.containsKey(word.substring(0, 3).intern())) {
simWords.put(word.substring(0, 3).intern(), "2");
}
}
}
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}這是我在當日的某新聞搞中隨意選的一段話(huà):
此外,巴黎市政府所在地和巴黎兩座體育場(chǎng)會(huì )掛出寫(xiě)有相同話(huà)語(yǔ)的巨幅標語(yǔ),這兩座體育場(chǎng)還安裝了巨大屏幕,以方便巴黎市民和游客觀(guān)看決賽。
分詞結果為:
此外 巴黎 市政府 所在地 和 巴黎 兩座 體育場(chǎng) 會(huì ) 掛出 寫(xiě)有 相同 話(huà)語(yǔ) 的 巨幅 標語(yǔ) 這 兩座 體育場(chǎng) 還 安裝 了 巨大 屏幕 以 方便 巴黎 市民 和 游客 觀(guān)看 決賽
這個(gè)lucene分詞器還比較脆弱,要想將其用于某類(lèi)項目中您還需要做一些工作,不過(guò)我想這里的lucene分詞器會(huì )成為您很好的起點(diǎn)。
Apache Lucene
聯(lián)系客服