6

有人可以帮助我了解在 Lucene 中使用抽象 Collector 类的自定义实现的方式吗?

我用一些测试文本实现了两种查询索引的方法:

1.Total hits is eq to 2. 两个文件名相同,因此结果大小为 eq to 1,因为我将它们保存在一个集合中。

TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
LOG.info("Total hits " + topDocs.totalHits);
ScoreDoc[] scoreDosArray = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDosArray) {
    Document doc = searcher.doc(scoreDoc.doc);
    String fileName = doc.get(FILENAME_FIELD);
    results.add(fileName);
}

2.CountCollect 是 eq 到 2。我在 Collector 的 collect 方法中从中获取文件名的两个文档都是唯一的,因此最终结果大小也是 eq 到 2。CountNextReader 变量在逻辑末尾是 eq 到 10。

private Set<String> doStreamingSearch(final IndexSearcher searcher, Query query) throws IOException {
    final Set<String> results = new HashSet<String>();
    Collector collector = new Collector() {
        private int base;
        private Scorer scorer;
        private int countCollect;
        private int countNextReader;

        @Override
        public void collect(int doc) throws IOException {
            Document document = searcher.doc(doc);
            String filename = document.get(FILENAME_FIELD);
            results.add(filename);
            countCollect++;
        }

        @Override
        public boolean acceptsDocsOutOfOrder() {
            return true;
        }

        @Override
        public void setScorer(Scorer scorer) throws IOException {
            this.scorer = scorer;
        }

        @Override
        public void setNextReader(AtomicReaderContext ctx) throws IOException {
            this.base = ctx.docBase;
            countNextReader++;
        }

        @Override
        public String toString() {
            LOG.info("CountCollect: " + countCollect);
            LOG.info("CountNextReader: " + countNextReader);
            return null;
        }
    };
    searcher.search(query, collector);
    collector.toString();
    return results;
}

我不明白为什么在 collect 方法中与以前的实现相比,我得到不同的文档和不同的文件名?我希望得到相同的结果,或者?

4

1 回答 1

12

Collector#collect方法是搜索请求的热点。每个与查询匹配的文档都会调用它,而不仅仅是您返回的文档。事实上,您通常只取回最重要的文档,这些文档实际上是您向用户展示的文档。

我建议不要这样做:

TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);

这将迫使 lucene 返回过多的文档。

无论如何,如果您只有两个匹配的文档(或者您要求所有匹配的文档),那么您返回的文档数量和对 collect 方法的调用次数应该是相同的。

setNextReader方法是完全不同的东西,你不应该太在意。如果您想了解更多关于 AtomicReader 等的信息,请查看这篇文章。为了简短起见,Lucene 将数据存储为段,即小型可搜索倒排索引。每个查询都按顺序在每个段上执行。每次搜索切换到下一个段时,setNextReader都会调用该方法以允许在Collector. 例如,内部 lucene 文档 id 仅在段内是唯一的,因此您需要添加docBase到它以使其在整个索引中唯一。这就是为什么您需要在段更改时存储它并考虑到它。您的countNextReader变量只包含已为您的查询分析的段数,它与您的文档没有任何关系。

深入研究您的代码,我还注意到您在按 id 检索文档时Collector没有考虑到。docBase这应该解决它:

Document document = searcher.doc(doc + docBase);

还要记住,在 a 中加载存储的字段Collector并不是一件明智的事情。这会让你的搜索变得非常慢,因为存储的字段是从磁盘加载的。您通常仅为要返回的文档子集加载存储字段。您通常会在其中Collector加载对有效负载或类似内容等文档进行评分所需的信息,通常也使用 lucene 字段缓存。

于 2013-03-22T12:29:55.287 回答