说说 org.apache.lucene.search.SearcherManager 的简单用法

JAVA herman 32浏览

我们的电商项目中用到了搜索,搜索功能是基于 lucene 开发的。最近有同事给我说,我们的搜索有问题。我吓了一跳,赶紧问什么问题?

他说,搜索商品后,点击第二页,第三页等出来的内容和第一页一样,翻页无效。

然后,我让他排查一下,他怕查了半天,说看不懂 lucene(不懂的可以先看这篇文章《Lucene 原理和实现机制》),于是便有了这篇文章。相当于给他简单的讲解一下 SearcherManager 的简单用法。

SearcherManager 是一个 final class。顾名思义,它就是一个搜索管理器。我们要实现搜索,就必须要通过 SearcherManager 获得一个 IndexSearcher 索引查询器。

那么 SearcherManager 是怎么来的呢?我要搜索,肯定的先创建搜索管理器吧。

创建 SearcherManager 非常的简单,SearcherManager 提供了 4 种构造函数用来创建它。

SearcherManager searcherManager = new SearcherManager(directory, null);

public SearcherManager(Directory dir, SearcherFactory searcherFactory) throws IOException {
	if (searcherFactory == null) {
	  searcherFactory = new SearcherFactory();
	}
	this.searcherFactory = searcherFactory;
	current = getSearcher(searcherFactory, DirectoryReader.open(dir), null);
}

上面是最简单的一种方式。Directory 和我们在学习 Hashtable 的解释的字典是一个意思。我们可以通过 FSDirectory、SimpleFSDirectory 等方式创建 Directory。也就是从本地路径(硬盘)上加载字典。

Directory directory = FSDirectory.open(new File("D:\\Workspaces\\xttblog\\index"));
directory = new SimpleFSDirectory(java.nio.file.Paths.get("D:\\Workspaces\\xttblog\\index"));

除此之外,SearcherManager 还提供了通过 IndexWriter 创建 SearcherManager 对象的方式。

public SearcherManager(IndexWriter writer, SearcherFactory searcherFactory) 
	throws IOException {
    this(writer, true, false, searcherFactory);
}

IndexWriter 是一个索引写入组件,我们以后再说它。

另外还有一个构造函数如下:

public SearcherManager(IndexWriter writer, boolean applyAllDeletes, boolean writeAllDeletes,
 SearcherFactory searcherFactory) throws IOException {
    if (searcherFactory == null) {
      searcherFactory = new SearcherFactory();
    }
    this.searcherFactory = searcherFactory;
    current = getSearcher(searcherFactory, 
    DirectoryReader.open(writer, applyAllDeletes, writeAllDeletes), null);
}

applyAllDeletes 如果为 true,那么在可见模式(made visible)下索引搜索器 IndexSearcher 和 DirectoryReader 词典阅读器中所有的缓冲都奖被删除。如果为 false,那么所有的缓冲可能会被删除,也可能不会被删除,取决于是否 commit,缓存会被保持缓冲在 IndexWriter 中。以便将来应用它们,删除的代价是非常高的,如果你非要这样做,建议参考 DirectoryReader.openIfChanged(DirectoryReader, IndexWriter, boolean) 方法。这个方法我们以后再讲。

另外还有一个构造函数是通过 DirectoryReader 词典阅读器去创建 SearcherManager 对象。

public SearcherManager(DirectoryReader reader, SearcherFactory searcherFactory)
 throws IOException {
    if (searcherFactory == null) {
      searcherFactory = new SearcherFactory();
    }
    this.searcherFactory = searcherFactory;
    this.current = getSearcher(searcherFactory, reader, null);
}

这个用的比较少,我们以后遇到了再说。

有了 SearcherManager 以后,我们就可以通过 acquire 方法获得一个 IndexSearcher 索引搜索器。然后创建 TermQuery(词组查询)、BooleanQuery(组合查询)、QueryParser(分词器查询) 查询等

Directory directory = FSDirectory.open(new File("/root/data/03"));
SearcherManager sm = new SearcherManager(directory, null);
IndexSearcher searcher = sm.acquire();
Query query = new TermQuery(new Term("title", "test"));
TopDocs results = searcher.search(query, null, 100);
System.out.println(results.totalHits);
ScoreDoc[] docs = results.scoreDocs;
for (ScoreDoc doc : docs) {
    System.out.println("doc inertalid:" + doc.doc + " ,docscore:" + doc.score);
    Document document = searcher.doc(doc.doc);
    System.out.println("id:" + document.get("id") + " ,title:" + document.get("title"));
}
sm.release(searcher);
sm.close();

通过 TopDocs 和 ScoreDoc 我们还可以构建分页查询。具体以后再说吧,本文我们只说 SearcherManager 的构建,它里面还有很多方法,我还没有列举到,后面再说。

解释到这里,可以说最简单的查询已经完成了。分析完了之后,他发现原来他的分页参数传递错误了。所以遇到问题,先简单的排查下,遇到看不懂的先跳过,看看能看懂的有没有问题,别直接就说无法解决!

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847,QQ3群:187424846。QQ群进群密码:xttblog,想加微信群的朋友,可以微信搜索:xmtxtt,备注:“xttblog”,添加助理微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 说说 org.apache.lucene.search.SearcherManager 的简单用法