lucene、solr全文搜索
lucene是一款搜索引擎技術,並非產品,而solr是搜索引擎所在服務器。
應用場景:
1:網站頭部的搜索
2:APP端頭部搜索
3:做成搜索產品
簡介:
Lucene是一個全文搜索框架,而不是應用產品。因此它並不像www.baidu.com 或者google Desktop那麼拿來就能用,它只是提供了一種工具讓你能實現這些產品。
lucene的工作方式
lucene提供的服務實際包含兩部分:一入一出。所謂入是寫入,即將你提供的源(本質是字符串)寫入索引或者將其從索引中刪除;所謂出是讀出,即向用戶提供全文搜索服務,讓用戶可以通過關鍵詞定位源。
寫入流程
源字符串首先經過analyzer處理,包括:分詞,分成一個個單詞;去除stopword(可選),將源中需要的信息加入Document的各個Field中,並把需要索引的Field索引起來,把需要存儲的Field存儲起來,將索引寫入存儲器,存儲器可以是內存或磁盤
讀出流程
用戶提供搜索關鍵詞,經過analyzer處理,對處理後的關鍵詞搜索索引找出對應的Document,用戶根據需要從找到的Document中提取需要的Field
概念
analyzer:
Analyzer是分析器,它的作用是把一個字符串按某種規則劃分成一個個詞語,並去除其中的無效詞語,這裏說的無效詞語是指英文中的“of”、“the”,中文中的“的”、“地”等詞語,這些詞語在文章中大量出現,但是本身不包含什麼關鍵信息,去掉有利於縮小索引文件、提高效率、提高命中率
document:
用戶提供的源是一條條記錄,它們可以是文本文件、字符串或者數據庫表的一條記錄等等。一條記錄經過索引之後,就是以一個Document的形式存儲在索引文件中的。用戶進行搜索,也是以Document列表的形式返回
field:
一個Document可以包含多個信息域,例如一篇文章可以包含“標題”、“正文”、“最後修改時間”等信息域,這些信息域就是通過Field在Document中存儲的。 Field有兩個屬性可選:存儲和索引。通過存儲屬性你可以控制是否對這個Field進行存儲;通過索引屬性你可以控制是否對該Field進行索引。這看起來似乎有些廢話,事實上對這兩個屬性的正確組合很重要,下面舉例說明:還是以剛纔的文章爲例子,我們需要對標題和正文進行全文搜索,所以我們要把索引屬性設置爲真,同時我們希望能直接從搜索結果中提取文章標題,所以我們把標題域的存儲屬性設置爲真,但是由於正文域太大了,我們爲了縮小索引文件大小,將正文域的存儲屬性設置爲假,當需要時再直接讀取文件;我們只是希望能從搜索解果中提取最後修改時間,不需要對它進行搜索,所以我們把最後修改時間域的存儲屬性設置爲真,索引屬性設置爲假。上面的三個域涵蓋了兩個屬性的三種組合,還有一種全爲假的沒有用到,事實上Field不允許你那麼設置,因爲既不存儲又不索引的域是沒有意義的
lucene入門示例
1:新建一個工程
2:導入所需jar包
入庫
1:新建一個入庫的實體對象
2:入庫IndexWrite
代碼如下:
/** * 文檔 * @author likang * @date 2017-12-22 上午9:50:21 */ public class Ariclte implements Serializable{ private static final long serialVersionUID = 1L; private Long aid; private String title; private String context; public Long getAid() { return aid; } public void setAid(Long aid) { this.aid = aid; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContext() { return context; } public void setContext(String context) { this.context = context; } } /** * 入庫:將一篇文件存儲到搜索庫中 * 出庫:根據關鍵詞,從搜索庫中搜索對應的匹配信息 * @author likang * @date 2017-12-22 上午9:49:26 */ public class HelloLucene { /** * 入庫 * @throws Exception */ @Test public void createIndex() throws Exception{ //初始化數據文章 Ariclte ariclte = new Ariclte(); ariclte.setAid(Long.valueOf(1)); ariclte.setTitle("Lucene是一款很好的搜索引擎"); ariclte.setContext("Lucene是一款搜索引擎技術,產品有百度,谷歌等"); Directory directory = FSDirectory.open(new File("./indexLucene"));//創建搜索庫路徑目錄 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);//搜索庫的分詞器 /** * MaxFieldLength.LIMITED:文章長度有限制 * UNLIMITED:無限制 */ //lucene中入庫的核心接口API IndexWriter indexWriter = new IndexWriter(directory, analyzer, MaxFieldLength.LIMITED); /** * Index: * NOT_ANALYZED:代表支持索引,不支持分詞,不支持創建對象,不支持存儲 * ANALYZED:代表支持索引,支持分詞,支持創建對象,支持存儲 * ANALYZED_NO_NORMS:代表支持索引,支持分詞,不支持創建對象,不支持存儲 * NOT_ANALYZED_NO_NORMS:代表支持索引,不支持分詞,不支持創建對象 * NO:都不支持 * * Store: * YES:存儲 * NO:不存儲 * */ Field field1 = new Field("aid", ariclte.getAid().toString(), Store.YES, Index.NOT_ANALYZED); Field field2 = new Field("title", ariclte.getTitle(), Store.YES, Index.NO); Field field3 = new Field("context", ariclte.getContext(), Store.YES, Index.ANALYZED); Document document = new Document(); document.add(field1); document.add(field2); document.add(field3); //將document,寫入到搜索庫中 indexWriter.addDocument(document); //關閉搜索庫 indexWriter.close(); } }
出庫
/** * 出庫 * 根據關鍵詞---匹配3個 * @throws Exception */ @Test public void searchIndex() throws Exception{ //獲取搜索庫的位置 Directory directory = FSDirectory.open(new File("./indexLucene")); //搜索庫的分詞器 Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30); //lucene搜索出庫API IndexSearcher indexSearcher = new IndexSearcher(directory); /** * 第一個參數代表之前的庫版本信息 * 第二參數代表要搜索的字段 * 第三個參數代表使用的分詞器 */ QueryParser queryParser = new QueryParser(Version.LUCENE_30, "context", analyzer); //輸入的關鍵詞 Query query = queryParser.parse("Lucene"); /** * 第一個參數代表搜索的關鍵詞 * 第二個參數代表根據關鍵詞匹配顯示的個數 */ TopDocs topDocs = indexSearcher.search(query, 3); //所有搜索對象--集合/數組中 ScoreDoc[] sds = topDocs.scoreDocs; List<Ariclte> list = new ArrayList<Ariclte>(); for (ScoreDoc sd : sds) { int index = sd.doc;//文章對應的下標 Document document = new Document(); document = indexSearcher.doc(index); Ariclte ariclte = new Ariclte(); ariclte.setAid(Long.valueOf(document.get("aid").toString())); ariclte.setTitle(document.get("title")); ariclte.setContext(document.get("context")); list.add(ariclte); } if (list != null && list.size() > 0) { for (int i = 0; i < list.size(); i++) { System.out.println("標題:"+list.get(i).getTitle()); System.out.println("簡短標題:"+list.get(i).getContext()); System.out.println("點擊進入:www.baidu.com"); } } }