Lucene学习使用小结(二)
Lucene作为底层全文检索开发工具,虽然它没有强大的solr那样可怕,但是底层还是封装了一些特殊查询和一些高级应用,此处将简单的介绍一些特殊查询和一些高级应用,至于solr的使用和solr的可怕将在下一篇笔记中介绍.
特殊查询
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
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:锤子手机真的很锤 |
TermQuery
@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分为词条的文档.
FuzzyQuery
@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
Lucene的高级使用
高亮显示
高亮显示的原理
在百度或者其他搜索引擎上搜索内容可见,匹配上搜索词条的内容作为高亮显示,这种实现查询网站源码可知有很多方式,一般而言是在匹配上的内容上加上前端定义好样式的标签,从而实现样式的更改.百度很多添加<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的分页一直都有些尴尬,希望深一步的学习可以搞懂为什么不支持物理分页吧.