You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2012/06/19 22:27:07 UTC
svn commit: r1351839 - in /lucene/dev/trunk:
lucene/suggest/src/java/org/apache/lucene/search/spell/ solr/
solr/core/src/java/org/apache/solr/schema/
solr/core/src/java/org/apache/solr/search/
solr/core/src/test/org/apache/solr/search/
Author: hossman
Date: Tue Jun 19 20:27:06 2012
New Revision: 1351839
URL: http://svn.apache.org/viewvc?rev=1351839&view=rev
Log:
SOLR-3548: Fixed a bug in the cachability of queries using the {!join} parser or the strdist() function, as well as some minor improvements to the hashCode implementation of {!bbox} and {!geofilt} queries
Added:
lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java (with props)
Modified:
lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/JaroWinklerDistance.java
lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/LevensteinDistance.java
lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/NGramDistance.java
lucene/dev/trunk/solr/CHANGES.txt
lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java
Modified: lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/JaroWinklerDistance.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/JaroWinklerDistance.java?rev=1351839&r1=1351838&r2=1351839&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/JaroWinklerDistance.java (original)
+++ lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/JaroWinklerDistance.java Tue Jun 19 20:27:06 2012
@@ -114,4 +114,25 @@ public class JaroWinklerDistance impleme
public float getThreshold() {
return threshold;
}
+
+ @Override
+ public int hashCode() {
+ return 113 * Float.floatToIntBits(threshold) * getClass().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (null == obj || getClass() != obj.getClass()) return false;
+
+ JaroWinklerDistance o = (JaroWinklerDistance)obj;
+ return (Float.floatToIntBits(o.threshold)
+ == Float.floatToIntBits(this.threshold));
+ }
+
+ @Override
+ public String toString() {
+ return "jarowinkler(" + threshold + ")";
+ }
+
}
Modified: lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/LevensteinDistance.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/LevensteinDistance.java?rev=1351839&r1=1351838&r2=1351839&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/LevensteinDistance.java (original)
+++ lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/LevensteinDistance.java Tue Jun 19 20:27:06 2012
@@ -106,4 +106,20 @@ public final class LevensteinDistance im
return 1.0f - ((float) p[n] / Math.max(other.length(), sa.length));
}
+ @Override
+ public int hashCode() {
+ return 163 * getClass().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (null == obj) return false;
+ return (getClass() == obj.getClass());
+ }
+
+ @Override
+ public String toString() {
+ return "levenstein";
+ }
}
Modified: lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/NGramDistance.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/NGramDistance.java?rev=1351839&r1=1351838&r2=1351839&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/NGramDistance.java (original)
+++ lucene/dev/trunk/lucene/suggest/src/java/org/apache/lucene/search/spell/NGramDistance.java Tue Jun 19 20:27:06 2012
@@ -141,4 +141,22 @@ public class NGramDistance implements St
return 1.0f - (p[sl] / Math.max(tl, sl));
}
+ @Override
+ public int hashCode() {
+ return 1427 * n * getClass().hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (null == obj || getClass() != obj.getClass()) return false;
+
+ NGramDistance o = (NGramDistance)obj;
+ return o.n == this.n;
+ }
+
+ @Override
+ public String toString() {
+ return "ngram(" + n + ")";
+ }
}
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1351839&r1=1351838&r2=1351839&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Tue Jun 19 20:27:06 2012
@@ -511,6 +511,11 @@ Bug Fixes
* SOLR-3522: fixed parsing of the 'literal()' function (hossman)
+* SOLR-3548: Fixed a bug in the cachability of queries using the {!join}
+ parser or the strdist() function, as well as some minor improvements to
+ the hashCode implementation of {!bbox} and {!geofilt} queries.
+ (hossman)
+
Other Changes
----------------------
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java?rev=1351839&r1=1351838&r2=1351839&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java Tue Jun 19 20:27:06 2012
@@ -595,6 +595,7 @@ class SpatialDistanceQuery extends Exten
// don't bother making the hash expensive - the center latitude + min longitude will be very uinque
long hash = Double.doubleToLongBits(latCenter);
hash = hash * 31 + Double.doubleToLongBits(lonMin);
+ hash = hash * 31 + (long)super.hashCode();
return (int)(hash >> 32 + hash);
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java?rev=1351839&r1=1351838&r2=1351839&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/JoinQParserPlugin.java Tue Jun 19 20:27:06 2012
@@ -549,7 +549,7 @@ class JoinQuery extends Query {
@Override
public boolean equals(Object o) {
- if (getClass() != o.getClass()) return false;
+ if (!super.equals(o)) return false;
JoinQuery other = (JoinQuery)o;
return this.fromField.equals(other.fromField)
&& this.toField.equals(other.toField)
@@ -562,7 +562,9 @@ class JoinQuery extends Query {
@Override
public int hashCode() {
- int h = q.hashCode() + (int)fromCoreOpenTime;
+ int h = super.hashCode();
+ h = h * 31 + q.hashCode();
+ h = h * 31 + (int)fromCoreOpenTime;
h = h * 31 + fromField.hashCode();
h = h * 31 + toField.hashCode();
return h;
Added: 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=1351839&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/QueryEqualityTest.java Tue Jun 19 20:27:06 2012
@@ -0,0 +1,752 @@
+package org.apache.solr.search;
+/*
+ * 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.
+ */
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.QueryUtils;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrRequestInfo;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.schema.IndexSchema;
+
+import java.util.Set;
+import java.util.HashSet;
+
+import org.junit.BeforeClass;
+import org.junit.AfterClass;
+
+
+
+/**
+ * Sanity checks that queries (generated by the QParser and ValueSourceParser
+ * framework) are appropraitely {@link Object#equals} and
+ * {@link Object#hashCode()} equivilent. If you are adding a new default
+ * QParser or ValueSourceParser, you will most likely get a failure from
+ * {@link #testParserCoverage} until you add a new test method to this class.
+ *
+ * @see ValueSourceParser#standardValueSourceParsers
+ * @see QParserPlugin.standardPlugins
+ * @see QueryUtils
+ **/
+public class QueryEqualityTest extends SolrTestCaseJ4 {
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig.xml","schema15.xml");
+ }
+
+ /** @see #testParserCoverage */
+ @AfterClass
+ public static void afterClassParserCoverageTest() {
+
+ if ( ! doAssertParserCoverage) return;
+
+ for (int i=0; i < QParserPlugin.standardPlugins.length; i+=2) {
+ assertTrue("qparser #"+i+" name not a string",
+ QParserPlugin.standardPlugins[i] instanceof String);
+ final String name = (String)QParserPlugin.standardPlugins[i];
+ assertTrue("testParserCoverage was run w/o any other method explicitly testing qparser: " + name, qParsersTested.contains(name));
+ }
+
+ for (final String name : ValueSourceParser.standardValueSourceParsers.keySet()) {
+ assertTrue("testParserCoverage was run w/o any other method explicitly testing val parser: " + name, valParsersTested.contains(name));
+ }
+
+ }
+
+ /** @see #testParserCoverage */
+ private static boolean doAssertParserCoverage = false;
+ /** @see #testParserCoverage */
+ private static final Set<String> qParsersTested = new HashSet<String>();
+ /** @see #testParserCoverage */
+ private static final Set<String> valParsersTested = new HashSet<String>();
+
+
+
+ public void testQueryLucene() throws Exception {
+ assertQueryEquals("lucene", "{!lucene}apache solr",
+ "apache solr", "apache solr ");
+ assertQueryEquals("lucene", "+apache +solr", "apache AND solr",
+ " +apache +solr");
+ }
+
+ public void testQueryLucenePlusSort() throws Exception {
+ assertQueryEquals("lucenePlusSort",
+ "apache solr", "apache solr", "apache solr ; score desc");
+ assertQueryEquals("lucenePlusSort",
+ "+apache +solr", "apache AND solr", " +apache +solr; score desc");
+ }
+
+ public void testQueryPrefix() throws Exception {
+ SolrQueryRequest req = req("myField","foo_s");
+ try {
+ assertQueryEquals("prefix", req,
+ "{!prefix f=$myField}asdf",
+ "{!prefix f=foo_s}asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryBoost() throws Exception {
+ SolrQueryRequest req = req("df","foo_s","myBoost","sum(3,foo_i)");
+ try {
+ assertQueryEquals("boost", req,
+ "{!boost b=$myBoost}asdf",
+ "{!boost b=$myBoost v=asdf}",
+ "{!boost b=sum(3,foo_i)}foo_s:asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryDismax() throws Exception {
+ for (final String type : new String[]{"dismax","edismax"}) {
+ assertQueryEquals(type, "{!"+type+"}apache solr",
+ "apache solr", "apache solr", "apache solr ");
+ assertQueryEquals(type, "+apache +solr", "apache AND solr",
+ " +apache +solr");
+ }
+ }
+ public void testField() throws Exception {
+ SolrQueryRequest req = req("myField","foo_s");
+ try {
+ assertQueryEquals("field", req,
+ "{!field f=$myField}asdf",
+ "{!field f=$myField v=asdf}",
+ "{!field f=foo_s}asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryRaw() throws Exception {
+ SolrQueryRequest req = req("myField","foo_s");
+ try {
+ assertQueryEquals("raw", req,
+ "{!raw f=$myField}asdf",
+ "{!raw f=$myField v=asdf}",
+ "{!raw f=foo_s}asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryTerm() throws Exception {
+ SolrQueryRequest req = req("myField","foo_s");
+ try {
+ assertQueryEquals("term", req,
+ "{!term f=$myField}asdf",
+ "{!term f=$myField v=asdf}",
+ "{!term f=foo_s}asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryNested() throws Exception {
+ SolrQueryRequest req = req("df", "foo_s");
+ try {
+ assertQueryEquals("query", req,
+ "{!query defType=lucene}asdf",
+ "{!query v='foo_s:asdf'}",
+ "{!query}foo_s:asdf",
+ "{!query}asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryFunc() throws Exception {
+ // more involved tests of specific functions in other methods
+ SolrQueryRequest req = req("myVar", "5",
+ "myField","foo_i",
+ "myInner","product(4,foo_i)");
+ try {
+ assertQueryEquals("func", req,
+ "{!func}sum(4,5)",
+ "{!func}sum(4,$myVar)",
+ "sum(4,5)");
+ assertQueryEquals("func", req,
+ "{!func}sum(1,2,3,4,5)",
+ "{!func}sum(1,2,3,4,$myVar)",
+ "sum(1,2,3,4,5)");
+ assertQueryEquals("func", req,
+ "{!func}sum(4,$myInner)",
+ "{!func}sum(4,product(4,foo_i))",
+ "{!func}sum(4,product(4,$myField))",
+ "{!func}sum(4,product(4,field(foo_i)))");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryFrange() throws Exception {
+ SolrQueryRequest req = req("myVar", "5",
+ "low","0.2",
+ "high", "20.4",
+ "myField","foo_i",
+ "myInner","product(4,foo_i)");
+ try {
+ assertQueryEquals("frange", req,
+ "{!frange l=0.2 h=20.4}sum(4,5)",
+ "{!frange l=$low h=$high}sum(4,$myVar)");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQueryGeofilt() throws Exception {
+ checkQuerySpatial("geofilt");
+ }
+ public void testQueryBbox() throws Exception {
+ checkQuerySpatial("bbox");
+ }
+
+ private void checkQuerySpatial(final String type) throws Exception {
+ SolrQueryRequest req = req("myVar", "5",
+ "d","109",
+ "pt","10.312,-20.556",
+ "sfield","store");
+ try {
+ assertQueryEquals(type, req,
+ "{!"+type+" d=109}",
+ "{!"+type+" sfield=$sfield}",
+ "{!"+type+" sfield=store d=109}",
+ "{!"+type+" sfield=store d=$d pt=$pt}",
+ "{!"+type+" sfield=store d=$d pt=10.312,-20.556}",
+ "{!"+type+"}");
+ // diff SpatialQueryable FieldTypes matter for determining final query
+ assertQueryEquals(type, req,
+ "{!"+type+" sfield=point_hash}",
+ "{!"+type+" sfield=point_hash d=109}",
+ "{!"+type+" sfield=point_hash d=$d pt=$pt}",
+ "{!"+type+" sfield=point_hash d=$d pt=10.312,-20.556}");
+ assertQueryEquals(type, req,
+ "{!"+type+" sfield=point}",
+ "{!"+type+" sfield=point d=109}",
+ "{!"+type+" sfield=point d=$d pt=$pt}",
+ "{!"+type+" sfield=point d=$d pt=10.312,-20.556}");
+ } finally {
+ req.close();
+ }
+ }
+ public void testQueryJoin() throws Exception {
+ SolrQueryRequest req = req("myVar", "5",
+ "df","text",
+ "ff","foo_s",
+ "tt", "bar_s");
+
+ try {
+ assertQueryEquals("join", req,
+ "{!join from=foo_s to=bar_s}asdf",
+ "{!join from=$ff to=$tt}asdf",
+ "{!join from=$ff to='bar_s'}text:asdf");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testQuerySurround() throws Exception {
+ assertQueryEquals("surround", "{!surround}and(apache,solr)",
+ "and(apache,solr)", "apache AND solr");
+ }
+
+ public void testFuncTestfunc() throws Exception {
+ assertFuncEquals("testfunc(foo_i)","testfunc(field(foo_i))");
+ assertFuncEquals("testfunc(23)");
+ assertFuncEquals("testfunc(sum(23,foo_i))",
+ "testfunc(sum(23,field(foo_i)))");
+ }
+ public void testFuncOrd() throws Exception {
+ assertFuncEquals("ord(foo_s)","ord(foo_s )");
+ }
+
+ public void testFuncLiteral() throws Exception {
+ SolrQueryRequest req = req("someVar","a string");
+ try {
+ assertFuncEquals(req,
+ "literal('a string')","literal(\"a string\")",
+ "literal($someVar)");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncRord() throws Exception {
+ assertFuncEquals("rord(foo_s)","rord(foo_s )");
+ }
+ public void testFuncTop() throws Exception {
+ assertFuncEquals("top(sum(3,foo_i))");
+ }
+ public void testFuncLinear() throws Exception {
+ SolrQueryRequest req = req("someVar","27");
+ try {
+ assertFuncEquals(req,
+ "linear(foo_i,$someVar,42)",
+ "linear(foo_i, 27, 42)");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncRecip() throws Exception {
+ SolrQueryRequest req = req("someVar","27");
+ try {
+ assertFuncEquals(req,
+ "recip(foo_i,$someVar,42, 27 )",
+ "recip(foo_i, 27, 42,$someVar)");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncScale() throws Exception {
+ SolrQueryRequest req = req("someVar","27");
+ try {
+ assertFuncEquals(req,
+ "scale(field(foo_i),$someVar,42)",
+ "scale(foo_i, 27, 42)");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncDiv() throws Exception {
+ assertFuncEquals("div(5,4)", "div(5, 4)");
+ assertFuncEquals("div(foo_i,4)", "div(foo_i, 4)",
+ "div(field('foo_i'), 4)");
+ assertFuncEquals("div(foo_i,sub(4,field('bar_i')))",
+ "div(field(foo_i), sub(4,bar_i))");
+
+ }
+ public void testFuncMap() throws Exception {
+ assertFuncEquals("map(field(foo_i), 0, 45, 100)",
+ "map(foo_i, 0.0, 45, 100)");
+ }
+
+ public void testFuncSum() throws Exception {
+ assertFuncEquals("sum(5,4)", "add(5, 4)");
+ assertFuncEquals("sum(5,4,3,2,1)", "add(5, 4, 3, 2, 1)");
+ assertFuncEquals("sum(foo_i,4)", "sum(foo_i, 4)",
+ "sum(field('foo_i'), 4)");
+ assertFuncEquals("add(foo_i,sub(4,field('bar_i')))",
+ "sum(field(foo_i), sub(4,bar_i))");
+
+ }
+
+ public void testFuncProduct() throws Exception {
+ assertFuncEquals("product(5,4,3,2,1)", "mul(5, 4, 3, 2, 1)");
+ assertFuncEquals("product(5,4)", "mul(5, 4)");
+ assertFuncEquals("product(foo_i,4)", "product(foo_i, 4)",
+ "product(field('foo_i'), 4)");
+ assertFuncEquals("mul(foo_i,sub(4,field('bar_i')))",
+ "product(field(foo_i), sub(4,bar_i))");
+
+ }
+ public void testFuncSub() throws Exception {
+ assertFuncEquals("sub(5,4)", "sub(5, 4)");
+ assertFuncEquals("sub(foo_i,4)", "sub(foo_i, 4)");
+ assertFuncEquals("sub(foo_i,sum(4,bar_i))", "sub(foo_i, sum(4,bar_i))");
+ }
+ public void testFuncVector() throws Exception {
+ assertFuncEquals("vector(5,4, field(foo_i))", "vector(5, 4, foo_i)");
+ assertFuncEquals("vector(foo_i,4)", "vector(foo_i, 4)");
+ assertFuncEquals("vector(foo_i,sum(4,bar_i))", "vector(foo_i, sum(4,bar_i))");
+ }
+ public void testFuncQuery() throws Exception {
+ SolrQueryRequest req = req("myQ","asdf");
+ try {
+ assertFuncEquals(req,
+ "query($myQ)",
+ "query($myQ,0)",
+ "query({!lucene v=$myQ},0)");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncBoost() throws Exception {
+ SolrQueryRequest req = req("myQ","asdf");
+ try {
+ assertFuncEquals(req,
+ "boost($myQ,sum(4,5))",
+ "boost({!lucene v=$myQ},sum(4,5))");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncJoindf() throws Exception {
+ assertFuncEquals("joindf(foo,bar)");
+ }
+
+ public void testFuncGeodist() throws Exception {
+ SolrQueryRequest req = req("pt","10.312,-20.556",
+ "sfield","store");
+ try {
+ assertFuncEquals(req,
+ "geodist()",
+ "geodist($sfield,$pt)",
+ "geodist(store,$pt)",
+ "geodist(field(store),$pt)",
+ "geodist(store,10.312,-20.556)");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testFuncHsin() throws Exception {
+ assertFuncEquals("hsin(45,true,0,0,45,45)");
+ }
+ public void testFuncGhhsin() throws Exception {
+ assertFuncEquals("ghhsin(45,point_hash,'asdf')",
+ "ghhsin(45,field(point_hash),'asdf')");
+ }
+ public void testFuncGeohash() throws Exception {
+ assertFuncEquals("geohash(45,99)");
+ }
+ public void testFuncDist() throws Exception {
+ assertFuncEquals("dist(2,45,99,101,111)",
+ "dist(2,vector(45,99),vector(101,111))");
+ }
+ public void testFuncSqedist() throws Exception {
+ assertFuncEquals("sqedist(45,99,101,111)",
+ "sqedist(vector(45,99),vector(101,111))");
+ }
+ public void testFuncMin() throws Exception {
+ assertFuncEquals("min(5,4,3,2,1)", "min(5, 4, 3, 2, 1)");
+ assertFuncEquals("min(foo_i,4)", "min(field('foo_i'), 4)");
+ assertFuncEquals("min(foo_i,sub(4,field('bar_i')))",
+ "min(field(foo_i), sub(4,bar_i))");
+ }
+ public void testFuncMax() throws Exception {
+ assertFuncEquals("max(5,4,3,2,1)", "max(5, 4, 3, 2, 1)");
+ assertFuncEquals("max(foo_i,4)", "max(field('foo_i'), 4)");
+ assertFuncEquals("max(foo_i,sub(4,field('bar_i')))",
+ "max(field(foo_i), sub(4,bar_i))");
+ }
+
+ public void testFuncMs() throws Exception {
+ // Note ms() takes in field name, not field(...)
+ assertFuncEquals("ms()", "ms(NOW)");
+ assertFuncEquals("ms(2000-01-01T00:00:00Z)",
+ "ms('2000-01-01T00:00:00Z')");
+ assertFuncEquals("ms(myDateField_dt)",
+ "ms('myDateField_dt')");
+ assertFuncEquals("ms(2000-01-01T00:00:00Z,myDateField_dt)",
+ "ms('2000-01-01T00:00:00Z','myDateField_dt')");
+ assertFuncEquals("ms(myDateField_dt, NOW)",
+ "ms('myDateField_dt', NOW)");
+ }
+ public void testFuncMathConsts() throws Exception {
+ assertFuncEquals("pi()");
+ assertFuncEquals("e()");
+ }
+ public void testFuncTerms() throws Exception {
+ SolrQueryRequest req = req("myField","field_t","myTerm","my term");
+ try {
+ for (final String type : new String[]{"docfreq","termfreq",
+ "totaltermfreq","ttf",
+ "idf","tf"}) {
+ // NOTE: these functions takes a field *name* not a field(..) source
+ assertFuncEquals(req,
+ type + "('field_t','my term')",
+ type + "(field_t,'my term')",
+ type + "(field_t,$myTerm)",
+ type + "(field_t,$myTerm)",
+ type + "($myField,$myTerm)");
+ }
+
+ // ttf is an alias for totaltermfreq
+ assertFuncEquals(req,
+ "ttf(field_t,'my term')", "ttf('field_t','my term')",
+ "totaltermfreq(field_t,'my term')");
+
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncSttf() throws Exception {
+ // sttf is an alias for sumtotaltermfreq
+ assertFuncEquals("sttf(foo_t)", "sttf('foo_t')",
+ "sumtotaltermfreq(foo_t)", "sumtotaltermfreq('foo_t')");
+ assertFuncEquals("sumtotaltermfreq('foo_t')");
+ }
+ public void testFuncNorm() throws Exception {
+ assertFuncEquals("norm(foo_t)","norm('foo_t')");
+ }
+ public void testFuncMaxdoc() throws Exception {
+ assertFuncEquals("maxdoc()");
+ }
+ public void testFuncNumdocs() throws Exception {
+ assertFuncEquals("numdocs()");
+ }
+
+ public void testFuncBools() throws Exception {
+ SolrQueryRequest req = req("myTrue","true","myFalse","false");
+ try {
+ assertFuncEquals(req, "true","$myTrue");
+ assertFuncEquals(req, "false","$myFalse");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testFuncExists() throws Exception {
+ SolrQueryRequest req = req("myField","field_t","myQ","asdf");
+ try {
+ assertFuncEquals(req,
+ "exists(field_t)",
+ "exists($myField)",
+ "exists(field('field_t'))",
+ "exists(field($myField))");
+ assertFuncEquals(req,
+ "exists(query($myQ))",
+ "exists(query({!lucene v=$myQ}))");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testFuncNot() throws Exception {
+ SolrQueryRequest req = req("myField","field_b", "myTrue","true");
+ try {
+ assertFuncEquals(req, "not(true)", "not($myTrue)");
+ assertFuncEquals(req, "not(not(true))", "not(not($myTrue))");
+ assertFuncEquals(req,
+ "not(field_b)",
+ "not($myField)",
+ "not(field('field_b'))",
+ "not(field($myField))");
+ assertFuncEquals(req,
+ "not(exists(field_b))",
+ "not(exists($myField))",
+ "not(exists(field('field_b')))",
+ "not(exists(field($myField)))");
+
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncDoubleValueBools() throws Exception {
+ SolrQueryRequest req = req("myField","field_b","myTrue","true");
+ try {
+ for (final String type : new String[]{"and","or","xor"}) {
+ assertFuncEquals(req,
+ type + "(field_b,true)",
+ type + "(field_b,$myTrue)",
+ type + "(field('field_b'),true)",
+ type + "(field($myField),$myTrue)",
+ type + "($myField,$myTrue)");
+ }
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testFuncIf() throws Exception {
+ SolrQueryRequest req = req("myBoolField","foo_b",
+ "myIntField","bar_i",
+ "myTrue","true");
+ try {
+ assertFuncEquals(req,
+ "if(foo_b,bar_i,25)",
+ "if($myBoolField,bar_i,25)",
+ "if(field('foo_b'),$myIntField,25)",
+ "if(field($myBoolField),field('bar_i'),25)");
+ assertFuncEquals(req,
+ "if(true,37,field($myIntField))",
+ "if($myTrue,37,$myIntField)");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testFuncDef() throws Exception {
+ SolrQueryRequest req = req("myField","bar_f");
+
+ try {
+ assertFuncEquals(req,
+ "def(bar_f,25)",
+ "def($myField,25)",
+ "def(field('bar_f'),25)");
+ assertFuncEquals(req,
+ "def(ceil(bar_f),25)",
+ "def(ceil($myField),25)",
+ "def(ceil(field('bar_f')),25)");
+ } finally {
+ req.close();
+ }
+ }
+
+ public void testFuncSingleValueMathFuncs() throws Exception {
+ SolrQueryRequest req = req("myVal","45", "myField","foo_i");
+ for (final String func : new String[] {"abs","rad","deg","sqrt","cbrt",
+ "log","ln","exp","sin","cos","tan",
+ "asin","acos","atan",
+ "sinh","cosh","tanh",
+ "ceil","floor","rint"}) {
+ try {
+ assertFuncEquals(req,
+ func + "(field(foo_i))", func + "(foo_i)",
+ func + "($myField)");
+ assertFuncEquals(req, func + "(45)", func+ "($myVal)");
+ } finally {
+ req.close();
+ }
+ }
+ }
+
+ public void testFuncDoubleValueMathFuncs() throws Exception {
+ SolrQueryRequest req = req("myVal","45", "myOtherVal", "27",
+ "myField","foo_i");
+ for (final String func : new String[] {"pow","hypot","atan2"}) {
+ try {
+ assertFuncEquals(req,
+ func + "(field(foo_i),$myVal)", func+"(foo_i,$myVal)",
+ func + "($myField,45)");
+ assertFuncEquals(req,
+ func+"(45,$myOtherVal)", func+"($myVal,27)",
+ func+"($myVal,$myOtherVal)");
+
+ } finally {
+ req.close();
+ }
+ }
+ }
+
+ public void testFuncStrdist() throws Exception {
+ SolrQueryRequest req = req("myVal","zot", "myOtherVal", "yak",
+ "myField","foo_s1");
+ try {
+ assertFuncEquals(req,
+ "strdist(\"zot\",literal('yak'),edit)",
+ "strdist(literal(\"zot\"),'yak', edit )",
+ "strdist(literal($myVal),literal($myOtherVal),edit)");
+ assertFuncEquals(req,
+ "strdist(\"zot\",literal($myOtherVal),ngram)",
+ "strdist(\"zot\",'yak', ngram, 2)");
+ assertFuncEquals(req,
+ "strdist(field('foo_s1'),literal($myOtherVal),jw)",
+ "strdist(field($myField),\"yak\",jw)",
+ "strdist($myField,'yak', jw)");
+ } finally {
+ req.close();
+ }
+ }
+ public void testFuncField() throws Exception {
+ assertFuncEquals("field(\"foo_i\")",
+ "field('foo_i\')",
+ "foo_i");
+ }
+
+ /**
+ * this test does not assert anything itself, it simply toggles a static
+ * boolean informing an @AfterClass method to assert that every default
+ * qparser and valuesource parser configured was recorded by
+ * assertQueryEquals and assertFuncEquals.
+ */
+ public void testParserCoverage() {
+ doAssertParserCoverage = true;
+ }
+
+
+ /**
+ * NOTE: defType is not only used to pick the parser, but also to record
+ * the parser being tested for coverage sanity checking
+ * @see #testParserCoverage
+ * @see #assertQueryEquals
+ */
+ protected void assertQueryEquals(final String defType,
+ final String... inputs) throws Exception {
+ SolrQueryRequest req = req();
+ try {
+ assertQueryEquals(defType, req, inputs);
+ } finally {
+ req.close();
+ }
+ }
+
+ /**
+ * NOTE: defType is not only used to pick the parser, but also to record
+ * the parser being tested for coverage sanity checking
+ *
+ * @see QueryUtils#check
+ * @see QueryUtils#checkEquals
+ * @see #testParserCoverage
+ */
+ protected void assertQueryEquals(final String defType,
+ final SolrQueryRequest req,
+ final String... inputs) throws Exception {
+ qParsersTested.add(defType);
+
+ final Query[] queries = new Query[inputs.length];
+
+ try {
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req,rsp));
+ for (int i = 0; i < inputs.length; i++) {
+ queries[i] = (QParser.getParser(inputs[i], defType, req).getQuery());
+ }
+ } finally {
+ SolrRequestInfo.clearRequestInfo();
+ }
+
+ for (int i = 0; i < queries.length; i++) {
+ QueryUtils.check(queries[i]);
+ // yes starting j=0 is redundent, we're making sure every query
+ // is equal to itself, and that the quality checks work regardless
+ // of which caller/callee is used.
+ for (int j = 0; j < queries.length; j++) {
+ QueryUtils.checkEqual(queries[i], queries[j]);
+ }
+ }
+ }
+
+ /**
+ * the function name for val parser coverage checking is extracted from
+ * the first input
+ * @see #assertQueryEquals
+ * @see #testParserCoverage
+ */
+ protected void assertFuncEquals(final String... inputs) throws Exception {
+ SolrQueryRequest req = req();
+ try {
+ assertFuncEquals(req, inputs);
+ } finally {
+ req.close();
+ }
+ }
+
+ /**
+ * the function name for val parser coverage checking is extracted from
+ * the first input
+ * @see #assertQueryEquals
+ * @see #testParserCoverage
+ */
+ protected void assertFuncEquals(final SolrQueryRequest req,
+ final String... inputs) throws Exception {
+ // pull out the function name
+ final String funcName = (new QueryParsing.StrParser(inputs[0])).getId();
+ valParsersTested.add(funcName);
+
+ assertQueryEquals(FunctionQParserPlugin.NAME, req, inputs);
+ }
+
+
+
+}