SOLR-1124: add top() function, fix ord/rord

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@768420 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yonik Seeley 2009-04-24 21:31:05 +00:00
parent accb58ed6f
commit f1be0a4f20
4 changed files with 120 additions and 19 deletions

View File

@ -23,22 +23,7 @@ import java.util.Map;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.search.function.BoostedQuery;
import org.apache.solr.search.function.DivFloatFunction;
import org.apache.solr.search.function.DocValues;
import org.apache.solr.search.function.LinearFloatFunction;
import org.apache.solr.search.function.MaxFloatFunction;
import org.apache.solr.search.function.OrdFieldSource;
import org.apache.solr.search.function.PowFloatFunction;
import org.apache.solr.search.function.ProductFloatFunction;
import org.apache.solr.search.function.QueryValueSource;
import org.apache.solr.search.function.RangeMapFloatFunction;
import org.apache.solr.search.function.ReciprocalFloatFunction;
import org.apache.solr.search.function.ReverseOrdFieldSource;
import org.apache.solr.search.function.ScaleFloatFunction;
import org.apache.solr.search.function.SimpleFloatFunction;
import org.apache.solr.search.function.SumFloatFunction;
import org.apache.solr.search.function.ValueSource;
import org.apache.solr.search.function.*;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
/**
@ -67,7 +52,7 @@ public abstract class ValueSourceParser implements NamedListInitializedPlugin
standardValueSourceParsers.put("ord", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
String field = fp.parseId();
return new OrdFieldSource(field);
return new TopValueSource(new OrdFieldSource(field));
}
public void init(NamedList args) {
@ -77,13 +62,23 @@ public abstract class ValueSourceParser implements NamedListInitializedPlugin
standardValueSourceParsers.put("rord", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
String field = fp.parseId();
return new ReverseOrdFieldSource(field);
return new TopValueSource(new ReverseOrdFieldSource(field));
}
public void init(NamedList args) {
}
});
standardValueSourceParsers.put("top", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
ValueSource source = fp.parseValueSource();
// nested top is redundant, and ord and rord get automatically wrapped
if (source instanceof TopValueSource) return source;
return new TopValueSource(source);
}
public void init(NamedList args) {
}
});
standardValueSourceParsers.put("linear", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
ValueSource source = fp.parseValueSource();

View File

@ -0,0 +1,84 @@
package org.apache.solr.search.function;
import org.apache.solr.search.SolrIndexReader;
import org.apache.lucene.index.IndexReader;
import java.io.IOException;
/**
* A value source that wraps another and ensures that the top level reader
* is used. This is useful for value sources like ord() who's value depend
* on all those around it.
*/
public class TopValueSource extends ValueSource {
private final ValueSource vs;
public TopValueSource(ValueSource vs) {
this.vs = vs;
}
public ValueSource getValueSource() {
return vs;
}
public String description() {
return "top(" + vs.description() + ')';
}
public DocValues getValues(IndexReader reader) throws IOException {
int offset = 0;
IndexReader topReader = reader;
if (topReader instanceof SolrIndexReader) {
SolrIndexReader r = (SolrIndexReader)topReader;
while (r.getParent() != null) {
offset += r.getBase();
r = r.getParent();
}
topReader = r;
}
final int off = offset;
final DocValues vals = vs.getValues(topReader);
if (topReader == reader) return vals;
return new DocValues() {
public float floatVal(int doc) {
return vals.floatVal(doc + off);
}
public int intVal(int doc) {
return vals.intVal(doc + off);
}
public long longVal(int doc) {
return vals.longVal(doc + off);
}
public double doubleVal(int doc) {
return vals.doubleVal(doc + off);
}
public String strVal(int doc) {
return vals.strVal(doc + off);
}
public String toString(int doc) {
return vals.strVal(doc + off);
}
};
}
public boolean equals(Object o) {
if (o.getClass() != TopValueSource.class) return false;
TopValueSource other = (TopValueSource)o;
return vs.equals(other.vs);
}
public int hashCode() {
int h = vs.hashCode();
return (h<<1) | (h>>>31);
}
public String toString() {
return "top("+vs.toString()+')';
}
}

View File

@ -273,6 +273,24 @@ public class TestFunctionQuery extends AbstractSolrTestCase {
singleTest(field, "\0", answers);
System.out.println("Done test "+i);
}
}
public void testGeneral() {
assertU(adoc("id","1"));
assertU(adoc("id","2"));
assertU(commit()); // create more than one segment
assertU(adoc("id","3"));
assertU(adoc("id","4"));
assertU(commit()); // create more than one segment
assertU(adoc("id","5"));
assertU(adoc("id","6"));
assertU(commit());
// test that ord and rord are working on a global index basis, not just
// at the segment level (since Lucene 2.9 has switched to per-segment searching)
assertQ(req("fl","*,score","q", "{!func}ord(id)", "fq","id:6"), "//float[@name='score']='6.0'");
assertQ(req("fl","*,score","q", "{!func}top(ord(id))", "fq","id:6"), "//float[@name='score']='6.0'");
assertQ(req("fl","*,score","q", "{!func}rord(id)", "fq","id:1"),"//float[@name='score']='6.0'");
assertQ(req("fl","*,score","q", "{!func}top(rord(id))", "fq","id:1"),"//float[@name='score']='6.0'");
}
}

View File

@ -89,9 +89,13 @@
<!-- lucene options specific to the main on-disk lucene index -->
<useCompoundFile>false</useCompoundFile>
<mergeFactor>10</mergeFactor>
<ramBufferSizeMB>32</ramBufferSizeMB>
<!-- for better multi-segment testing, we are using slower
indexing properties of maxBufferedDocs=10 and LogDocMergePolicy.
-->
<maxBufferedDocs>10</maxBufferedDocs>
<maxMergeDocs>2147483647</maxMergeDocs>
<maxFieldLength>10000</maxFieldLength>
<mergePolicy>org.apache.lucene.index.LogDocMergePolicy</mergePolicy>
<unlockOnStartup>true</unlockOnStartup>
</mainIndex>