这就是我做的,虽然它对内存有点沉重:
你需要的是提前创建一堆BitSets,每个类别一个,包含一个类别中所有文档的doc 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;
}
Run Code Online (Sandbox Code Playgroud)
这只是一种方法.如果您的类别足够简单,您可以使用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;
}
Run Code Online (Sandbox Code Playgroud)
您最终得到的是一个数组,其中包含搜索结果中每个类别的计数.如果您还需要搜索结果,则应该向命中收集器添加TopDocCollector(yo dawg ...).或者,您可以再次运行搜索.2次搜索优于30次.
我没有足够的声誉来评论(!)但是在Matt Quail的回答中我很确定你可以替换它:
int numDocs = 0;
td.seek(terms);
while (td.next()) {
    numDocs++;
}
Run Code Online (Sandbox Code Playgroud)
有了这个:
int numDocs = terms.docFreq()
Run Code Online (Sandbox Code Playgroud)
然后完全摆脱td变量.这应该会更快.
您可能需要考虑使用TermDocs 迭代器来查找与类别匹配的所有文档。
此示例代码遍历每个“类别”术语,然后计算与该术语匹配的文档数量。
public static void countDocumentsInCategories(IndexReader reader) throws IOException {
    TermEnum terms = null;
    TermDocs td = null;
    try {
        terms = reader.terms(new Term("Category", ""));
        td = reader.termDocs();
        do {
            Term currentTerm = terms.term();
            if (!currentTerm.field().equals("Category")) {
                break;
            }
            int numDocs = 0;
            td.seek(terms);
            while (td.next()) {
                numDocs++;
            }
            System.out.println(currentTerm.field() + " : " + currentTerm.text() + " --> " + numDocs);
        } while (terms.next());
    } finally {
        if (td != null) td.close();
        if (terms != null) terms.close();
    }
}
Run Code Online (Sandbox Code Playgroud)
即使对于大型索引,此代码也应该运行得相当快。
这是测试该方法的一些代码:
public static void main(String[] args) throws Exception {
    RAMDirectory store = new RAMDirectory();
    IndexWriter w = new IndexWriter(store, new StandardAnalyzer());
    addDocument(w, 1, "Apple", "fruit", "computer");
    addDocument(w, 2, "Orange", "fruit", "colour");
    addDocument(w, 3, "Dell", "computer");
    addDocument(w, 4, "Cumquat", "fruit");
    w.close();
    IndexReader r = IndexReader.open(store);
    countDocumentsInCategories(r);
    r.close();
}
private static void addDocument(IndexWriter w, int id, String name, String... categories) throws IOException {
    Document d = new Document();
    d.add(new Field("ID", String.valueOf(id), Field.Store.YES, Field.Index.UN_TOKENIZED));
    d.add(new Field("Name", name, Field.Store.NO, Field.Index.UN_TOKENIZED));
    for (String category : categories) {
        d.add(new Field("Category", category, Field.Store.NO, Field.Index.UN_TOKENIZED));
    }
    w.addDocument(d);
}
Run Code Online (Sandbox Code Playgroud)
        |   归档时间:  |  
           
  |  
        
|   查看次数:  |  
           9623 次  |  
        
|   最近记录:  |