1. 程式人生 > >3.6 Lucene基本檢索+關鍵詞高亮+分頁

3.6 Lucene基本檢索+關鍵詞高亮+分頁

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;
7 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 }
Searcher

搜索的過程總的來說就是將詞典及倒排表信息從索引中讀出來,根據用戶輸入的查詢語句合並倒排表,得到結果文檔集並對文檔進行打分的過程。

總結起來檢索有以下以下五個步驟:

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基本檢索+關鍵詞高亮+分頁