目錄 1. Apache Lucene(全文檢索引擎)—創建索引:http://www.cnblogs.com/hanyinglong/p/5387816.html 2. Apache Lucene(全文檢索引擎)—搜索:http://www.cnblogs.com/hanyinglong/p/53 ...
目錄
1. Apache Lucene(全文檢索引擎)—創建索引:http://www.cnblogs.com/hanyinglong/p/5387816.html
2. Apache Lucene(全文檢索引擎)—搜索:http://www.cnblogs.com/hanyinglong/p/5391269.html
3. Apache Lucene(全文檢索引擎)—分詞器:http://www.cnblogs.com/hanyinglong/p/5395600.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來做搜索。