Apache Lucene(全文检索引擎)—搜索
目录
返回目录:http://www.cnblogs.com/hanyinglong/p/5464604.html
本项目Demo已上传GitHub,欢迎大家fork下载学习:https://github.com/kencery/Lucene_Compass(项目内部有很详细的注释)
1. 搜索思路
a. 当用户在搜索的时候,先在词汇表中查找,得到符合条件的文档编号列表,再根据文档编号去索引库中得到数据(Document)。
b. Lucene实现搜索的思路
b.1 首先把需要查询的字符串转换为Query对象,把查询字符串转换为Query需要使用QueryParser、MultiFieldQueryParser,查询字符串首先也要经过分词器(Analyzer),要求搜索时使用的Analyzer和建立索引的时候使用的Analyzer要一致,否则极有可能搜索不出正确的结果。
b.2 调用indexSearcher.search()进行查询得到结果,此方法返回值为TopDocs,是包含结果的多个信息的一个对象,其中有totalHits代表总记录数,ScoreDoc数组代表一个结果的相关度得分和文档编号等信息的对象。
b.3 取出需要的数据文档编号列表,调用Document doc=indexSearcher.doc(docId)以取出指定编号对应的Document数据。
2. 理解核心搜索类
a. public class org.apache.lucene.search.IndexSearcher
a.1 IndexSearch是用来在建立好的索引上进行搜索的,它提供了很多搜索方法,其中一些在抽象基类Searcher中实现
a.2 它只能以只读的方式打开一个索引,所以可以有多个IndexSearcher的实例在一个索引上进行操作。
a.3 在使用完IndexSearcher后,需要释放资源,调用方法:indexSearcher.getIndexReader().close();
b. public final class org.apache.lucene.index.Term
b.1 Term是搜索的基本单元,一个Term对象由两个Sting类型的域组成,字段的名称和字段的值
b.2 在搜索时,你可以创建Term对象并和TermQuery同时使用,其中第一个参数代表了要在文档的哪一个Field上进行查找,第二个参数代表了要查询的关键字
Query query=new TermQuery(new Term("content","lucene"));
TopDocs topDocs= indexSearcher.search(query,100 ); //返回查询出来的前n条结果
b.3 这段代码使用Lucene查找出content字段中含有单词lucene的所有文档,因为TermQuery对象继承自它的抽象父类Query,所以你可以在等式的左边用Query类型。
c. public abstract class org.apache.lucene.search.Query
c.1 Query是一个抽象类,这个类的目的是把用户输入的查询字符串封装成Lucene能够识别的Query。
c.2 Query包含了很多子(必须通过一系列子类来表达检索的具体需求,在4个模块中有说明),具体请同时按住Ctrl+T查看
d. public class org.apache.lucene.search.TermQuery
d.1 TermQuery是抽象类Query的一个子类,他同时也是Lucene支持的最为基本的一个查询类。
d.2 生成一个TermQuery对象由如下语句完成(它的构造函数主要只接受一个参数,那就是一个Term对象)。
TermQuery query=new TermQuery(new Term("content","lucene"));
e. public class org.apache.lucene.search.TopDocs
e.1 TopDocs是用来保存搜索的结果的,思路是:指向相互匹配的搜索条件的前N个搜索结果,它是指针的简单容器指向他们的搜索结果输出的文档。
e.2 基于性能的考虑,TopDocs的实例并不是从索引中加载所有匹配查询的所有文档,而是每次按照你给的条件查询出一小部分展现给用户(分页原理)。
f.QueryParser和MultiFieldQueryParser
f.1 QueryParser查询分析器,处理用户输入的查询条件,把用户输入的非格式话检索词转化成后台可以使用的Query对象。
f.2 MultiFieldQueryParser是QueryParser的子类,与父类相比,MultiFieldQueryParser可以在多个属性中搜索。
3. 关键字搜索的大致实现
a. 代码以在github上开源,地址:https://github.com/kencery/Lucene_Compass
1 /** 2 * 测试搜索 3 * @throws Exception 4 */ 5 @Test 6 public void testSearch() throws Exception { 7 //1 搜索条件 8 String queryCondition="lucene"; 9 //2 执行搜索(lucene) 10 List<Article> articles=new ArrayList<Article>(); 11 //--------------------------搜索代码----------------------------- 12 Directory directory=FSDirectory.open(Paths.get("./indexDir/")); //索引库目录 13 Analyzer analyzer=new StandardAnalyzer(); //分词器 14 15 //2.1 把查询字符串转为Query对象(只在title中查询) 16 QueryParser queryParser=new QueryParser("title",analyzer); 17 Query query=queryParser.parse(queryCondition); 18 19 //2.2 执行搜索得到结果 20 IndexReader indexReader=DirectoryReader.open(directory); 21 IndexSearcher indexSearcher=new IndexSearcher(indexReader); 22 TopDocs topDocs= indexSearcher.search(query, 100); //返回查询出来的前n条结果 23 24 Integer count= topDocs.totalHits; //总结果数量 25 ScoreDoc[] scoreDocs=topDocs.scoreDocs; //返回前N条结果信息 26 27 //2.3 处理结果 28 for (int i = 0; i < scoreDocs.length; i++) { 29 ScoreDoc scoreDoc=scoreDocs[i]; 30 int docId=scoreDoc.doc; 31 System.out.println("得分是:"+scoreDoc.score+",内部编号是:"+docId); 32 //根据内部编号取出真正的Document数据 33 Document doc=indexSearcher.doc(docId); 34 //将document转化为Article 35 Article article=new Article(Integer.parseInt(doc.get("id")), doc.get("title"), doc.get("content")); 36 articles.add(article); 37 } 38 //------------------------------------------------------------ 39 //3 控制台显示结果 40 System.err.println("总结果数:"+count); 41 for (Article article : articles) { 42 System.out.println("查询结果为:"+article); 43 } 44 indexSearcher.getIndexReader().close(); 45 }
4.内建Query对象阐述
a. BooleanQuery 布尔搜索,对应的查询语句:
a.1 BooleanQuery是实际开发过程中经常使用的一种查询,它其实就是一个组合的Query,在使用中的时候可以把各种Query对象添加进去并且标明它们之间的逻辑关系。
a.2 BooleanQuery是可以嵌套的(BooleanQuery是一个布尔子句的容器)
(1) 一个BooleanQuery可以成为另一个BooleanQuery的条件子句。
(2) 布尔型的子句数目不能跟你超过1024。
a.3 public void add(Query query,BooleanClause.Occur occur),BooleanClause表示布尔查询子句关系的类,包括:BooleanClause.Occur.MUST、BooleanClause.Occur.MUST_NOT、BooleanClause.Occur.SHOULD,它含有以下6种组合。
(1) MUST和MUST:取得两个查询子句的交集。
(2) MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应的查询子句的检索结果
(3) MUST_NOT和MUST_NOT:无意义,检索无结果
(4) SHOULD和MUST:无意义,结果为MUST子句的检索结果
(5) SHOULD和MUST_NOT:SHOULD功能同MUST,相当于MUST和MUST_NOT的检索结果
(6) SHOULD和SHOULD:表示"或"的关系,最终检索结果为所有检索子句的并集。
Query query1=new MatchAllDocsQuery();
Query query2=NumericRangeQuery.newIntRange("id", 5, 15, true, false);
booleanQuery.add(query1,Occur.MUST);
booleanQuery.add(query2,Occur.MUST_NOT);
对应的查询字符串为:+*:* -id:[5 TO 15}
b. NumericRangeQuery 范围搜索
b.1 NumericRangeQuery.newIntRange(String field,Integer min,Integer max,boolean minInclusive,boolean maxInclusive); 布尔型的后面的两个参数表示是否可以将两个临界值也加入到搜索中。
例如:Query query=NumericRangeQuery.newIntRange("id", 5, 15, true, false);
对应的查询语句:对应的查询字符串为:id:[5 TO 15}
c. PrefixQuery 前缀查询,查询出某个字段以什么开头的信息
Term term= new Term("content","这是");
PrefixQuery query=new PrefixQuery(term);
对应的查询语句:content:这是*
d. PhraseQuery短语查询
d.1 PhraseQuery提供了一种为"坡度"的参数,用于表示词组的两个字之间可以插入无关单词的个数
PhraseQuery phraseQuery=new PhraseQuery();
phraseQuery.add(new Term("title","lucene"));
phraseQuery.add(new Term("title","框架"));
phraseQuery.setSlop(5); //之间的间隔最大不能超过5个
对应的查询语句:title:"lucene 框架"~5
e. FuzzyQuery模糊查询(FuzzyQuery(Term term,int maxEdits))
e.1 maxEdits最小相似度,默认为2,数字越小,查询结果越少,取值范围为0、1、2,当为0的时候相当于TermQuery。
Query query=new FuzzyQuery(new Term("title","lucenX"),2);
对应的查询语句:title:lucenX~2
f. WildcardQuery通配符搜索
f.1 *代表0到多个字符,?代表一个单一的字符。
Query query=new WildcardQuery(new Term("title","lu*n?"));
对应的查询语句是:title:lu*n?
g. MatchAllDocsQuery搜索全部
Query query=new MatchAllDocsQuery();
对应的查询语句是:*:*
5. 排序、过滤、高亮
a. 这部分内容在demo中备注已经非常详细,如果大家想去了解,请去github上下载项目自行查看(里面有详细备注)。
b. GitHub地址是:https://github.com/kencery/Lucene_Compass/tree/master/Lucene_5.5
c. 排序对应分支是:lucene_seven,过滤对应的分支是:lucene_eight,高亮对应的分支是:lucene_six
希望大家能从中间学到东西,如有疑问,请留言或者去GitHub上看LuceneDemo或者添加我的QQ,我们共同探讨。
初心商城:初心商城
作者:韩迎龙(Kencery) MVC/.NET群:159227188如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏一杯咖啡,本页版权归作者和博客园所有,欢迎转载,但未经作者同意必须保留此段声明, 且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利