【Lucene3.6.2入門系列】第04節_中文分詞器

  1. package com.jadyer.lucene;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.StringReader;  
  5.   
  6. import org.apache.lucene.analysis.Analyzer;  
  7. import org.apache.lucene.analysis.SimpleAnalyzer;  
  8. import org.apache.lucene.analysis.StopAnalyzer;  
  9. import org.apache.lucene.analysis.TokenStream;  
  10. import org.apache.lucene.analysis.WhitespaceAnalyzer;  
  11. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  12. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;  
  13. import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;  
  14. import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;  
  15. import org.apache.lucene.analysis.tokenattributes.TypeAttribute;  
  16. import org.apache.lucene.util.Version;  
  17.   
  18. import com.chenlb.mmseg4j.analysis.ComplexAnalyzer;  
  19. import com.chenlb.mmseg4j.analysis.MMSegAnalyzer;  
  20.   
  21. /** 
  22.  * 【Lucene3.6.2入門系列】第04節_中文分詞器 
  23.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  24.  * @see Lucene3.5推薦的四大分詞器:SimpleAnalyzer,StopAnalyzer,WhitespaceAnalyzer,StandardAnalyzer 
  25.  * @see 這四大分詞器有一個共同的抽象父類,此類有個方法public final TokenStream tokenStream(),即分詞的一個流 
  26.  * @see 假設有這樣的文本"how are you thank you",實際它是以一個java.io.Reader傳進分詞器中 
  27.  * @see Lucene分詞器處理完畢後,會把整個分詞轉換爲TokenStream,這個TokenStream中就保存所有的分詞信息 
  28.  * @see TokenStream有兩個實現類,分別爲Tokenizer和TokenFilter 
  29.  * @see Tokenizer---->用於將一組數據劃分爲獨立的語彙單元(即一個一個的單詞) 
  30.  * @see TokenFilter-->過濾語彙單元 
  31.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  32.  * @see 分詞流程 
  33.  * @see 1)將一組數據流java.io.Reader交給Tokenizer,由其將數據轉換爲一個個的語彙單元 
  34.  * @see 2)通過大量的TokenFilter對已經分好詞的數據進行過濾操作,最後產生TokenStream 
  35.  * @see 3)通過TokenStream完成索引的存儲 
  36.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  37.  * @see Tokenizer的一些子類 
  38.  * @see KeywordTokenizer-----不分詞,傳什麼就索引什麼 
  39.  * @see StandardTokenizer----標準分詞,它有一些較智能的分詞操作,諸如將'[email protected]'中的'yeah.net'當作一個分詞流 
  40.  * @see CharTokenizer--------針對字符進行控制的,它還有兩個子類WhitespaceTokenizer和LetterTokenizer 
  41.  * @see WhitespaceTokenizer--使用空格進行分詞,諸如將'Thank you,I am jadyer'會被分爲4個詞 
  42.  * @see LetterTokenizer------基於文本單詞的分詞,它會根據標點符號來分詞,諸如將'Thank you,I am jadyer'會被分爲5個詞 
  43.  * @see LowerCaseTokenizer---它是LetterTokenizer的子類,它會將數據轉爲小寫並分詞 
  44.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  45.  * @see TokenFilter的一些子類 
  46.  * @see StopFilter--------它會停用一些語彙單元 
  47.  * @see LowerCaseFilter---將數據轉換爲小寫 
  48.  * @see StandardFilter----對標準輸出流做一些控制 
  49.  * @see PorterStemFilter--還原一些數據,比如將coming還原爲come,將countries還原爲country 
  50.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  51.  * @see eg:'how are you thank you'會被分詞爲'how','are','you','thank','you'合計5個語彙單元 
  52.  * @see 那麼應該保存什麼東西,才能使以後在需要還原數據時保證正確的還原呢???其實主要保存三個東西,如下所示 
  53.  * @see CharTermAttribute(Lucene3.5以前叫TermAttribute),OffsetAttribute,PositionIncrementAttribute 
  54.  * @see 1)CharTermAttribute-----------保存相應的詞彙,這裏保存的就是'how','are','you','thank','you' 
  55.  * @see 2)OffsetAttribute-------------保存各詞彙之間的偏移量(大致理解爲順序),比如'how'的首尾字母偏移量爲0和3,'are'爲4和7,'thank'爲12和17 
  56.  * @see 3)PositionIncrementAttribute--保存詞與詞之間的位置增量,比如'how'和'are'增量爲1,'are'和'you'之間的也是1,'you'和'thank'的也是1 
  57.  * @see                               但假設'are'是停用詞(StopFilter的效果),那麼'how'和'you'之間的位置增量就變成了2 
  58.  * @see 當我們查找某一個元素時,Lucene會先通過位置增量來取這個元素,但如果兩個詞的位置增量相同,會發生什麼情況呢 
  59.  * @see 假設還有一個單詞'this',它的位置增量和'how'是相同的,那麼當我們在界面中搜索'this'時 
  60.  * @see 也會搜到'how are you thank you',這樣就可以有效的做同義詞了,目前非常流行的一個叫做WordNet的東西,就可以做同義詞的搜索 
  61.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  62.  * @see 中文分詞器 
  63.  * @see Lucene默認提供的衆多分詞器完全不適用中文 
  64.  * @see 1)Paoding--庖丁解牛分詞器,官網爲http://code.google.com/p/paoding(貌似已託管在http://git.oschina.net/zhzhenqin/paoding-analysis) 
  65.  * @see 2)MMSeg4j--據說它使用的是搜狗的詞庫,官網爲https://code.google.com/p/mmseg4j(另外還有一個https://code.google.com/p/jcseg) 
  66.  * @ses 3)IK-------https://code.google.com/p/ik-analyzer/ 
  67.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  68.  * @see MMSeg4j的使用 
  69.  * @see 1)下載mmseg4j-1.8.5.zip並引入mmseg4j-all-1.8.5-with-dic.jar 
  70.  * @see 2)在需要指定分詞器的位置編寫new MMSegAnalyzer()即可 
  71.  * @see 注1)由於使用的mmseg4j-all-1.8.5-with-dic.jar中已自帶了詞典,故直接new MMSegAnalyzer()即可 
  72.  * @see 注2)若引入的是mmseg4j-all-1.8.5.jar,則應指明詞典目錄,如new MMSegAnalyzer("D:\\Develop\\mmseg4j-1.8.5\\data") 
  73.  * @see     但若非要使用new MMSegAnalyzer(),則要將mmseg4j-1.8.5.zip自帶的data目錄拷入classpath下即可 
  74.  * @see 總結:直接引入mmseg4j-all-1.8.5-with-dic.jar就行了 
  75.  * @see ----------------------------------------------------------------------------------------------------------------------- 
  76.  * @create Aug 2, 2013 5:30:45 PM 
  77.  * @author 玄玉<http://blog.csdn.net/jadyer> 
  78.  */  
  79. public class HelloChineseAnalyzer {  
  80.     /** 
  81.      * 查看分詞信息 
  82.      * @see TokenStream還有兩個屬性,分別爲FlagsAttribute和PayloadAttribute,都是開發時用的 
  83.      * @see FlagsAttribute----標註位屬性 
  84.      * @see PayloadAttribute--做負載的屬性,用來檢測是否已超過負載,超過則可以決定是否停止搜索等等 
  85.      * @param txt        待分詞的字符串 
  86.      * @param analyzer   所使用的分詞器 
  87.      * @param displayAll 是否顯示所有的分詞信息 
  88.      */  
  89.     public static void displayTokenInfo(String txt, Analyzer analyzer, boolean displayAll){  
  90.         //第一個參數沒有任何意義,可以隨便傳一個值,它只是爲了顯示分詞  
  91.         //這裏就是使用指定的分詞器將'txt'分詞,分詞後會產生一個TokenStream(可將分詞後的每個單詞理解爲一個Token)  
  92.         TokenStream stream = analyzer.tokenStream("此參數無意義"new StringReader(txt));  
  93.         //用於查看每一個語彙單元的信息,即分詞的每一個元素  
  94.         //這裏創建的屬性會被添加到TokenStream流中,並隨着TokenStream而增加(此屬性就是用來裝載每個Token的,即分詞後的每個單詞)  
  95.         //當調用TokenStream.incrementToken()時,就會指向到這個單詞流中的第一個單詞,即此屬性代表的就是分詞後的第一個單詞  
  96.         //可以形象的理解成一隻碗,用來盛放TokenStream中每個單詞的碗,每調用一次incrementToken()後,這個碗就會盛放流中的下一個單詞  
  97.         CharTermAttribute cta = stream.addAttribute(CharTermAttribute.class);  
  98.         //用於查看位置增量(指的是語彙單元之間的距離,可理解爲元素與元素之間的空格,即間隔的單元數)  
  99.         PositionIncrementAttribute pia = stream.addAttribute(PositionIncrementAttribute.class);  
  100.         //用於查看每個語彙單元的偏移量  
  101.         OffsetAttribute oa = stream.addAttribute(OffsetAttribute.class);  
  102.         //用於查看使用的分詞器的類型信息  
  103.         TypeAttribute ta = stream.addAttribute(TypeAttribute.class);  
  104.         try {  
  105.             if(displayAll){  
  106.                 //等價於while(stream.incrementToken())  
  107.                 for(; stream.incrementToken() ;){  
  108.                     System.out.println(ta.type() + " " + pia.getPositionIncrement() + " ["+oa.startOffset()+"-"+oa.endOffset()+"] ["+cta+"]");  
  109.                 }  
  110.             }else{  
  111.                 System.out.println();  
  112.                 while(stream.incrementToken()){  
  113.                     System.out.print("[" + cta + "]");  
  114.                 }  
  115.             }  
  116.         } catch (IOException e) {  
  117.             e.printStackTrace();  
  118.         }  
  119.     }  
  120.       
  121.       
  122.     /** 
  123.      * 測試一下中文分詞的效果 
  124.      * @author 玄玉<http://blog.csdn.net/jadyer> 
  125.      */  
  126.     public static void main(String[] args) {  
  127.         String txt = "我來自中國黑龍江省哈爾濱市巴彥縣興隆鎮";  
  128.         displayTokenInfo(txt, new StandardAnalyzer(Version.LUCENE_36), false);  
  129.         displayTokenInfo(txt, new StopAnalyzer(Version.LUCENE_36), false);  
  130.         displayTokenInfo(txt, new SimpleAnalyzer(Version.LUCENE_36), false);  
  131.         displayTokenInfo(txt, new WhitespaceAnalyzer(Version.LUCENE_36), false);  
  132.         displayTokenInfo(txt, new MMSegAnalyzer(), false); //等價於new com.chenlb.mmseg4j.analysis.MaxWordAnalyzer()  
  133.         displayTokenInfo(txt, new com.chenlb.mmseg4j.analysis.SimpleAnalyzer(), false);  
  134.         displayTokenInfo(txt, new ComplexAnalyzer(), false);  
  135.     }  
  136. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章