You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by yo...@apache.org on 2009/11/20 16:09:38 UTC
svn commit: r882596 - in /lucene/solr/trunk: ./
src/java/org/apache/solr/search/ src/java/org/apache/solr/search/function/
src/test/org/apache/solr/search/function/
Author: yonik
Date: Fri Nov 20 15:09:37 2009
New Revision: 882596
URL: http://svn.apache.org/viewvc?rev=882596&view=rev
Log:
SOLR-1574: simplify specification of builtin functions, add many from java Math
Removed:
lucene/solr/trunk/src/java/org/apache/solr/search/function/DegreeFunction.java
lucene/solr/trunk/src/java/org/apache/solr/search/function/RadianFunction.java
Modified:
lucene/solr/trunk/CHANGES.txt
lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java
lucene/solr/trunk/src/test/org/apache/solr/search/function/TestFunctionQuery.java
Modified: lucene/solr/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=882596&r1=882595&r2=882596&view=diff
==============================================================================
--- lucene/solr/trunk/CHANGES.txt (original)
+++ lucene/solr/trunk/CHANGES.txt Fri Nov 20 15:09:37 2009
@@ -42,6 +42,8 @@
fielded queries, improved proximity boosting, and improved stopword
handling. (yonik)
+* SOLR-1574: Add many new functions from java Math (e.g. sin, cos) (yonik)
+
Optimizations
----------------------
Modified: lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java?rev=882596&r1=882595&r2=882596&view=diff
==============================================================================
--- lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java (original)
+++ lucene/solr/trunk/src/java/org/apache/solr/search/ValueSourceParser.java Fri Nov 20 15:09:37 2009
@@ -19,6 +19,7 @@
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Searcher;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.schema.DateField;
@@ -47,13 +48,11 @@
* Intented usage is to create pluggable, named functions for use in function queries.
*/
public abstract class ValueSourceParser implements NamedListInitializedPlugin {
-
/**
* Initialize the plugin.
*/
public void init(NamedList args) {}
-
/**
* Parse the user input into a ValueSource.
*
@@ -72,6 +71,17 @@
return standardValueSourceParsers.put(name, p);
}
+ /** Adds a new parser for the name and returns any existing one that was overriden.
+ * This is not thread safe.
+ */
+ public static ValueSourceParser addParser(NamedParser p) {
+ return standardValueSourceParsers.put(p.name(), p);
+ }
+
+ private static void alias(String source, String dest) {
+ standardValueSourceParsers.put(dest, standardValueSourceParsers.get(source));
+ }
+
static {
addParser("ord", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
@@ -130,13 +140,6 @@
return new TopValueSource(new ScaleFloatFunction(source, min, max));
}
});
- addParser("pow", new ValueSourceParser() {
- public ValueSource parse(FunctionQParser fp) throws ParseException {
- ValueSource a = fp.parseValueSource();
- ValueSource b = fp.parseValueSource();
- return new PowFloatFunction(a, b);
- }
- });
addParser("div", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
ValueSource a = fp.parseValueSource();
@@ -154,34 +157,7 @@
return new RangeMapFloatFunction(source, min, max, target, def);
}
});
- addParser("sqrt", new ValueSourceParser() {
- public ValueSource parse(FunctionQParser fp) throws ParseException {
- ValueSource source = fp.parseValueSource();
- return new SimpleFloatFunction(source) {
- protected String name() {
- return "sqrt";
- }
- protected float func(int doc, DocValues vals) {
- return (float) Math.sqrt(vals.floatVal(doc));
- }
- };
- }
- });
- addParser("log", new ValueSourceParser() {
- public ValueSource parse(FunctionQParser fp) throws ParseException {
- ValueSource source = fp.parseValueSource();
- return new SimpleFloatFunction(source) {
- protected String name() {
- return "log";
- }
-
- protected float func(int doc, DocValues vals) {
- return (float) Math.log10(vals.floatVal(doc));
- }
- };
- }
- });
addParser("abs", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
ValueSource source = fp.parseValueSource();
@@ -191,7 +167,7 @@
}
protected float func(int doc, DocValues vals) {
- return (float) Math.abs(vals.floatVal(doc));
+ return Math.abs(vals.floatVal(doc));
}
};
}
@@ -202,12 +178,16 @@
return new SumFloatFunction(sources.toArray(new ValueSource[sources.size()]));
}
});
+ alias("sum","add");
+
addParser("product", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
List<ValueSource> sources = fp.parseValueSourceList();
return new ProductFloatFunction(sources.toArray(new ValueSource[sources.size()]));
}
});
+ alias("product","mul");
+
addParser("sub", new ValueSourceParser() {
public ValueSource parse(FunctionQParser fp) throws ParseException {
ValueSource a = fp.parseValueSource();
@@ -276,16 +256,114 @@
}
});
-
- addParser("rad", new ValueSourceParser() {
- public ValueSource parse(FunctionQParser fp) throws ParseException {
- return new RadianFunction(fp.parseValueSource());
+ addParser(new DoubleParser("rad") {
+ public double func(int doc, DocValues vals) {
+ return Math.toRadians(vals.doubleVal(doc));
}
});
-
- addParser("deg", new ValueSourceParser() {
- public ValueSource parse(FunctionQParser fp) throws ParseException {
- return new DegreeFunction(fp.parseValueSource());
+ addParser(new DoubleParser("deg") {
+ public double func(int doc, DocValues vals) {
+ return Math.toDegrees(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("sqrt") {
+ public double func(int doc, DocValues vals) {
+ return Math.sqrt(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("cbrt") {
+ public double func(int doc, DocValues vals) {
+ return Math.cbrt(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("log") {
+ public double func(int doc, DocValues vals) {
+ return Math.log10(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("ln") {
+ public double func(int doc, DocValues vals) {
+ return Math.log(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("exp") {
+ public double func(int doc, DocValues vals) {
+ return Math.exp(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("sin") {
+ public double func(int doc, DocValues vals) {
+ return Math.sin(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("cos") {
+ public double func(int doc, DocValues vals) {
+ return Math.cos(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("tan") {
+ public double func(int doc, DocValues vals) {
+ return Math.tan(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("asin") {
+ public double func(int doc, DocValues vals) {
+ return Math.asin(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("acos") {
+ public double func(int doc, DocValues vals) {
+ return Math.acos(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("atan") {
+ public double func(int doc, DocValues vals) {
+ return Math.atan(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("sinh") {
+ public double func(int doc, DocValues vals) {
+ return Math.sinh(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("cosh") {
+ public double func(int doc, DocValues vals) {
+ return Math.cosh(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("tanh") {
+ public double func(int doc, DocValues vals) {
+ return Math.tanh(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("ceil") {
+ public double func(int doc, DocValues vals) {
+ return Math.ceil(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("floor") {
+ public double func(int doc, DocValues vals) {
+ return Math.floor(vals.doubleVal(doc));
+ }
+ });
+ addParser(new DoubleParser("rint") {
+ public double func(int doc, DocValues vals) {
+ return Math.rint(vals.doubleVal(doc));
+ }
+ });
+ addParser(new Double2Parser("pow") {
+ public double func(int doc, DocValues a, DocValues b) {
+ return Math.pow(a.doubleVal(doc), b.doubleVal(doc));
+ }
+ });
+ addParser(new Double2Parser("hypot") {
+ public double func(int doc, DocValues a, DocValues b) {
+ return Math.hypot(a.doubleVal(doc), b.doubleVal(doc));
+ }
+ });
+ addParser(new Double2Parser("atan2") {
+ public double func(int doc, DocValues a, DocValues b) {
+ return Math.atan2(a.doubleVal(doc), b.doubleVal(doc));
}
});
@@ -319,9 +397,21 @@
}
});
addParser("ms", new DateValueSourceParser());
+
+
+ addParser("pi", new ValueSourceParser() {
+ public ValueSource parse(FunctionQParser fp) throws ParseException {
+ return new DoubleConstValueSource(Math.PI);
+ }
+ });
+ addParser("e", new ValueSourceParser() {
+ public ValueSource parse(FunctionQParser fp) throws ParseException {
+ return new DoubleConstValueSource(Math.E);
+ }
+ });
}
- protected void splitSources(int dim, List<ValueSource> sources, List<ValueSource> dest1, List<ValueSource> dest2) {
+ private static void splitSources(int dim, List<ValueSource> sources, List<ValueSource> dest1, List<ValueSource> dest2) {
//Get dim value sources for the first vector
for (int i = 0; i < dim; i++) {
dest1.add(sources.get(i));
@@ -483,3 +573,193 @@
return this.constant == other.constant;
}
}
+
+// Private for now - we need to revisit how to handle typing in function queries
+class DoubleConstValueSource extends ValueSource {
+ final double constant;
+
+ public DoubleConstValueSource(double constant) {
+ this.constant = constant;
+ }
+
+ public String description() {
+ return "const(" + constant + ")";
+ }
+
+ public DocValues getValues(Map context, IndexReader reader) throws IOException {
+ return new DocValues() {
+ public float floatVal(int doc) {
+ return (float)constant;
+ }
+
+ public int intVal(int doc) {
+ return (int) constant;
+ }
+
+ public long longVal(int doc) {
+ return (long)constant;
+ }
+
+ public double doubleVal(int doc) {
+ return constant;
+ }
+
+ public String strVal(int doc) {
+ return Double.toString(constant);
+ }
+
+ public String toString(int doc) {
+ return description();
+ }
+ };
+ }
+
+ public int hashCode() {
+ long bits = Double.doubleToRawLongBits(constant);
+ return (int)(bits ^ (bits >>> 32));
+ }
+
+ public boolean equals(Object o) {
+ if (DoubleConstValueSource.class != o.getClass()) return false;
+ DoubleConstValueSource other = (DoubleConstValueSource) o;
+ return this.constant == other.constant;
+ }
+}
+
+
+abstract class NamedParser extends ValueSourceParser {
+ private final String name;
+ public NamedParser(String name) {
+ this.name = name;
+ }
+ public String name() {
+ return name;
+ }
+}
+
+
+abstract class DoubleParser extends NamedParser {
+ public DoubleParser(String name) {
+ super(name);
+ }
+
+ public abstract double func(int doc, DocValues vals);
+
+ public ValueSource parse(FunctionQParser fp) throws ParseException {
+ return new Function(fp.parseValueSource());
+ }
+
+ class Function extends SingleFunction {
+ public Function(ValueSource source) {
+ super(source);
+ }
+
+ public String name() {
+ return DoubleParser.this.name();
+ }
+
+ @Override
+ public DocValues getValues(Map context, IndexReader reader) throws IOException {
+ final DocValues vals = source.getValues(context, reader);
+ return new DocValues() {
+ public float floatVal(int doc) {
+ return (float)doubleVal(doc);
+ }
+ public int intVal(int doc) {
+ return (int)doubleVal(doc);
+ }
+ public long longVal(int doc) {
+ return (long)doubleVal(doc);
+ }
+ public double doubleVal(int doc) {
+ return func(doc, vals);
+ }
+ public String strVal(int doc) {
+ return Double.toString(doubleVal(doc));
+ }
+ public String toString(int doc) {
+ return name() + '(' + vals.toString(doc) + ')';
+ }
+ };
+ }
+ }
+}
+
+
+abstract class Double2Parser extends NamedParser {
+ public Double2Parser(String name) {
+ super(name);
+ }
+
+ public abstract double func(int doc, DocValues a, DocValues b);
+
+ public ValueSource parse(FunctionQParser fp) throws ParseException {
+ return new Function(fp.parseValueSource(), fp.parseValueSource());
+ }
+
+ class Function extends ValueSource {
+ private final ValueSource a;
+ private final ValueSource b;
+
+ /**
+ * @param a the base.
+ * @param b the exponent.
+ */
+ public Function(ValueSource a, ValueSource b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ public String description() {
+ return name() + "(" + a.description() + "," + b.description() + ")";
+ }
+
+ public DocValues getValues(Map context, IndexReader reader) throws IOException {
+ final DocValues aVals = a.getValues(context, reader);
+ final DocValues bVals = b.getValues(context, reader);
+ return new DocValues() {
+ public float floatVal(int doc) {
+ return (float)doubleVal(doc);
+ }
+ public int intVal(int doc) {
+ return (int)doubleVal(doc);
+ }
+ public long longVal(int doc) {
+ return (long)doubleVal(doc);
+ }
+ public double doubleVal(int doc) {
+ return func(doc, aVals, bVals);
+ }
+ public String strVal(int doc) {
+ return Double.toString(doubleVal(doc));
+ }
+ public String toString(int doc) {
+ return name() + '(' + aVals.toString(doc) + ',' + bVals.toString(doc) + ')';
+ }
+ };
+ }
+
+ @Override
+ public void createWeight(Map context, Searcher searcher) throws IOException {
+ a.createWeight(context,searcher);
+ b.createWeight(context,searcher);
+ }
+
+ public int hashCode() {
+ int h = a.hashCode();
+ h ^= (h << 13) | (h >>> 20);
+ h += b.hashCode();
+ h ^= (h << 23) | (h >>> 10);
+ h += name().hashCode();
+ return h;
+ }
+
+ public boolean equals(Object o) {
+ if (this.getClass() != o.getClass()) return false;
+ Function other = (Function)o;
+ return this.a.equals(other.a)
+ && this.b.equals(other.b);
+ }
+ }
+
+}
Modified: lucene/solr/trunk/src/test/org/apache/solr/search/function/TestFunctionQuery.java
URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/search/function/TestFunctionQuery.java?rev=882596&r1=882595&r2=882596&view=diff
==============================================================================
--- lucene/solr/trunk/src/test/org/apache/solr/search/function/TestFunctionQuery.java (original)
+++ lucene/solr/trunk/src/test/org/apache/solr/search/function/TestFunctionQuery.java Fri Nov 20 15:09:37 2009
@@ -278,7 +278,7 @@
}
}
- public void testGeneral() {
+ public void testGeneral() throws Exception {
assertU(adoc("id","1", "a_tdt","2009-08-31T12:10:10.123Z", "b_tdt","2009-08-31T12:10:10.124Z"));
assertU(adoc("id","2"));
assertU(commit()); // create more than one segment
@@ -326,9 +326,12 @@
q ="{!func}sub(div(sum(0.0,product(1,query($qq))),1),0)";
assertQ(req("fl","*,score","q", q, "qq","text:batman", "fq",fq), "//float[@name='score']<'1.0'");
assertQ(req("fl","*,score","q", q, "qq","text:superman", "fq",fq), "//float[@name='score']>'1.0'");
+
+ doTestDegreeRads();
+ doTestFuncs();
}
- public void testDegreeRads() throws Exception {
+ public void doTestDegreeRads() throws Exception {
assertU(adoc("id", "1", "x_td", "0", "y_td", "0"));
assertU(adoc("id", "2", "x_td", "90", "y_td", String.valueOf(Math.PI / 2)));
assertU(adoc("id", "3", "x_td", "45", "y_td", String.valueOf(Math.PI / 4)));
@@ -343,4 +346,47 @@
assertQ(req("fl", "*,score", "q", "{!func}deg(y_td)", "fq", "id:2"), "//float[@name='score']='90.0'");
assertQ(req("fl", "*,score", "q", "{!func}deg(y_td)", "fq", "id:3"), "//float[@name='score']='45.0'");
}
+
+ public void dofunc(String func, double val) throws Exception {
+ // String sval = Double.toString(val);
+ String sval = Float.toString((float)val);
+
+ assertQ(req("fl", "*,score", "defType","func", "fq","id:1", "q",func),
+ "//float[@name='score']='" + sval + "'");
+ }
+
+ public void doTestFuncs() throws Exception {
+ assertU(adoc("id", "1", "foo_d", "9"));
+ assertU(commit());
+
+ dofunc("1.0", 1.0);
+ dofunc("e()", Math.E);
+ dofunc("pi()", Math.PI);
+ dofunc("add(2,3)", 2+3);
+ dofunc("mul(2,3)", 2*3);
+ dofunc("rad(45)", Math.toRadians(45));
+ dofunc("deg(.5)", Math.toDegrees(.5));
+ dofunc("sqrt(9)", Math.sqrt(9));
+ dofunc("cbrt(8)", Math.cbrt(8));
+ dofunc("log(100)", Math.log10(100));
+ dofunc("ln(3)", Math.log(3));
+ dofunc("exp(1)", Math.exp(1));
+ dofunc("sin(.5)", Math.sin(.5));
+ dofunc("cos(.5)", Math.cos(.5));
+ dofunc("tan(.5)", Math.tan(.5));
+ dofunc("asin(.5)", Math.asin(.5));
+ dofunc("acos(.5)", Math.acos(.5));
+ dofunc("atan(.5)", Math.atan(.5));
+ dofunc("sinh(.5)", Math.sinh(.5));
+ dofunc("cosh(.5)", Math.cosh(.5));
+ dofunc("tanh(.5)", Math.tanh(.5));
+ dofunc("ceil(2.3)", Math.ceil(2.3));
+ dofunc("floor(2.3)", Math.floor(2.3));
+ dofunc("rint(2.3)", Math.rint(2.3));
+ dofunc("pow(2,0.5)", Math.pow(2,0.5));
+ dofunc("hypot(3,4)", Math.hypot(3,4));
+ dofunc("atan2(.25,.5)", Math.atan2(.25,.5));
+ }
+
+
}
\ No newline at end of file