使用 Lucene 按类别对结果进行计数

2022-09-02 21:41:19

我正在尝试使用Lucene Java 2.3.2来实现对产品目录的搜索。除了产品的常规字段外,还有一个名为“类别”的字段。一个产品可以分为多个类别。目前,我使用FilteredQuery在每个类别中搜索相同的搜索词,以获取每个类别的结果数。

这将导致每个查询进行 20-30 次内部搜索调用以显示结果。这大大减慢了搜索速度。有没有一种更快的方法可以使用Lucene获得相同的结果?


答案 1

以下是我所做的,尽管它有点内存过重:

您需要的是提前创建一堆 BitSets,每个类别一个,其中包含一个类别中所有文档的文档 ID。现在,在搜索时,您可以使用 HitCollector 并根据 BitSet 检查文档 ID。

下面是创建位集的代码:

public BitSet[] getBitSets(IndexSearcher indexSearcher, 
                           Category[] categories) {
    BitSet[] bitSets = new BitSet[categories.length];
    for(int i=0; i<categories.length; i++)
    {
        Query query = categories[i].getQuery();
        final BitSet bitset = new BitSet()
        indexSearcher.search(query, new HitCollector() {
            public void collect(int doc, float score) {
                bitSet.set(doc);
            }
        });
        bitSets[i] = bitSet;
    }
    return bitSets;
}

这只是实现这一目标的一种方法。如果您的类别足够简单,则可以使用 TermDocs 而不是运行完整搜索,但无论如何,当您加载索引时,这应该只运行一次。

现在,当需要计算搜索结果的类别时,您可以执行以下操作:

public int[] getCategroryCount(IndexSearcher indexSearcher, 
                               Query query, 
                               final BitSet[] bitSets) {
    final int[] count = new int[bitSets.length];
    indexSearcher.search(query, new HitCollector() {
        public void collect(int doc, float score) {
            for(int i=0; i<bitSets.length; i++) {
                if(bitSets[i].get(doc)) count[i]++;
            }
        }
    });
    return count;
}

您最终得到的是一个数组,其中包含搜索结果中每个类别的计数。如果您还需要搜索结果,则应将TopDocCollector添加到您的热门收集器中(yo dawg...)。或者,您可以再次运行搜索。2 个搜索优于 30 个。


答案 2

我没有足够的声誉来评论(!),但在Matt Quail的答案中,我很确定你可以替换这个:

int numDocs = 0;
td.seek(terms);
while (td.next()) {
    numDocs++;
}

有了这个:

int numDocs = terms.docFreq()

然后完全摆脱td变量。这应该使它更快。