我们的电商项目中用到了搜索,搜索功能是基于 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 的构建,它里面还有很多方法,我还没有列举到,后面再说。
解释到这里,可以说最简单的查询已经完成了。分析完了之后,他发现原来他的分页参数传递错误了。所以遇到问题,先简单的排查下,遇到看不懂的先跳过,看看能看懂的有没有问题,别直接就说无法解决!
: » 说说 org.apache.lucene.search.SearcherManager 的简单用法
原创文章,作者:kirin,如若转载,请注明出处:https://blog.ytso.com/251952.html