Apache Lucene(全文檢索引擎)—分詞器


目錄

  返回目錄:http://www.cnblogs.com/hanyinglong/p/5464604.html

  本項目Demo已上傳GitHub,歡迎大家fork下載學習:https://github.com/kencery/Lucene_Compass(項目內部有很詳細的注釋)

1.分詞器的作用

  a. 在創建索引的時候需要用到分詞器,在使用字符串搜索的時候也會用到分詞器,並且這兩個地方要使用同一個分詞器,否則可能會搜索不出來結果。

  b. 分詞器(Analyzer)的作用是把一段文本中的詞按規則取出所包含的所有詞,對應的是Analyzer類,這是一個抽象類(public abstract class org.apache.lucene.analysis.Analyzer),切分詞的具體規則是由子類實現的,所以對於不同的語言規則,要有不同的分詞器。

  c.關於分詞器的詳細運行代碼,請在GitHub上下載,下載地址:https://github.com/kencery/Lucene_Compass/tree/master/Lucene_5.5,對應的分支為:lucene_five。

2.英文分詞器的原理

  a.英文的處理流程為:輸入文本,詞匯切分,詞匯過濾(去除停用詞),詞干提取(形態還原)、大寫轉小寫,結果輸出。

  b. 何為形態還原,意思是:去除單詞詞尾的形態變化,將其還原為詞的原形,這樣做可以搜索出更多有意義的結果,比如在搜索student的時候,同事也可以搜索出students的結果。

  c. 任何一個分詞法對英文的支持都是還可以的。

3.中文分詞器的原理

  a.中文分詞比較復雜,並沒有英文分詞那么簡單,這主要是因為中文的詞與詞之間並不是像英文那樣用空格來隔開,

因為不是一個字就是一個詞,而且一個詞在另外一個地方就可能不是一個詞,如:"我們是中國人","是中"就不是一個詞,對於中文分詞,通常有三種方式:單字分詞、二分法分詞、詞典分詞。

    a.1 單字分詞:就是按照中文一個字一個字的進行分詞,比如:"我們是中國人",分詞的效果就是"我","們","是","中","國","人",StandardAnalyzer分詞法就是單字分詞。

    a.2 二分法分詞:按照兩個字進行切分,比如:"我們是中國人",分詞的效果就是:"我們","們是","是中","中國","國人",CJKAnalyzer分詞法就是二分法分詞

    a.3 詞庫分詞:按照某種算法構造詞,然后去匹配已建好的詞庫集合,如果匹配到就切分出來成為詞語,通常詞庫分詞被認為是最好的中文分詞算法,如:"我們是中國人",分詞的效果就是:"我們","中國人",極易分詞

MMAnalyzer、庖丁分詞、IkAnalyzer等分詞法就是屬於詞庫分詞。

  b.分詞器還有很大,請大家自行查詢,它們的實現基本一致,都是Analyzer的子類,故而可以很完美的繼承到Lucene中。

4.停用詞的規則

  a. 有些詞在文本中出現的頻率非常高,但是對文本所攜帶的信息基本不產生影響,例如英文的"a、an、the、of"或中文的"的、了、着、是",以及各種標點符號等,這樣的詞稱為停用詞,文本經過分詞處理后,停用詞通常會被過濾掉,不會被進行索引,在檢索的時候,用戶的查詢中如果含有停用詞,檢索系統也會將其過濾掉,這是因為用戶輸入哦查詢字符串也要進行分詞處理,排除停用詞可以礆蕢建立索引的速度,減小索引庫文件的大小。

5.分詞器的使用代碼

  1 package com.lyzj.kencery.unit;
  2 import java.io.StringReader;
  3 import org.apache.lucene.analysis.Analyzer;
  4 import org.apache.lucene.analysis.TokenStream;
  5 import org.apache.lucene.analysis.cjk.CJKAnalyzer;
  6 import org.apache.lucene.analysis.standard.StandardAnalyzer;
  7 import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
  8 import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
  9 import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;
 10 import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
 11 import org.junit.Test;
 12 import org.wltea.analyzer.lucene.IKAnalyzer;
 13 /**
 14  * 測試分詞器
 15  * 分詞器工作流程
 16  *     1.切分,將需要分詞的內容進行切分成每個單詞或者詞語
 17  *     2.去除停用詞,有些詞在文本中出現的頻率非常高,但是對文本所攜帶的信息基本不產生影響,例如英文的“a、an、the、of”,或中文的“的、了、着、是”,以及各種標點符號等,
 18  * 這樣的詞稱為停用詞(stop word)。文本經過分詞之后,停用詞通常被過濾掉,不會被進行索引。在檢索的時候,用戶的查詢中如果含有停用詞,
 19  * 檢索系統也會將其過濾掉(因為用戶輸入的查詢字符串也要進行分詞處理)。排除停用詞可以加快建立索引的速度,減小索引庫文件的大小。
 20  *     3.對於英文字母,轉為小寫,因為搜索的時候不區分大小寫
 21  * @author kencery
 22  *
 23  */
 24 public class AnalyzerTest {
 25 
 26     /**
 27      * StandardAnalyzer分詞法測試,對中文支持不是很好,將中文分詞成1個字(單字分詞)
 28      * @throws Exception 
 29      */
 30     @Test
 31     public void StandardAnalyzerTest() throws Exception{
 32         //英文測試
 33         String text="An IndexWriter creaters and maintains an index.";
 34         Analyzer analyzer=new StandardAnalyzer();
 35         displayTokens(analyzer,text);
 36         //中文測試
 37         String text1="Lucene是全文檢索框架";
 38         displayTokens(analyzer,text1);    
 39     }
 40 
 41      /**
 42       * CJKAnalyzerTest分詞法測試,對中文支持不是很好,將中文分詞成2個字(二分法分詞)
 43       * 
 44       * @throws Exception
 45       */
 46     @Test
 47     public void CJKAnalyzerTest() throws Exception{
 48         //英文測試
 49         String text="An IndexWriter creaters and maintains an index.";
 50         Analyzer analyzer=new CJKAnalyzer();
 51         displayTokens(analyzer,text);
 52         //中文測試
 53         String text1="Lucene是全文檢索框架";
 54         displayTokens(analyzer,text1);    
 55     }
 56 
 57      /**
 58       * IKAnalyzerTest分詞法測試,對中文支持很好,詞庫分詞
 59       * @throws Exception
 60       */
 61     @Test
 62     public void IKAnalyzerTest() throws Exception{
 63         //英文測試
 64         String text="An IndexWriter creaters and maintains an index.";
 65         Analyzer analyzer=new IKAnalyzer();
 66         displayTokens(analyzer,text);
 67         //中文測試
 68         String text1="韓迎龍易淘食的Lucene是全文檢索框架";
 69         displayTokens(analyzer,text1);    
 70     }
 71 
 72     /**
 73      * 使用指定的分詞器對指定的文本進行分詞,並打印出分出的詞,測試分詞法的方法
 74      * 備注說明:這里注意版本問題,暫無方法解決
 75      * @param analyzer
 76      * @param text
 77      * @throws Exception
 78      */
 79     public static void displayTokens(Analyzer analyzer, String text) throws Exception {
 80         System.out.println("當前使用的分詞器:" + analyzer.getClass().getName());
 81         //分詞流,即將對象分詞后所得的Token在內存中以流的方式存在,也說是說如果在取得Token必須從TokenStream中獲取,而分詞對象可以是文檔文本,也可以是查詢文本。
 82         TokenStream tokenStream = analyzer.tokenStream("content", new StringReader(text));
 83         //表示token的首字母和尾字母在原文本中的位置。比如I'm的位置信息就是(0,3),需要注意的是startOffset與endOffset的差值並不一定就是termText.length(),
 84         //因為可能term已經用stemmer或者其他過濾器處理過;
 85         OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
 86         //這個有點特殊,它表示tokenStream中的當前token與前一個token在實際的原文本中相隔的詞語數量,用於短語查詢。比如: 在tokenStream中[2:a]的前一個token是[1:I'm ],
 87         //它們在原文本中相隔的詞語數是1,則token="a"的PositionIncrementAttribute值為1;
 88         PositionIncrementAttribute positionIncrementAttribute = tokenStream.addAttribute(PositionIncrementAttribute.class);
 89 
 90         //問題說明:這里需要使用jdk1.7,如果使用jdk1.8或者jdk1.6則會出現報錯信息
 91         //>>如果大家誰有相應的解決方案,請提交到git上我將會合並或者添加我的QQ我們互相討論
 92         CharTermAttribute charTermAttribute= tokenStream.addAttribute(CharTermAttribute.class);
 93 
 94         //表示token詞典類別信息,默認為“Word”,比如I'm就屬於<APOSTROPHE>,有撇號的類型;
 95         TypeAttribute typeAttribute = tokenStream.addAttribute(TypeAttribute.class);
 96         tokenStream.reset();
 97 
 98         int position = 0;
 99         while (tokenStream.incrementToken()) {
100           int increment = positionIncrementAttribute.getPositionIncrement();
101           if(increment > 0) {
102             position = position + increment;
103           }
104           int startOffset = offsetAttribute.startOffset();
105           int endOffset = offsetAttribute.endOffset();
106           String term ="輸出結果為:"+ charTermAttribute.toString();
107           System.out.println("第"+position+"個分詞,分詞內容是:[" + term + "]" + ",分詞內容的開始結束位置為:(" + startOffset + "-->" + endOffset + "),類型是:" + typeAttribute.type());
108         }
109         tokenStream.close();
110     }
111 }

 

6. Compass簡單介紹(不建議使用)

  a. 已經不建議使用,因為官方已停止更新,支持的Lucene的最高版本為2.4,而當前Lucene的版本已經到了5.5。

  b. 因為是學習,所以簡單寫了一個Compass的Demo,下載地址:https://github.com/kencery/Lucene_Compass/tree/master/Compass_2.2,項目內部有詳細的代碼備注。

  c.這里有一篇別人寫的Compass博客,個人感覺非常好,地址:http://yufenfei.iteye.com/blog/1683546

 

   備注:接下來將使用ElasticSearch來做搜索。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM