我們這些網民,見得多了檢索應用了。Google、百度、論壇內部搜索、網站內部搜索…,這些應用使用的就是檢索技術。今天我們學習的主要是針對WEB應用的內部文本檢索,比如論壇。我們使用的框架是lucene。授課老師是湯陽光,年輕有為!
搞技術的,看到什么新技術總是十分好奇。先不說google和baidu吧(他們的專業檢索技術很強哦),見到論壇內部的檢索功能,就讓我十分好奇。我原本以為論壇內部的檢索就是模糊查找數據庫,但今日的課程讓我學習到了論壇內部真正的檢索技術。
一、信息檢索和全文檢索
信息檢索就是從信息集合中找出與用戶需求相關的信息。被檢索的信息除了文本外,還有圖像、音頻、視頻等多媒體信息。我們只關注文本的檢索,把用戶的查詢請求和全文中的每一個詞進行比較,不考慮查詢請求與文本語義上的匹配,這叫做全文檢索。在信息檢索工具中,全文檢索是最具通用性和實用性的。例如,使用百度從一大堆網頁中搜出與“傳智播客”相關的網頁。
我們簡單看一下檢索技術的流程:
請求
上面可見索引數據庫是十分重要的,簡單的說。全文檢索系統,將網絡上的數據通過某種格式保存到索引庫中。當用戶發送查詢請求時,實質上就是向索引庫查詢。全文檢索引擎負責處理用戶的請求用索引庫的更新等。
小時候查的漢語字典、英語詞典…我們是如何查詢的?當然不是一頁一頁的翻了,靠的是字典的目錄。Lucene的檢索方式正是使用了此技術,lucene的索引庫格式:
|
上面的表只是簡單說明lucene索引庫的存儲格式。我們通過lucene提供的類可以向索引庫添加、修改、查詢、刪除操作…。
關鍵字是通過分詞器分析出來的,一般情況下各有語言有各字的分詞器。分詞器的強大提高了查詢數據的接近性。
二、lucene操作
我們編寫一個對Article對象向lucene索引庫的添加、修改、查詢、刪除操作:
import java.util.ArrayList; import java.util.List; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.search.TopDocs; import cn.itcast.cc.lucene.helloword.Article; import cn.itcast.cc.lucene.helloword.utils.ArticleDocUtils; public class IndexDao { // 索引目錄 private String indexPath = "./index"; // 分詞器 private Analyzer analyzer = new StandardAnalyzer(); /** * 保存記錄 * * @param art */ public void save(Article art) { // lucene的寫出索引類 IndexWriter indexWriter = null; try { indexWriter = new IndexWriter(this.indexPath, this.analyzer, MaxFieldLength.LIMITED); // 添加到索引庫 indexWriter.addDocument(ArticleDocUtils.Article2Doc(art)); } catch (Exception e) { e.printStackTrace(); } // 釋放indexWriter if (indexWriter != null) { try { // 使用后一定要關閉 indexWriter.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 更新記錄 * * @param art */ public void update(Article art) { IndexWriter indexWriter = null; try { indexWriter = new IndexWriter(this.indexPath, this.analyzer, MaxFieldLength.LIMITED); Term term = new Term("id", art.getId() + ""); // 更新 indexWriter.updateDocument(term, ArticleDocUtils.Article2Doc(art)); } catch (Exception e) { e.printStackTrace(); } // 釋放indexWriter if (indexWriter != null) { try { indexWriter.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 刪除記錄 * * @param id */ public void delete(int id) { IndexWriter indexWriter = null; try { indexWriter = new IndexWriter(this.indexPath, this.analyzer, MaxFieldLength.LIMITED); Term term = new Term("id", id + ""); // 刪除 indexWriter.deleteDocuments(term); } catch (Exception e1) { e1.printStackTrace(); } // 釋放indexWriter if (indexWriter != null) { try { indexWriter.close(); } catch (Exception e) { e.printStackTrace(); } } } /** * 查詢記錄(具有分頁功能) * * @param queryString * @param startIndex * @param recordCount * @return */ public List search(String queryString, int startIndex, int recordCount) { List result = new ArrayList(); IndexSearcher indexSearcher = null; try { indexSearcher = new IndexSearcher(this.indexPath); String[] fields = new String[] {"title","content"}; // 分析查詢條件 QueryParser queryParser = new MultiFieldQueryParser(fields, this.analyzer); // 生成查詢對象 Query query = queryParser.parse(queryString); int findTotalRecord = startIndex + recordCount; // 查詢 TopDocs topDocs = indexSearcher.search(query, null, findTotalRecord); //獲取分頁數據 int endIndex = Math.min(startIndex+recordCount,topDocs.totalHits); for(int i=startIndex; i<endIndex;i++){ result.add(indexSearcher.doc(topDocs.scoreDocs[i].doc)); } } catch (Exception e1) { e1.printStackTrace(); } // 釋放indexWriter if (indexSearcher != null) { try { indexSearcher.close(); } catch (Exception e) { e.printStackTrace(); } } return result; } } |
其中使用到的“ArticleDocUtils”如下:
import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.Field.Index; import org.apache.lucene.document.Field.Store; import cn.itcast.cc.lucene.helloword.Article; public class ArticleDocUtils { public static Document Article2Doc(Article art){ // lucene索引庫中的document對象 Document doc = new Document(); // 添加到document中的都是field對象,注冊其中的key,檢索時會用到。 // Store是否存儲,決定對象是臨時性還是持久性的 // Index在庫中建立什么樣的索引 doc.add(new Field("id", art.getId()+"", Store.YES, Index.NOT_ANALYZED)); doc.add(new Field("title", art.getTitle(), Store.YES, Index.ANALYZED)); doc.add(new Field("content", art.getContent(), Store.YES, Index.ANALYZED)); return doc; } public static Article Doc2Article(Document doc){ Article art = new Article(); art.setId(Integer.parseInt(doc.getField("id").stringValue())); art.setTitle(doc.getField("title").stringValue()); art.setContent(doc.getField("content").stringValue()); return art; } |
需要導入的jar包:lucene-analyzers-
上面是對lunce的簡單操作,明天會講解檢索的分詞器、高亮、排序、過濾…
湯老師今天有留練習作業,我去做練習了哦~~ lucene很簡單、很方便~~