標籤:highlight 自己 offset 記錄 target turn tle 標籤 rect
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 csl18 * @description: 19 * 依賴jar:Lucene-core,lucene-analyzers-common,lucene-queryparser20 * 作用:使用索引搜尋檔案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、建立Directory32 Directory directory = FSDirectory.open(Paths.get("index"));//在硬碟上產生Directory33 // 2、建立IndexReader34 reader = DirectoryReader.open(directory);35 // 3、根據IndexReader建立IndexSearcher36 IndexSearcher searcher = new IndexSearcher(reader);37 // 4、建立搜尋的query38 // 建立parse用來確定搜尋的內容,第二個參數表示搜尋的域39 QueryParser parser = new QueryParser("content",new StandardAnalyzer());//content表示搜尋的域或者說欄位40 Query query = parser.parse(keywords);//被搜尋的內容41 // 5、根據Searcher返回TopDocs42 TopDocs tds = searcher.search(query, 20);//查詢20條記錄43 // 6、根據TopDocs擷取ScoreDoc44 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、關閉reader60 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 IOException69 {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返回TopDocs2 TopDocs tds = searcher.search(query, 20);//查詢20條記錄3 // 6、根據TopDocs擷取ScoreDoc4 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 //輸出d9 } 分頁
其中pageIndex和pageSize可以是前端傳的參數。
以上五個步驟就可以基本實現Lucene的檢索、關鍵詞高亮和分頁返回結果了,是不是很簡單呢?
下節我們會介紹Lucene的進階檢索方式~~
3.6 Lucene基本檢索+關鍵詞高亮+分頁