SOLR-5773: CollapsingQParserPlugin should make elevated documents the group head

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1583500 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Joel Bernstein 2014-04-01 00:23:33 +00:00
parent 719d5cd12e
commit 002f3d1b6b
3 changed files with 98 additions and 15 deletions

View File

@ -253,6 +253,9 @@ Other Changes
* SOLR-5934: LBHttpSolrServer exception handling improvement and small test * SOLR-5934: LBHttpSolrServer exception handling improvement and small test
improvements. (Gregory Chanan via Mark Miller) improvements. (Gregory Chanan via Mark Miller)
* SOLR-5773: CollapsingQParserPlugin should make elevated documents the
group head. (David Boychuck, Joel Bernstein)
================== 4.7.1 ================== ================== 4.7.1 ==================
Versions of Major Components Versions of Major Components

View File

@ -443,6 +443,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
private int nullDoc; private int nullDoc;
private FloatArrayList nullScores; private FloatArrayList nullScores;
private IntOpenHashSet boostDocs; private IntOpenHashSet boostDocs;
private int[] boostOrds;
public CollapsingScoreCollector(int maxDoc, public CollapsingScoreCollector(int maxDoc,
int segments, int segments,
@ -455,11 +456,19 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.boostDocs = boostDocs; this.boostDocs = boostDocs;
if(this.boostDocs != null) { if(this.boostDocs != null) {
//Set the elevated docs now. //Set the elevated docs now.
IntOpenHashSet boostG = new IntOpenHashSet();
Iterator<IntCursor> it = this.boostDocs.iterator(); Iterator<IntCursor> it = this.boostDocs.iterator();
while(it.hasNext()) { while(it.hasNext()) {
IntCursor cursor = it.next(); IntCursor cursor = it.next();
this.collapsedSet.set(cursor.value); int i = cursor.value;
this.collapsedSet.set(i);
int ord = values.getOrd(i);
if(ord > -1) {
boostG.add(ord);
}
} }
boostOrds = boostG.toArray();
Arrays.sort(boostOrds);
} }
this.values = values; this.values = values;
int valueCount = values.getValueCount(); int valueCount = values.getValueCount();
@ -489,6 +498,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
public void collect(int docId) throws IOException { public void collect(int docId) throws IOException {
int globalDoc = docId+this.docBase; int globalDoc = docId+this.docBase;
int ord = values.getOrd(globalDoc); int ord = values.getOrd(globalDoc);
if(ord > -1) { if(ord > -1) {
float score = scorer.score(); float score = scorer.score();
if(score > scores[ord]) { if(score > scores[ord]) {
@ -520,6 +530,12 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.collapsedSet.set(nullDoc); this.collapsedSet.set(nullDoc);
} }
if(this.boostOrds != null) {
for(int i=0; i<this.boostOrds.length; i++) {
ords[boostOrds[i]] = -1;
}
}
for(int i=0; i<ords.length; i++) { for(int i=0; i<ords.length; i++) {
int doc = ords[i]; int doc = ords[i];
if(doc > -1) { if(doc > -1) {
@ -539,6 +555,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
while((docId = it.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) { while((docId = it.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
int ord = values.getOrd(docId); int ord = values.getOrd(docId);
if(ord > -1) { if(ord > -1) {
dummy.score = scores[ord]; dummy.score = scores[ord];
} else if(this.boostDocs != null && boostDocs.contains(docId)) { } else if(this.boostDocs != null && boostDocs.contains(docId)) {
@ -600,14 +617,14 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.needsScores = needsScores; this.needsScores = needsScores;
this.boostDocs = boostDocs; this.boostDocs = boostDocs;
if(funcQuery != null) { if(funcQuery != null) {
this.fieldValueCollapse = new ValueSourceCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs, funcQuery, searcher); this.fieldValueCollapse = new ValueSourceCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs, funcQuery, searcher, values);
} else { } else {
if(fieldType instanceof TrieIntField) { if(fieldType instanceof TrieIntField) {
this.fieldValueCollapse = new IntValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs); this.fieldValueCollapse = new IntValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs, values);
} else if(fieldType instanceof TrieLongField) { } else if(fieldType instanceof TrieLongField) {
this.fieldValueCollapse = new LongValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs); this.fieldValueCollapse = new LongValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs, values);
} else if(fieldType instanceof TrieFloatField) { } else if(fieldType instanceof TrieFloatField) {
this.fieldValueCollapse = new FloatValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs); this.fieldValueCollapse = new FloatValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs, values);
} else { } else {
throw new IOException("min/max must be either TrieInt, TrieLong or TrieFloat."); throw new IOException("min/max must be either TrieInt, TrieLong or TrieFloat.");
} }
@ -696,6 +713,7 @@ public class CollapsingQParserPlugin extends QParserPlugin {
protected float[] scores; protected float[] scores;
protected FixedBitSet collapsedSet; protected FixedBitSet collapsedSet;
protected IntOpenHashSet boostDocs; protected IntOpenHashSet boostDocs;
protected int[] boostOrds;
protected int nullDoc = -1; protected int nullDoc = -1;
protected boolean needsScores; protected boolean needsScores;
protected boolean max; protected boolean max;
@ -709,7 +727,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int nullPolicy, int nullPolicy,
boolean max, boolean max,
boolean needsScores, boolean needsScores,
IntOpenHashSet boostDocs) { IntOpenHashSet boostDocs,
SortedDocValues values) {
this.field = field; this.field = field;
this.nullPolicy = nullPolicy; this.nullPolicy = nullPolicy;
this.max = max; this.max = max;
@ -717,11 +736,19 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.collapsedSet = new FixedBitSet(maxDoc); this.collapsedSet = new FixedBitSet(maxDoc);
this.boostDocs = boostDocs; this.boostDocs = boostDocs;
if(this.boostDocs != null) { if(this.boostDocs != null) {
IntOpenHashSet boostG = new IntOpenHashSet();
Iterator<IntCursor> it = boostDocs.iterator(); Iterator<IntCursor> it = boostDocs.iterator();
while(it.hasNext()) { while(it.hasNext()) {
IntCursor cursor = it.next(); IntCursor cursor = it.next();
this.collapsedSet.set(cursor.value); int i = cursor.value;
this.collapsedSet.set(i);
int ord = values.getOrd(i);
if(ord > -1) {
boostG.add(ord);
}
} }
this.boostOrds = boostG.toArray();
Arrays.sort(this.boostOrds);
} }
} }
@ -730,6 +757,12 @@ public class CollapsingQParserPlugin extends QParserPlugin {
this.collapsedSet.set(nullDoc); this.collapsedSet.set(nullDoc);
} }
if(this.boostOrds != null) {
for(int i=0; i<this.boostOrds.length; i++) {
ords[boostOrds[i]] = -1;
}
}
for(int i=0; i<ords.length; i++) { for(int i=0; i<ords.length; i++) {
int doc = ords[i]; int doc = ords[i];
if(doc > -1) { if(doc > -1) {
@ -770,8 +803,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int[] ords, int[] ords,
boolean max, boolean max,
boolean needsScores, boolean needsScores,
IntOpenHashSet boostDocs) throws IOException { IntOpenHashSet boostDocs, SortedDocValues values) throws IOException {
super(maxDoc, field, nullPolicy, max, needsScores, boostDocs); super(maxDoc, field, nullPolicy, max, needsScores, boostDocs, values);
this.ords = ords; this.ords = ords;
this.ordVals = new int[ords.length]; this.ordVals = new int[ords.length];
Arrays.fill(ords, -1); Arrays.fill(ords, -1);
@ -838,8 +871,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int[] ords, int[] ords,
boolean max, boolean max,
boolean needsScores, boolean needsScores,
IntOpenHashSet boostDocs) throws IOException { IntOpenHashSet boostDocs, SortedDocValues values) throws IOException {
super(maxDoc, field, nullPolicy, max, needsScores, boostDocs); super(maxDoc, field, nullPolicy, max, needsScores, boostDocs, values);
this.ords = ords; this.ords = ords;
this.ordVals = new long[ords.length]; this.ordVals = new long[ords.length];
Arrays.fill(ords, -1); Arrays.fill(ords, -1);
@ -907,8 +940,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
int[] ords, int[] ords,
boolean max, boolean max,
boolean needsScores, boolean needsScores,
IntOpenHashSet boostDocs) throws IOException { IntOpenHashSet boostDocs, SortedDocValues values) throws IOException {
super(maxDoc, field, nullPolicy, max, needsScores, boostDocs); super(maxDoc, field, nullPolicy, max, needsScores, boostDocs, values);
this.ords = ords; this.ords = ords;
this.ordVals = new float[ords.length]; this.ordVals = new float[ords.length];
Arrays.fill(ords, -1); Arrays.fill(ords, -1);
@ -982,8 +1015,8 @@ public class CollapsingQParserPlugin extends QParserPlugin {
boolean max, boolean max,
boolean needsScores, boolean needsScores,
IntOpenHashSet boostDocs, IntOpenHashSet boostDocs,
FunctionQuery funcQuery, IndexSearcher searcher) throws IOException { FunctionQuery funcQuery, IndexSearcher searcher, SortedDocValues values) throws IOException {
super(maxDoc, null, nullPolicy, max, needsScores, boostDocs); super(maxDoc, null, nullPolicy, max, needsScores, boostDocs, values);
this.valueSource = funcQuery.getValueSource(); this.valueSource = funcQuery.getValueSource();
this.rcontext = ValueSource.newContext(searcher); this.rcontext = ValueSource.newContext(searcher);
this.ords = ords; this.ords = ords;

View File

@ -23,9 +23,11 @@ import org.apache.solr.common.params.ModifiableSolrParams;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import com.carrotsearch.hppc.IntOpenHashSet;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.Random;
public class TestCollapseQParserPlugin extends SolrTestCaseJ4 { public class TestCollapseQParserPlugin extends SolrTestCaseJ4 {
@ -146,6 +148,51 @@ public class TestCollapseQParserPlugin extends SolrTestCaseJ4 {
"//result/doc[3]/float[@name='id'][.='3.0']", "//result/doc[3]/float[@name='id'][.='3.0']",
"//result/doc[4]/float[@name='id'][.='6.0']"); "//result/doc[4]/float[@name='id'][.='6.0']");
//Test SOLR-5773 with score collapse criteria
params = new ModifiableSolrParams();
params.add("q", "YYYY");
params.add("fq", "{!collapse field=group_s nullPolicy=collapse}");
params.add("defType", "edismax");
params.add("bf", "field(test_ti)");
params.add("qf", "term_s");
params.add("qt", "/elevate");
params.add("elevateIds", "1,5");
assertQ(req(params), "*[count(//doc)=3]",
"//result/doc[1]/float[@name='id'][.='1.0']",
"//result/doc[2]/float[@name='id'][.='5.0']",
"//result/doc[3]/float[@name='id'][.='3.0']");
//Test SOLR-5773 with max field collapse criteria
params = new ModifiableSolrParams();
params.add("q", "YYYY");
params.add("fq", "{!collapse field=group_s min=test_ti nullPolicy=collapse}");
params.add("defType", "edismax");
params.add("bf", "field(test_ti)");
params.add("qf", "term_s");
params.add("qt", "/elevate");
params.add("elevateIds", "1,5");
assertQ(req(params), "*[count(//doc)=3]",
"//result/doc[1]/float[@name='id'][.='1.0']",
"//result/doc[2]/float[@name='id'][.='5.0']",
"//result/doc[3]/float[@name='id'][.='4.0']");
//Test SOLR-5773 elevating documents with null group
params = new ModifiableSolrParams();
params.add("q", "YYYY");
params.add("fq", "{!collapse field=group_s}");
params.add("defType", "edismax");
params.add("bf", "field(test_ti)");
params.add("qf", "term_s");
params.add("qt", "/elevate");
params.add("elevateIds", "3,4");
assertQ(req(params), "*[count(//doc)=4]",
"//result/doc[1]/float[@name='id'][.='3.0']",
"//result/doc[2]/float[@name='id'][.='4.0']",
"//result/doc[3]/float[@name='id'][.='2.0']",
"//result/doc[4]/float[@name='id'][.='6.0']");
//Test collapse by min int field and sort //Test collapse by min int field and sort
params = new ModifiableSolrParams(); params = new ModifiableSolrParams();