这就是我做的,虽然它对内存有点沉重:
你需要的是提前创建一堆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)