3.6 Lucene基本檢索+關鍵詞高亮+分頁
阿新 • • 發佈:2017-05-10
trac 16px b- 標註 enter author amp 影響 重要
3.2節我們已經運行了一個Lucene實現檢索的小程序,這一節我們將以這個小程序為例,講一下Lucene檢索的基本步驟,同時介紹關鍵詞高亮顯示和分頁返回結果這兩個有用的技巧。
一、Lucene檢索的基本步驟
1 import java.nio.file.Paths; 2 import java.io.*; 3 4 import org.apache.lucene.analysis.standard.StandardAnalyzer; 5 import org.apache.lucene.document.Document; 6 import org.apache.lucene.index.DirectoryReader;Searcher7 import org.apache.lucene.queryparser.classic.QueryParser; 8 import org.apache.lucene.search.IndexSearcher; 9 import org.apache.lucene.search.Query; 10 import org.apache.lucene.search.ScoreDoc; 11 import org.apache.lucene.search.TopDocs; 12 import org.apache.lucene.store.Directory; 13 import org.apache.lucene.store.FSDirectory;14 import org.apache.lucene.util.Version; 15 16 /** 17 * @author csl 18 * @description: 19 * 依賴jar:Lucene-core,lucene-analyzers-common,lucene-queryparser 20 * 作用:使用索引搜索文件 21 */ 22 public class Searcher { 23 public static Version luceneVersion = Version.LATEST; 24 /** 25 * 查詢內容 26 */27 public static String indexSearch(String keywords){ 28 String res = ""; 29 DirectoryReader reader = null; 30 try{ 31 // 1、創建Directory 32 Directory directory = FSDirectory.open(Paths.get("index"));//在硬盤上生成Directory 33 // 2、創建IndexReader 34 reader = DirectoryReader.open(directory); 35 // 3、根據IndexReader創建IndexSearcher 36 IndexSearcher searcher = new IndexSearcher(reader); 37 // 4、創建搜索的query 38 // 創建parse用來確定搜索的內容,第二個參數表示搜索的域 39 QueryParser parser = new QueryParser("content",new StandardAnalyzer());//content表示搜索的域或者說字段 40 Query query = parser.parse(keywords);//被搜索的內容 41 // 5、根據Searcher返回TopDocs 42 TopDocs tds = searcher.search(query, 20);//查詢20條記錄 43 // 6、根據TopDocs獲取ScoreDoc 44 ScoreDoc[] sds = tds.scoreDocs; 45 // 7、根據Searcher和ScoreDoc獲取搜索到的document對象 46 int cou=0; 47 for(ScoreDoc sd:sds){ 48 cou++; 49 Document d = searcher.doc(sd.doc); 50 // 8、根據document對象獲取查詢的字段值 51 /** 查詢結果中content為空,是因為索引中沒有存儲content的內容,需要根據索引path和name從原文件中獲取content**/ 52 res+=cou+". "+d.get("path")+" "+d.get("name")+" "+d.get("content")+"\n"; 53 } 54 55 56 }catch(Exception e){ 57 e.printStackTrace(); 58 }finally{ 59 //9、關閉reader 60 try { 61 reader.close(); 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 } 66 return res; 67 } 68 public static void main(String[] args) throws IOException 69 { 70 System.out.println(indexSearch("你好")); //搜索的內容可以修改 71 } 72 }
搜索的過程總的來說就是將詞典及倒排表信息從索引中讀出來,根據用戶輸入的查詢語句合並倒排表,得到結果文檔集並對文檔進行打分的過程。
總結起來檢索有以下以下五個步驟:
1. 打開IndexReader指向索引文件夾。
1 Directory directory = FSDirectory.open(Paths.get("index")); 2 IndexReader reader = DirectoryReader.open(directory);IndexReader
這一步驟將磁盤上的索引信息讀入內存。
2. 創建IndexSearcher準備進行搜索。
1 IndexSearcher searcher = new IndexSearcher(reader);IndexSearcher
IndexSearcher提供了兩個非常重要的函數:
- void setSimilarity(Similarity similarity),用戶可以實現自己的Similarity對象,從而影響搜索過程的打分。
- 一系列search函數,是搜索過程的關鍵,主要負責打分的計算和倒排表的合並。
3. 創建QueryParser解析查詢語句生成查詢對象。
1 QueryParser parser = new QueryParser("content",new StandardAnalyzer());//content表示搜索的域或者說字段 2 Query query = parser.parse(keywords);//被搜索的內容QueryParser
解析分為兩個過程:
- 創建Analyer用來對查詢語句進行詞法分析和語言處理。
- QueryParser調用parser進行語法分析,形成查詢語法樹,放到Query中。
4. IndexSearcher調用search對查詢語法樹Query進行搜索,得到結果集Topdocs。
1 // 5、根據Searcher返回TopDocs 2 TopDocs tds = searcher.search(query, 20);//查詢20條記錄 3 // 6、根據TopDocs獲取ScoreDoc 4 ScoreDoc[] sds = tds.scoreDocs;Search
該方法收集文檔集合並計算打分。
5. 返回查詢結果給用戶。
1 int cou=0; 2 for(ScoreDoc sd:sds){ 3 cou++; 4 Document d = searcher.doc(sd.doc); 5 // 8、根據document對象獲取查詢的字段值 6 /** 查詢結果中content為空,是因為索引中沒有存儲content的內容,需要根據索引path和name從原文件中獲取content**/ 7 res+=cou+". "+d.get("path")+" "+d.get("name")+" "+d.get("content")+"\n"; 8 }Document
在返回查詢結果給用戶時,為了提高用戶體驗,我們可以給關鍵詞標註高亮和分頁返回結果。
5.1 給關鍵詞標註高亮。
1 public static String displayHtmlHighlight(Query query, String fieldName, String fieldContent) throws IOException, InvalidTokenOffsetsException 2 { 3 MyIkAnalyzer analyzer=new MyIkAnalyzer(); 4 //設置高亮標簽,可以自定義 5 SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<font color=‘#ff0000‘>", "</font>"); 6 /**創建QueryScorer*/ 7 //評分 8 QueryScorer scorer=new QueryScorer(query); 9 /**創建Fragmenter*/ 10 Fragmenter fragmenter = new SimpleSpanFragmenter(scorer); 11 //高亮分析器 12 Highlighter highlight=new Highlighter(formatter,scorer); 13 highlight.setTextFragmenter(fragmenter); 14 //fieldname是域名,如"title",fieldContent是d.get("title"); 15 String str=highlight.getBestFragment(analyzer, fieldName, fieldContent); 16 if (str==null) return fieldContent; 17 return str; 18 }displayHtmlHighlight
該函數有三個參數:
- Query query是第4步產生的查詢對象。
- String fieldName是要標註內容的域名,比如“title”
- String fieldContent是要標註的具體內容,比如某一個“title”的具體內容。
該函數實現了兩個基本功能:
- 如果要標註內容fieldContent為空,返回空串。
- 不為空時,對fieldContent進行自定義的html標簽標註。
1 SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<font color=‘#ff0000‘>", "</font>");formatter
這裏可以進行個性化定制。關於HighLighter的具體用法大家可以參考我的另一篇博客【lucene系列學習二】Lucene實現高亮顯示關鍵詞
5.2 分頁展示結果。
這裏介紹一種簡單的分頁方法:
1 int start=(pageIndex-1)*pageSize; 2 int end=pageIndex*pageSize; 3 Document d=null; 4 int cnt=0; 5 for(int i=start;i<end&&i<sds.length;i++) 6 { 7 d = searcher.doc(sds[i].doc); 8 //輸出d 9 }分頁
其中pageIndex和pageSize可以是前端傳的參數。
以上五個步驟就可以基本實現Lucene的檢索、關鍵詞高亮和分頁返回結果了,是不是很簡單呢?
下節我們會介紹Lucene的高級檢索方式~~
3.6 Lucene基本檢索+關鍵詞高亮+分頁