標籤:lucene分詞 分詞器 自訂分詞器 同義字分詞器
在較複雜的lucene搜尋業務情境下,直接網上下載一個作為項目的分詞器,是不夠的。那麼怎麼去評定一個中文分詞器的好與差:一般來講,有兩個點;詞庫和搜尋效率,也就是演算法。
lucene的倒排列表中,不同的分詞單元有不同的PositionIncrementAttribute,如果兩個詞有著相同位置屬性,比如:我定義美國和中國這兩個詞在倒排列表中是同一個位置,那麼搜尋美國的話,中國也能出來。這就是同義字搜尋原理。
以下代碼(用mmseg的 Tokenizer 去切詞之後,然後再做同義字):
先自訂分詞器:
package hhc;import java.io.Reader;import org.apache.lucene.analysis.Analyzer;import org.apache.lucene.analysis.TokenStream;import com.chenlb.mmseg4j.Dictionary;import com.chenlb.mmseg4j.MaxWordSeg;import com.chenlb.mmseg4j.analysis.MMSegTokenizer;/** * 寫一個分詞器,一般可以參照原來分詞器是怎麼寫法的 * @author hhc * */public class MySameAnalyzer extends Analyzer{//同義字private SamewordContext samewordContext=null;public MySameAnalyzer(SamewordContext samewordContext){this.samewordContext=samewordContext;}@Overridepublic TokenStream tokenStream(String fieldName, Reader reader) {// Dictionary dic=Dictionary.getInstance();return new MySameTokenFilter(new MMSegTokenizer(new MaxWordSeg(dic), reader),samewordContext);}}
然後再對TokenStream流做同義字處理
package hhc;import java.io.IOException;import java.util.Stack;import org.apache.lucene.analysis.TokenFilter;import org.apache.lucene.analysis.TokenStream;import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;import org.apache.lucene.util.AttributeSource;public class MySameTokenFilter extends TokenFilter {// 分詞單元資訊private CharTermAttribute cta = null;// 位置資訊private PositionIncrementAttribute pia = null;// 狀態private AttributeSource.State current;// 同義字集合private Stack<String> sames = null;private SamewordContext samewordContext=null;protected MySameTokenFilter(TokenStream input,SamewordContext samewordContext) {super(input);cta = input.addAttribute(CharTermAttribute.class);pia = input.addAttribute(PositionIncrementAttribute.class);sames=new Stack<String>();this.samewordContext=samewordContext;}@Overridepublic boolean incrementToken() throws IOException {try {if (sames!=null&&sames.size()> 0) {// 刪除對象在堆棧,然後返回的對象上的函數值,並且擷取這個同義字String str = sames.pop();// 還原狀態restoreState(current);cta.setEmpty();cta.append(str);pia.setPositionIncrement(0);return true;}// 如果流中沒有資料了。if (!input.incrementToken())return false;/** * 流中有資料的話,進行相應的同義字 */// 處理切分出來的詞的資訊if (existAddSameword(cta.toString())) {// 把目前狀態先儲存current = captureState();}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}return true;}/** * 判斷是否該分詞單元存在 * * @param word * @return */private boolean existAddSameword(String word) { String[] words=samewordContext.getSameword(word);if (words != null) {for (String s : words) {sames.push(s);}return true;}return false;}}
lucene構建同義字分詞器