You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jb...@apache.org on 2013/12/31 15:35:49 UTC
svn commit: r1554523 - in /lucene/dev/trunk/solr: ./
core/src/java/org/apache/solr/search/
core/src/java/org/apache/solr/search/function/
core/src/test/org/apache/solr/search/
Author: jbernste
Date: Tue Dec 31 14:35:48 2013
New Revision: 1554523
URL: http://svn.apache.org/r1554523
Log:
SOLR-5536: Add ValueSource collapse criteria to CollapsingQParserPlugin
Added:
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/CollapseScoreFunction.java (with props)
Modified:
lucene/dev/trunk/solr/CHANGES.txt
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java
lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestCollapseQParserPlugin.java
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1554523&r1=1554522&r2=1554523&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Tue Dec 31 14:35:48 2013
@@ -134,6 +134,8 @@ New Features
* SOLR-5581: Give ZkCLI the ability to get files. (Gregory Chanan via Mark Miller)
+* SOLR-5536: Add ValueSource collapse criteria to CollapsingQParsingPlugin (Joel Bernstein)
+
Bug Fixes
----------------------
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java?rev=1554523&r1=1554522&r2=1554523&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/CollapsingQParserPlugin.java Tue Dec 31 14:35:48 2013
@@ -17,7 +17,12 @@
package org.apache.solr.search;
+import org.apache.lucene.queries.function.FunctionQuery;
+import org.apache.lucene.queries.function.FunctionValues;
+import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.util.BytesRef;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.schema.TrieFloatField;
import org.apache.solr.schema.TrieIntField;
import org.apache.solr.schema.TrieLongField;
@@ -47,6 +52,7 @@ import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
+import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
@@ -242,7 +248,7 @@ public class CollapsingQParserPlugin ext
SchemaField schemaField = schema.getField(this.field);
SortedDocValues docValues = null;
-
+ FunctionQuery funcQuery = null;
if(schemaField.hasDocValues()) {
docValues = searcher.getAtomicReader().getSortedDocValues(this.field);
} else {
@@ -252,11 +258,39 @@ public class CollapsingQParserPlugin ext
FieldType fieldType = null;
if(this.max != null) {
- fieldType = searcher.getSchema().getField(this.max).getType();
+ if(this.max.indexOf("(") == -1) {
+ fieldType = searcher.getSchema().getField(this.max).getType();
+ } else {
+ LocalSolrQueryRequest request = null;
+ try {
+ SolrParams params = new ModifiableSolrParams();
+ request = new LocalSolrQueryRequest(searcher.getCore(), params);
+ FunctionQParser functionQParser = new FunctionQParser(this.max, null, null,request);
+ funcQuery = (FunctionQuery)functionQParser.parse();
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ request.close();
+ }
+ }
}
if(this.min != null) {
- fieldType = searcher.getSchema().getField(this.min).getType();
+ if(this.min.indexOf("(") == -1) {
+ fieldType = searcher.getSchema().getField(this.min).getType();
+ } else {
+ LocalSolrQueryRequest request = null;
+ try {
+ SolrParams params = new ModifiableSolrParams();
+ request = new LocalSolrQueryRequest(searcher.getCore(), params);
+ FunctionQParser functionQParser = new FunctionQParser(this.min, null, null,request);
+ funcQuery = (FunctionQuery)functionQParser.parse();
+ } catch (Exception e) {
+ throw new IOException(e);
+ } finally {
+ request.close();
+ }
+ }
}
int maxDoc = searcher.maxDoc();
@@ -274,7 +308,8 @@ public class CollapsingQParserPlugin ext
max != null,
this.needsScores,
fieldType,
- boostDocs);
+ boostDocs,
+ funcQuery);
} else {
return new CollapsingScoreCollector(maxDoc, leafCount, docValues, this.nullPolicy, boostDocs);
}
@@ -508,7 +543,8 @@ public class CollapsingQParserPlugin ext
boolean max,
boolean needsScores,
FieldType fieldType,
- IntOpenHashSet boostDocs) throws IOException{
+ IntOpenHashSet boostDocs,
+ FunctionQuery funcQuery) throws IOException{
this.maxDoc = maxDoc;
this.contexts = new AtomicReaderContext[segments];
@@ -517,14 +553,18 @@ public class CollapsingQParserPlugin ext
this.nullPolicy = nullPolicy;
this.needsScores = needsScores;
this.boostDocs = boostDocs;
- if(fieldType instanceof TrieIntField) {
- this.fieldValueCollapse = new IntValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs);
- } else if(fieldType instanceof TrieLongField) {
- this.fieldValueCollapse = new LongValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs);
- } else if(fieldType instanceof TrieFloatField) {
- this.fieldValueCollapse = new FloatValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs);
+ if(funcQuery != null) {
+ this.fieldValueCollapse = new ValueSourceCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs, funcQuery);
} else {
- throw new IOException("min/max must be either TrieInt, TrieLong or TrieFloat.");
+ if(fieldType instanceof TrieIntField) {
+ this.fieldValueCollapse = new IntValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs);
+ } else if(fieldType instanceof TrieLongField) {
+ this.fieldValueCollapse = new LongValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs);
+ } else if(fieldType instanceof TrieFloatField) {
+ this.fieldValueCollapse = new FloatValueCollapse(maxDoc, field, nullPolicy, new int[valueCount], max, this.needsScores, boostDocs);
+ } else {
+ throw new IOException("min/max must be either TrieInt, TrieLong or TrieFloat.");
+ }
}
}
@@ -877,6 +917,97 @@ public class CollapsingQParserPlugin ext
}
}
+ private class ValueSourceCollapse extends FieldValueCollapse {
+
+ private FloatCompare comp;
+ private float nullVal;
+ private ValueSource valueSource;
+ private FunctionValues functionValues;
+ private float[] ordVals;
+ private Map rcontext = new HashMap();
+ private CollapseScore collapseScore = new CollapseScore();
+ private float score;
+ private boolean cscore;
+
+ public ValueSourceCollapse(int maxDoc,
+ String funcStr,
+ int nullPolicy,
+ int[] ords,
+ boolean max,
+ boolean needsScores,
+ IntOpenHashSet boostDocs,
+ FunctionQuery funcQuery) throws IOException {
+ super(maxDoc, null, nullPolicy, max, needsScores, boostDocs);
+ this.valueSource = funcQuery.getValueSource();
+ this.ords = ords;
+ this.ordVals = new float[ords.length];
+ Arrays.fill(ords, -1);
+
+ if(max) {
+ comp = new MaxFloatComp();
+ Arrays.fill(ordVals, -Float.MAX_VALUE );
+ } else {
+ this.nullVal = Float.MAX_VALUE;
+ comp = new MinFloatComp();
+ Arrays.fill(ordVals, Float.MAX_VALUE);
+ }
+
+ if(funcStr.indexOf("cscore()") != -1) {
+ this.cscore = true;
+ this.rcontext.put("CSCORE",this.collapseScore);
+ }
+
+ if(this.needsScores) {
+ this.scores = new float[ords.length];
+ if(nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+ nullScores = new FloatArrayList();
+ }
+ }
+ }
+
+ public void setNextReader(AtomicReaderContext context) throws IOException {
+ functionValues = this.valueSource.getValues(rcontext, context);
+ }
+
+ public void collapse(int ord, int contextDoc, int globalDoc) throws IOException {
+ if(needsScores || cscore) {
+ this.score = scorer.score();
+ this.collapseScore.score = score;
+ }
+
+ float val = functionValues.floatVal(contextDoc);
+
+ if(ord > -1) {
+ if(comp.test(val, ordVals[ord])) {
+ ords[ord] = globalDoc;
+ ordVals[ord] = val;
+ if(needsScores) {
+ scores[ord] = score;
+ }
+ }
+ } else if (this.collapsedSet.fastGet(globalDoc)) {
+ //Elevated doc so do nothing
+ } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_COLLAPSE) {
+ if(comp.test(val, nullVal)) {
+ nullVal = val;
+ nullDoc = globalDoc;
+ if(needsScores) {
+ nullScore = score;
+ }
+ }
+ } else if(this.nullPolicy == CollapsingPostFilter.NULL_POLICY_EXPAND) {
+ this.collapsedSet.fastSet(globalDoc);
+ if(needsScores) {
+ nullScores.add(score);
+ }
+ }
+ }
+ }
+
+ public static final class CollapseScore {
+ public float score;
+ }
+
private interface IntCompare {
public boolean test(int i1, int i2);
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java?rev=1554523&r1=1554522&r2=1554523&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/ValueSourceParser.java Tue Dec 31 14:35:48 2013
@@ -41,6 +41,7 @@ import org.apache.solr.common.util.Named
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.schema.*;
+import org.apache.solr.search.function.CollapseScoreFunction;
import org.apache.solr.search.function.distance.*;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
@@ -221,6 +222,12 @@ public abstract class ValueSourceParser
};
}
});
+ addParser("cscore", new ValueSourceParser() {
+ @Override
+ public ValueSource parse(FunctionQParser fp) throws SyntaxError {
+ return new CollapseScoreFunction();
+ }
+ });
addParser("sum", new ValueSourceParser() {
@Override
public ValueSource parse(FunctionQParser fp) throws SyntaxError {
Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/CollapseScoreFunction.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/CollapseScoreFunction.java?rev=1554523&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/CollapseScoreFunction.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/CollapseScoreFunction.java Tue Dec 31 14:35:48 2013
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.search.function;
+
+import org.apache.lucene.queries.function.ValueSource;
+import org.apache.lucene.queries.function.FunctionValues;
+import org.apache.lucene.index.AtomicReaderContext;
+import org.apache.solr.search.CollapsingQParserPlugin.CollapseScore;
+import java.util.Map;
+import java.io.IOException;
+
+public class CollapseScoreFunction extends ValueSource {
+
+ public String description() {
+ return "CollapseScoreFunction";
+ }
+
+ public boolean equals(Object o) {
+ if(o instanceof CollapseScoreFunction){
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ return 1213241257;
+ }
+
+ public FunctionValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
+ return new CollapseScoreFunctionValues(context);
+ }
+
+ public class CollapseScoreFunctionValues extends FunctionValues {
+
+ private CollapseScore cscore;
+
+ public CollapseScoreFunctionValues(Map context) {
+ this.cscore = (CollapseScore) context.get("CSCORE");
+ }
+
+ public int intVal(int doc) {
+ return 0;
+ }
+
+ public String toString(int doc) {
+ return Float.toString(cscore.score);
+ }
+
+ public float floatVal(int doc) {
+ return cscore.score;
+ }
+
+ public double doubleVal(int doc) {
+ return 0.0D;
+ }
+ }
+}
\ No newline at end of file
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java?rev=1554523&r1=1554522&r2=1554523&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java Tue Dec 31 14:35:48 2013
@@ -343,6 +343,11 @@ public class QueryEqualityTest extends S
public void testFuncRord() throws Exception {
assertFuncEquals("rord(foo_s)","rord(foo_s )");
}
+
+ public void testFuncCscore() throws Exception {
+ assertFuncEquals("cscore()", "cscore( )");
+ }
+
public void testFuncTop() throws Exception {
assertFuncEquals("top(sum(3,foo_i))");
}
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestCollapseQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestCollapseQParserPlugin.java?rev=1554523&r1=1554522&r2=1554523&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestCollapseQParserPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestCollapseQParserPlugin.java Tue Dec 31 14:35:48 2013
@@ -95,6 +95,40 @@ public class TestCollapseQParserPlugin e
"//result/doc[4]/float[@name='id'][.='6.0']"
);
+ // Test value source collapse criteria
+ params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("fq", "{!collapse field=group_s nullPolicy=collapse min=field(test_ti)}");
+ params.add("sort", "test_ti desc");
+ assertQ(req(params), "*[count(//doc)=3]",
+ "//result/doc[1]/float[@name='id'][.='4.0']",
+ "//result/doc[2]/float[@name='id'][.='1.0']",
+ "//result/doc[3]/float[@name='id'][.='5.0']"
+ );
+
+ // Test value source collapse criteria with cscore function
+ params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("fq", "{!collapse field=group_s nullPolicy=collapse min=cscore()}");
+ params.add("defType", "edismax");
+ params.add("bf", "field(test_ti)");
+ assertQ(req(params), "*[count(//doc)=3]",
+ "//result/doc[1]/float[@name='id'][.='4.0']",
+ "//result/doc[2]/float[@name='id'][.='1.0']",
+ "//result/doc[3]/float[@name='id'][.='5.0']"
+ );
+
+ // Test value source collapse criteria with compound cscore function
+ params = new ModifiableSolrParams();
+ params.add("q", "*:*");
+ params.add("fq", "{!collapse field=group_s nullPolicy=collapse min=sum(cscore(),field(test_ti))}");
+ params.add("defType", "edismax");
+ params.add("bf", "field(test_ti)");
+ assertQ(req(params), "*[count(//doc)=3]",
+ "//result/doc[1]/float[@name='id'][.='4.0']",
+ "//result/doc[2]/float[@name='id'][.='1.0']",
+ "//result/doc[3]/float[@name='id'][.='5.0']"
+ );
//Test collapse by score with elevation