Lucene学习使用小结(二)
Lucene作为底层全文检索开发工具,虽然它没有强大的solr那样可怕,但是底层还是封装了一些特殊查询和一些高级应用,此处将简单的介绍一些特殊查询和一些高级应用,至于solr的使用和solr的可怕将在下一篇笔记中介绍.
Instantiable subclasses are:
TermQuery BooleanQuery WildcardQuery PhraseQuery PrefixQuery MultiPhraseQuery FuzzyQuery RegexpQuery TermRangeQuery NumericRangeQuery ConstantScoreQuery DisjunctionMaxQuery MatchAllDocsQuery
Lucene官方API中介绍了这么多的特殊查询,我主要实现了TermQuery,BooleanQuery,WildcardQuery,FuzzyQuery,NumericRangeQuery.对于这些特殊查询的方式大同小异,只是传入的不同的Query从而产生不同的结果,此处对博客<使用小结(一)>中的测试方法进行了抽取,将Query作为参数传入.
public void search(Query query) throws Exception{
//索引库位置
Directory directory = FSDirectory.open(new File("luceneTest"));
//索引读取
IndexReader indexReader = DirectoryReader.open(directory);
//索引查询
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//查询
TopDocs topDocs = indexSearcher.search(query, 10);
System.out.println("查询到"+topDocs.totalHits+"个文档");
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc doc : scoreDocs) {
//文档编号
int did = doc.doc;
//拿到文档
Document document = indexReader.document(did);
System.out.println("id:"+document.get("id"));
System.out.println("text:"+document.get("text"));
}
}
如果查出所有的数据?可以采用通配符查询WildcardQuery
@Test
public void testWildcardQuery() throws Exception{
WildcardQuery wildcardQuery = new WildcardQuery(new Term("text","*"));
search(wildcardQuery);
}
查询结果:
查询到4个文档
id:1
text:Tom喜欢使用华为手机
id:2
text:Jack一直在用iPhone
id:3
text:xiaomi在印度受广大欢迎
id:4
text:锤子手机真的很锤
星号表示的是另个或多个字符,所有查询出所有内容.
@Test
public void testWildcardQuery2() throws Exception{
WildcardQuery wildcardQuery = new WildcardQuery(new Term("text","*手机*"));
search(wildcardQuery);
}
此处查询的是text中内容包含手机字段的内容
查询到2个文档
id:1
text:Tom喜欢使用华为手机
id:4
text:锤子手机真的很锤
@Test
public void testTermQuery() throws Exception{
TermQuery termQuery = new TermQuery(new Term("text","iphone"));
search(termQuery);
}
结果如下:
查询到1个文档
id:2
text:Jack一直在用iPhone
Term查询是根据词条完整匹配,查询text包含iPhone的文档,并且分词器将iPhone分为词条的文档.
@Test
public void testFuzzyQuery() throws Exception{
FuzzyQuery fuzzyQuery = new FuzzyQuery(new Term("text","iphonn"));
search(fuzzyQuery);
}
模糊匹配查询指的是允许在匹配词条的时候出现错误单词,例如本例中输入的是iPhonn,依然可以查出iPhone的结果.但是值得注意的是在lucene的底层只允许错误两个,也就是如果输入iphyyy就无法查询到结果
查询到1个文档
id:2
text:Jack一直在用iPhone
其他具体的使用情况可以参见API
高亮显示的原理
在百度或者其他搜索引擎上搜索内容可见,匹配上搜索词条的内容作为高亮显示,这种实现查询网站源码可知有很多方式,一般而言是在匹配上的内容上加上前端定义好样式的标签,从而实现样式的更改.百度很多添加<em></em>标签
这种实现方式在lucene底层也是有实现的.
@Test
public void testHighlight() throws Exception{
//索引库位置
Directory directory = FSDirectory.open(new File("luceneTest"));
//索引读取
IndexReader indexReader = DirectoryReader.open(directory);
//索引查询
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//查询
TermQuery query = new TermQuery(new Term("text","手机"));
//样式编辑器
Formatter formatter = new SimpleHTMLFormatter("<em>", "</em>");
Scorer scorer = new QueryScorer(query);
Highlighter highlighter = new Highlighter(formatter,scorer);
TopDocs topDocs = indexSearcher.search(query, 10);
System.out.println("查询到"+topDocs.totalHits+"个文档");
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc doc : scoreDocs) {
//文档编号
int did = doc.doc;
//拿到文档
Document document = indexReader.document(did);
System.out.println("id:"+document.get("id"));
//拿到原来的text
String textString = document.get("text");
//高亮文本
String hTextString = highlighter.getBestFragment(new IKAnalyzer(), "text", textString);
System.out.println("text:"+hTextString);
}
}
运行结果如下:
查询到2个文档
id:1
加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
text:Tom喜欢使用华为<em>手机</em>
id:4
text:锤子<em>手机</em>真的很锤
@Test
public void testLuceneSort() throws Exception{
//索引库位置
Directory directory = FSDirectory.open(new File("luceneTest"));
//索引读取
IndexReader indexReader = DirectoryReader.open(directory);
//索引查询
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//查询
WildcardQuery query = new WildcardQuery(new Term("text","*"));
//true表示十分降序排列
Sort sort = new Sort(new SortField("id",Type.LONG,true));
//查询的时候传入sort
TopDocs topDocs = indexSearcher.search(query, 10,sort );
System.out.println("查询到"+topDocs.totalHits+"个文档");
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc doc : scoreDocs) {
//文档编号
int did = doc.doc;
//拿到文档
Document document = indexReader.document(did);
System.out.println("id:"+document.get("id"));
System.out.println("text:"+document.get("text"));
}
}
查询结果如下
查询到4个文档
id:4
text:锤子手机真的很锤
id:3
text:xiaomi在印度受广大欢迎
id:2
text:Jack一直在用iPhone
id:1
text:Tom喜欢使用华为手机
此处需要强调的是Lucene并不支持物理分页,而只支持逻辑分页.
@Test
public void testLucenePage() throws Exception{
//从页面传来的值page当前页和pageSize每页展示的数量
int page = 1;
int pageSize=2;
//起始和结束位置
int start = (page-1)*pageSize;
int end = start+pageSize;
//索引库位置
Directory directory = FSDirectory.open(new File("luceneTest"));
//索引读取
IndexReader indexReader = DirectoryReader.open(directory);
//索引查询
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//查询
WildcardQuery query = new WildcardQuery(new Term("text","*"));
//true表示十分降序排列
Sort sort = new Sort(new SortField("id",Type.LONG,true));
//查询的时候传入sort
//此处end之后的数据无需查询了
TopDocs topDocs = indexSearcher.search(query, end,sort);
System.out.println("查询到"+topDocs.totalHits+"个文档");
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for(int i=start;i<end;i++){
int docID = scoreDocs[i].doc;
Document document = indexReader.document(docID);
System.out.println(document.get("id"));
System.out.println(document.get("text"));
}
}
测试结果如下
查询到4个文档
4
锤子手机真的很锤
3
xiaomi在印度受广大欢迎
可以看到,虽然是分页查询,但是还是查询到了4条数据,只是我们返回2条数据而已,个人觉得lucene的分页一直都有些尴尬,希望深一步的学习可以搞懂为什么不支持物理分页吧.