blob: 0dfa8f4a5a1b2fd85249b0c9570e2b6d34e8bcb4 [file] [log] [blame]
Index: modules/join/src/test/org/apache/lucene/search/TestBlockJoin.java
===================================================================
--- modules/join/src/test/org/apache/lucene/search/TestBlockJoin.java (revision 1183333)
+++ modules/join/src/test/org/apache/lucene/search/TestBlockJoin.java (working copy)
@@ -57,6 +57,14 @@
return job;
}
+ // ... has multiple qualifications
+ private Document makeQualification(String qualification, int year) {
+ Document job = new Document();
+ job.add(newField("qualification", qualification, StringField.TYPE_STORED));
+ job.add(new NumericField("year").setIntValue(year));
+ return job;
+ }
+
public void testSimple() throws Exception {
final Directory dir = newDirectory();
@@ -492,4 +500,94 @@
}
}
}
+
+ public void testMultiChildTypes() throws Exception {
+
+ final Directory dir = newDirectory();
+ final RandomIndexWriter w = new RandomIndexWriter(random, dir);
+
+ final List<Document> docs = new ArrayList<Document>();
+
+ docs.add(makeJob("java", 2007));
+ docs.add(makeJob("python", 2010));
+ docs.add(makeQualification("maths", 1999));
+ docs.add(makeResume("Lisa", "United Kingdom"));
+ w.addDocuments(docs);
+
+ IndexReader r = w.getReader();
+ w.close();
+ IndexSearcher s = new IndexSearcher(r);
+
+ // Create a filter that defines "parent" documents in the index - in this case resumes
+ Filter parentsFilter = new CachingWrapperFilter(new QueryWrapperFilter(new TermQuery(new Term("docType", "resume"))));
+
+ // Define child document criteria (finds an example of relevant work experience)
+ BooleanQuery childJobQuery = new BooleanQuery();
+ childJobQuery.add(new BooleanClause(new TermQuery(new Term("skill", "java")), Occur.MUST));
+ childJobQuery.add(new BooleanClause(NumericRangeQuery.newIntRange("year", 2006, 2011, true, true), Occur.MUST));
+
+ BooleanQuery childQualificationQuery = new BooleanQuery();
+ childQualificationQuery.add(new BooleanClause(new TermQuery(new Term("qualification", "maths")), Occur.MUST));
+ childQualificationQuery.add(new BooleanClause(NumericRangeQuery.newIntRange("year", 1980, 2000, true, true), Occur.MUST));
+
+
+ // Define parent document criteria (find a resident in the UK)
+ Query parentQuery = new TermQuery(new Term("country", "United Kingdom"));
+
+ // Wrap the child document query to 'join' any matches
+ // up to corresponding parent:
+ BlockJoinQuery childJobJoinQuery = new BlockJoinQuery(childJobQuery, parentsFilter, BlockJoinQuery.ScoreMode.Avg);
+ BlockJoinQuery childQualificationJoinQuery = new BlockJoinQuery(childQualificationQuery, parentsFilter, BlockJoinQuery.ScoreMode.Avg);
+
+ // Combine the parent and nested child queries into a single query for a candidate
+ BooleanQuery fullQuery = new BooleanQuery();
+ fullQuery.add(new BooleanClause(parentQuery, Occur.MUST));
+ fullQuery.add(new BooleanClause(childJobJoinQuery, Occur.MUST));
+ fullQuery.add(new BooleanClause(childQualificationJoinQuery, Occur.MUST));
+
+ //????? How do I control volume of jobs vs qualifications per parent?
+ BlockJoinCollector c = new BlockJoinCollector(Sort.RELEVANCE, 10, true, false);
+
+ s.search(fullQuery, c);
+
+ //Examine "Job" children
+ boolean showNullPointerIssue=true;
+ if (showNullPointerIssue) {
+ TopGroups<Integer> jobResults = c.getTopGroups(childJobJoinQuery, null, 0, 10, 0, true);
+
+ //assertEquals(1, results.totalHitCount);
+ assertEquals(1, jobResults.totalGroupedHitCount);
+ assertEquals(1, jobResults.groups.length);
+
+ final GroupDocs<Integer> group = jobResults.groups[0];
+ assertEquals(1, group.totalHits);
+
+ Document childJobDoc = s.doc(group.scoreDocs[0].doc);
+ //System.out.println(" doc=" + group.scoreDocs[0].doc);
+ assertEquals("java", childJobDoc.get("skill"));
+ assertNotNull(group.groupValue);
+ Document parentDoc = s.doc(group.groupValue);
+ assertEquals("Lisa", parentDoc.get("name"));
+ }
+
+ //Now Examine qualification children
+ TopGroups<Integer> qualificationResults = c.getTopGroups(childQualificationJoinQuery, null, 0, 10, 0, true);
+
+ //!!!!! This next line can null pointer - but only if prior "jobs" section called first
+ assertEquals(1, qualificationResults.totalGroupedHitCount);
+ assertEquals(1, qualificationResults.groups.length);
+
+ final GroupDocs<Integer> qGroup = qualificationResults.groups[0];
+ assertEquals(1, qGroup.totalHits);
+
+ Document childQualificationDoc = s.doc(qGroup.scoreDocs[0].doc);
+ assertEquals("maths", childQualificationDoc.get("qualification"));
+ assertNotNull(qGroup.groupValue);
+ Document parentDoc = s.doc(qGroup.groupValue);
+ assertEquals("Lisa", parentDoc.get("name"));
+
+
+ r.close();
+ dir.close();
+ }
}
Index: modules/join/src/java/org/apache/lucene/search/join/BlockJoinCollector.java
===================================================================
--- modules/join/src/java/org/apache/lucene/search/join/BlockJoinCollector.java (revision 1183333)
+++ modules/join/src/java/org/apache/lucene/search/join/BlockJoinCollector.java (working copy)
@@ -387,15 +387,17 @@
// unbox once
final int slot = _slot;
- if (offset >= queue.size()) {
+ if (sortedGroups == null) {
+ if (offset >= queue.size()) {
+ return null;
+ }
+ sortQueue();
+ } else if (offset > sortedGroups.length) {
return null;
}
+
int totalGroupedHitCount = 0;
- if (sortedGroups == null) {
- sortQueue();
- }
-
final FakeScorer fakeScorer = new FakeScorer();
final GroupDocs<Integer>[] groups = new GroupDocs[sortedGroups.length - offset];
Index: lucene/contrib/CHANGES.txt
===================================================================
--- lucene/contrib/CHANGES.txt (revision 1183333)
+++ lucene/contrib/CHANGES.txt (working copy)
@@ -121,6 +121,10 @@
* LUCENE-3495: Fix BlockJoinQuery to properly implement getBoost()/setBoost().
(Robert Muir)
+ * LUCENE-3519: BlockJoinCollector always returned null when you tried
+ to retrieve top groups for any BlockJoinQuery after the first (Mark
+ Harwood, Mike McCandless)
+
API Changes
* LUCENE-3436: Add SuggestMode to the spellchecker, so you can specify the strategy