一、全文检索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 }