通过前几篇《全文检索技术专栏》关于倒排索引算法的原理、Lucene分词、索引的创建等内容的介绍,Lucene中最重要也是最能体现Lucene作用的非搜索功能莫属。Lucene对创建的索引可实现多种搜索功能(词项查询、多域查询、布尔查询、范围查询、模糊查询、通配查询),在进行搜索时,将查询条件封装成query对象,最终得到多个document数据。
词项查询
词项查询是最基本的查询方式,查询参数就是一个域中的词语。判断倒排索引表中是否有相关词项,最终将document匹配集合返回。
@Test
public void termQuery() throws IOException {
//指定一个文件输出目录
Path path= Paths.get("d:/test/index");
//将路径交给FSDirectory完成路径的管理,当路径不存在时,由FSDirectory帮你创建
FSDirectory fsDirectory=FSDirectory.open(path);
//创建索引输入流
IndexReader indexReader= DirectoryReader.open(fsDirectory);
IndexSearcher indexSearcher=new IndexSearcher(indexReader);
//创建词项查询条件
Term term=new Term("title","巴西");
Query query= new TermQuery(term);
//查询
TopDocs docs = indexSearcher.search(query, 3);
ScoreDoc[] scoreDocs=docs.scoreDocs;
for (ScoreDoc scoreDoc:scoreDocs){
//获取document对象属性
//documentId
int did = scoreDoc.doc;
Document docObj = indexSearcher.doc(did);
System.out.println("============"+did+"============");
System.out.println(docObj.get("title"));
System.out.println(docObj.get("origin"));
System.out.println(docObj.get("content"));
}
}
查询结果:
多域查询
在上面的词项查询中,我们只搜索了titile,如果想同时搜索title、origin、content中有没有要查询的关键词,可以通过多域查询的方式。
代码和词项查询的区别不是很大,唯一不同的是构造查询条件和构造查询对象的方式不同:
@Test
public void multiQuery() throws IOException, ParseException {
//指定一个文件输出目录
Path path= Paths.get("d:/test/index");
//将路径交给FSDirectory完成路径的管理,当路径不存在时,由FSDirectory帮你创建
FSDirectory fsDirectory=FSDirectory.open(path);
//创建索引输入流
IndexReader indexReader= DirectoryReader.open(fsDirectory);
IndexSearcher indexSearcher=new IndexSearcher(indexReader);
//要查询的域
String[] files={"title","origin","content"};
//创建多域查询条件
MultiFieldQueryParser parser=new MultiFieldQueryParser(files,new SmartChineseAnalyzer());
Query query= parser.parse("巴西");
//查询
TopDocs docs = indexSearcher.search(query, 3);
ScoreDoc[] scoreDocs=docs.scoreDocs;
for (ScoreDoc scoreDoc:scoreDocs){
//获取document对象属性
//documentId
int did = scoreDoc.doc;
Document docObj = indexSearcher.doc(did);
System.out.println("============"+did+"============");
System.out.println(docObj.get("title"));
System.out.println(docObj.get("origin"));
System.out.println(docObj.get("content"));
}
}
查询结果:
布尔查询
布尔查询是使用最广泛的一种查询方式。可以组合其它所有的查询条件。可以将任何query对象作为布尔查询的子条件,从而决定最终的结果。比如在京东购买手机,可以选择品牌、价格区间、存储大小等组合条件进行查询。
由于前后代码都类似,这里只展示查询条件的创建过程:
//要查询的域
String[] files={"title","origin","content"};
//创建多域查询条件1
MultiFieldQueryParser parser=new MultiFieldQueryParser(files,new SmartChineseAnalyzer());
Query query= parser.parse("疫苗");
//创建词项查询条件2
Term term=new Term("title","中国");
Query query2= new TermQuery(term);
//封装布尔查询子条件
BooleanClause bc1=new BooleanClause(query,BooleanClause.Occur.MUST);
BooleanClause bc2=new BooleanClause(query2,BooleanClause.Occur.MUST);
//封装最终查询条件
Query finalQuery=new BooleanQuery.Builder().add(bc1).add(bc2).build();
代码中,以下这两项的意思是,查询既满足query又满足query2的结果,也就是查询query和query2的交集:
BooleanClause bc1=new BooleanClause(query,BooleanClause.Occur.MUST);
BooleanClause bc2=new BooleanClause(query2,BooleanClause.Occur.MUST);
这里的各种组合关系,我们用图例说明:
取得query和query2查询子句的交集:
表示查询结果中不能包含MUST_NOT所对应的查询子句的检索结果:
MUST_NOT和MUST_NOT连用,没有任何搜索结果,查询无意义:
除此之外,还有SHOULD,有兴趣的可以继续深入拓展。
范围查询
可以对域属性中数字类型进行范围查询。
比如:查询文章点击率在10-70次的文章
//范围查询 文章点击率在10-70次的文档
Query rangeQuery=IntPoint.newRangeQuery("clickNum",10,70);
模糊查询
在title域中查找和“苗”类似的词语:
//模糊查询
Query fuzzyQuery=new FuzzyQuery(new Term("title","苗"));
通配查询
?代表任意一个字符。* 代表任意多个字符。
//通配查询
Query wquery=new WildcardQuery(new Term("content","?国"));