程式扎記: [ Lucene 文章收集 ] Lucene 的 CJKAnalyzer 分析器 (v3.6)

標籤

2013年10月17日 星期四

[ Lucene 文章收集 ] Lucene 的 CJKAnalyzer 分析器 (v3.6)

來源自 這裡 
Preface: 
在 CJKAnalyzer 分析器中對中文漢字,以每兩個字作為一個 Token,例如 A,B,C,D 是四個中文漢字,使用 CJKAnalyzer 分析器分詞後一共得到三個詞條如下: 
AB,BC,CD

CJKAnalyzer 分析器在對中文分詞方面比 StandardAnalyzer 分析器要好一點。因為根據中文的習慣,包括搜索的時候鍵入關鍵字的習慣,中文的詞(大於一個漢字)比單個漢字的頻率應該高一些. 

但是,在設置相同的過濾詞條文​​本以後,CJKAnalyzer 分析器的缺點就是產生了冗餘會​​比較大,相對於 StandardAnalyzer 分析器來說。使用 StandardAnalyzer 分析器可以考慮在以字作為詞條時,通過過濾詞條文​​本來優化分詞。而 CJKAnalyzer 分析器在給定的過濾詞條文​​本的基礎之上,獲取有用的詞條實際是一個在具有一定中文語言習慣的基礎上能夠獲得最高的期望. 

Example: 
如果將 "不錯" 加入過濾詞組 (stop word list): 
  1. package demo.test;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileReader;  
  5. import java.io.Reader;  
  6. import java.util.HashSet;  
  7. import java.util.Set;  
  8.   
  9. import org.apache.lucene.analysis.Analyzer;  
  10. import org.apache.lucene.analysis.TokenStream;  
  11. import org.apache.lucene.analysis.cjk.CJKAnalyzer;  
  12. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;  
  13. import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;  
  14. import org.apache.lucene.util.Version;  
  15.   
  16. public class CJKAnalyzerTest {  
  17.   
  18.     /** 
  19.      * REF: 
  20.      *  - http://stackoverflow.com/questions/2638200/how-to-get-a-token-from-a-lucene-tokenstream 
  21.      * @param args 
  22.      */  
  23.     public static void main(String[] args) {  
  24.         try {   
  25.             File file = new File("data/Doc4.txt");            
  26.             Reader reader = new FileReader(file);     
  27.             Set stopwords = new HashSet();  
  28.             stopwords.add("不錯");  
  29.             Analyzer a = new CJKAnalyzer(Version.LUCENE_30, stopwords);               
  30.             TokenStream ts = a.tokenStream("", reader);   
  31.             OffsetAttribute offsetAttribute = ts.getAttribute(OffsetAttribute.class);  
  32.             CharTermAttribute termAttribute = ts.getAttribute(CharTermAttribute.class);           
  33.             int n = 0;   
  34.             while (ts.incrementToken()) {   
  35.                 int startOffset = offsetAttribute.startOffset();  
  36.                 int endOffset = offsetAttribute.endOffset();  
  37.                 String term = termAttribute.toString();  
  38.                 n++;   
  39.                 System.out.println("Token("+n+") 的內容為:"+term);   
  40.             }   
  41.             System.out.println("==共有詞條"+n+"條==");      
  42.         }   
  43.         catch (Exception e) {e.printStackTrace(); }   
  44.     }  
  45. }  
執行結果如下: 
Token(1) 的內容為:今天
Token(2) 的內容為:天的
Token(3) 的內容為:的天
Token(4) 的內容為:天氣
Token(5) 的內容為:氣不
Token(6) 的內容為:你想
Token(7) 的內容為:想要
Token(8) 的內容為:要出
Token(9) 的內容為:出去
Token(10) 的內容為:去嗎
==共有詞條10條==

上面的結果產生的無用的 Token 比例大概佔50%左右,而且,如果被分詞的文件很大,存儲也有一定的開銷。相對於使用 StandardAnalyzer 分析器,使用 CJKAnalyzer 分析器的存儲開銷是StandardAnalyzer 分析器的兩倍。然而無論是那種分詞方式,都要考慮對重複的詞條進行處理。 

CJKAnalyzer 分析器的分詞工具是 CJKTokenizer 核心類。至於如果過濾,這和 StandardAnalyzer 分析器很相似,但是它只是設置了在程序中指定了一個 stopTable。可以參考StandardAnalyzer 分析器實現讀取文件系統中的文本的實現

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!