一、全文檢索java
將非結構化數據中的一部分信息提取出來,從新組織,使其變得有必定結構,而後對此有必定結構的數據進行搜索,從而達到搜索相對較快的目的。這部分從非結構化數據中提取出而後從新組織的信息,咱們稱之索引。
這種先創建索引,再對索引進行搜索的過程就叫全文檢索(Full-text Search)。apache
二、Lucene技術工具
Lucene是apache下的一個開源的全文檢索引擎工具包(類庫)。它的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能。Lucene提供了完整的查詢引擎和索引引擎,部分文本分析引擎。網站
三、Lucene實現全文檢索的流程spa
全文檢索的流程分爲兩大部分:索引流程、搜索流程。3d
Lucene是開發全文檢索功能的工具包,使用時從官方網站下載,並解壓。code
官方網站:http://lucene.apache.org/對象
下載地址:http://archive.apache.org/dist/lucene/java/blog
下載版本:4.10.3索引
JDK要求:1.7以上(從版本4.8開始,不支持1.7如下)
1 //建立索引 2 @Test 3 public void testIndex() throws IOException { 4 //1. 採集數據:(jdbc採集數據經過BookDao調用方法獲得結果集) 5 BookDaoImpl dao = new BookDaoImpl(); 6 List<Book> bookList = dao.queryBookList(); 7 8 //2. 遍歷book結果集,組裝Document數據列表 9 for (Book book : bookList) { 10 Document doc = new Document(); 11 //3. 構建Field域,說白了就是將要存儲的數據字段須要用到new TextField對象三個參數的構造方法,book中有多個字段,因此建立多個Field對象。 12 //參數一:域的名稱,可隨意起;參數二:域對應的值;參數三:是否存儲 13 /*Field id = new TextField("id", book.getId().toString(), Field.Store.YES); 14 Field name = new TextField("name",book.getName(), Field.Store.YES); 15 Field price = new TextField("price",book.getPrice().toString(), Field.Store.YES); 16 Field pic = new TextField("pic",book.getPic(), Field.Store.YES); 17 Field description = new TextField("description",book.getDescription(), Field.Store.YES);*/ 18 19 //id不分詞 要索引 要存儲 20 Field id = new StringField("id", book.getId().toString(), Field.Store.YES); 21 // name 要分詞 要索引 要存儲 22 Field name = new TextField("name", book.getName(), Field.Store.YES); 23 // price 要分詞 要索引 要存儲,數字比較特殊 24 Field price = new FloatField("price", book.getPrice(), Field.Store.YES); 25 // pic 不分詞 不索引 要存儲 26 Field pic = new StoredField("pic", book.getPic()); 27 // description 要分詞 要索引 不存儲 28 Field description = new TextField("description", book.getDescription(), Field.Store.NO); 29 30 //4. 將Field域全部對象,添加到文檔對象中。調用Document.add 31 doc.add(id); 32 doc.add(name); 33 doc.add(price); 34 doc.add(pic); 35 doc.add(description); 36 37 //5. 建立一個標準分詞器(Analyzer與StandardAnalyzer),對文檔中的Field域進行分詞 38 StandardAnalyzer analyzer = new StandardAnalyzer(); 39 //6. 指定索引儲存目錄,使用FSDirectory.open()方法。 40 FSDirectory directory = FSDirectory.open(new File("/Users/Shared/index")); 41 //7. 建立IndexWriterConfig對象,直接new,用於接下來建立IndexWriter對象 42 IndexWriterConfig config = new IndexWriterConfig(Version.LATEST, analyzer); 43 //8. 建立IndexWriter對象,直接new 44 IndexWriter writer = new IndexWriter(directory, config); 45 //9. 添加文檔對象到索引庫輸出對象中,使用IndexWriter.addDocuments方法 46 writer.addDocument(doc); 47 //10. 釋放資源IndexWriter.close(); 48 writer.close(); 49 } 50 }
1 //搜索 2 @Test 3 public void testQuery() throws IOException { 4 // 1. 建立一個Directory對象,FSDirectory.open指定索引庫存放的位置 5 FSDirectory directory = FSDirectory.open(new File("/Users/Shared/index")); 6 // 2. 建立一個IndexReader對象,DirectoryReader.open須要指定Directory對象 7 IndexReader indexReader = DirectoryReader.open(directory); 8 // 3. 建立一個Indexsearcher對象,直接new,須要指定IndexReader對象 9 IndexSearcher indexSearcher = new IndexSearcher(indexReader); 10 // 4. 建立一個TermQuery對象,直接new,指定查詢的域和查詢的關鍵詞new Term(域名稱,關鍵詞) 11 TermQuery query = new TermQuery(new Term("name", "java")); 12 // 5. 執行查詢,IndexSearcher.search,須要指定TermQuery對象與查詢排名靠多少名前的記錄數,獲得結果TopDocs 13 TopDocs docs = indexSearcher.search(query, 10); 14 // 6. 遍歷查詢結果並輸出,TopDocs.totalHits總記錄數,topDocs.scoreDocs數據列表,經過scoreDoc.doc獲得惟一id,再經過IndexSearcher.doc(id),獲得文檔對象Document再Document.get(域名稱)獲得結果 15 System.out.println("查詢總記錄數爲:"+docs.totalHits); 16 for (ScoreDoc scoreDoc : docs.scoreDocs) { 17 //獲得文檔 18 int id = scoreDoc.doc; 19 Document doc = indexSearcher.doc(id); 20 System.out.println("id:"+doc.get("id")); 21 System.out.println("name:"+doc.get("name")); 22 System.out.println("price:"+doc.get("price")); 23 System.out.println("pic:"+doc.get("pic")); 24 System.out.println("description:"+doc.get("description")); 25 } 26 // 7. 關閉IndexReader對象 27 indexReader.close(); 28 }
一、經過Query子類搜索
①經過MatchAllDocsQuery(查詢全部文檔)
1 @Test 2 public void testFindall() throws Exception{ 3 //matachalldocsquery 4 Query query = new MatchAllDocsQuery(); 5 //建立一個indexSearcher 對象 6 //經過indexSearcher 調用search方法查詢 7 doSearcherBy(query); 8 }
②TermQuery
1 @Test 2 public void testTermQuery() throws IOException { 3 TermQuery termQuery = new TermQuery(new Term("name", "apache")); 4 doSearchBy(termQuery); 5 }
③NumericRangeQuery
1 @Test 2 public void testNumbericRange() throws IOException{ 3 //第一個參數:域的名稱 4 //第二個參數:最小值 5 //第三個參數:最大值 6 //第四個參數:是否包含最小值 7 //第五個參數:是否包含最大值 8 NumericRangeQuery query = NumericRangeQuery.newFloatRange("price", 55f, 60f, false, false); 9 doSearcherBy(query); 10 }
④BooleanQuery
1 @Test 2 publicvoid booleanQuery() throws Exception { 3 BooleanQuery query = new BooleanQuery(); 4 Query query1 = new TermQuery(new Term("id", "3")); 5 Query query2 = NumericRangeQuery.newFloatRange("price", 10f, 200f,true, true); 6 //MUST:查詢條件必須知足,至關於AND 7 //SHOULD:查詢條件可選,至關於OR 8 //MUST_NOT:查詢條件不能知足,至關於NOT非 9 query.add(query1, Occur.MUST); 10 query.add(query2, Occur.SHOULD); 11 System.out.println(query); 12 doSearcherBy(query); 13 }
二、經過QueryParser搜索
①查詢語法
查看語法,Query對象執行的查詢語法可經過System.out.println(query),查看。
第一種簡單的語法:
域名+":"+搜索的關鍵詞 例如:name:java 表示搜索域名爲name ,其關鍵詞爲java的文檔對象。
第二種:查詢全部的文檔
*:*
第三種:數值範圍的語法:
域名+「:」+[數值 TO 數值] 表示數值範圍,而且包括數值。若是不包括數值 用"{}"好比:
price:[55.0 TO 70.0] 等同於 55=< price <=70
price:{55.0 TO 70.0] 等同於 55 < price <=70
數值範圍類的查詢語法,不支持在queryparser中查詢。語法是沒有錯誤的。在solr中能夠查詢出來。
第四種:組合條件查詢
Occur.MUST 查詢條件必須知足,至關於and
+(加號)
Occur.SHOULD 查詢條件可選,至關於or
空(不用符號)
Occur.MUST_NOT 查詢條件不能知足,至關於not非
-(減號)
1)+條件1 +條件2:兩個條件之間是而且的關係and
例如:+filename:apache +content:apache
2)+條件1 條件2:必須知足第一個條件,忽略第二個條件
例如:+filename:apache content:apache
3)條件1 條件2:兩個條件知足其一便可。
例如:filename:apache content:apache
4)-條件1 條件2:必須不知足條件1,要知足條件2
例如:-filename:apache content:apache
第二種寫法:
②MultiFieldQueryParser
1 @Test 2 publicvoidtestMultiFieldQueryParser() throws Exception { 3 // 能夠指定默認搜索的域是多個 4 String[] fields = { "name", "description" }; 5 // 建立一個MulitFiledQueryParser對象 6 QueryParser parser = new MultiFieldQueryParser(fields, new IKAnalyzer()); 7 // 指定查詢語法,若是不指定域,就搜索默認的域 8 Query query = parser.parse("lucene"); 9 // 二、執行搜索 10 doSearcherBy(query); 11 }