| 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 |