| /* |
| * 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; |
| |
| import java.util.Arrays; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| import java.util.Random; |
| |
| import com.codahale.metrics.Gauge; |
| import org.apache.lucene.search.BooleanClause; |
| import org.apache.lucene.search.BooleanQuery; |
| import org.apache.lucene.search.BoostQuery; |
| import org.apache.lucene.search.ConstantScoreQuery; |
| import org.apache.lucene.search.DocValuesFieldExistsQuery; |
| import org.apache.lucene.search.IndexSearcher; |
| import org.apache.lucene.search.NormsFieldExistsQuery; |
| import org.apache.lucene.search.PointInSetQuery; |
| import org.apache.lucene.search.Query; |
| import org.apache.lucene.search.TermInSetQuery; |
| import org.apache.lucene.search.TermQuery; |
| import org.apache.lucene.util.LuceneTestCase; |
| import org.apache.solr.SolrTestCaseJ4; |
| import org.apache.solr.SolrTestCaseUtil; |
| import org.apache.solr.common.SolrException; |
| import org.apache.solr.common.SolrInputDocument; |
| import org.apache.solr.common.params.MapSolrParams; |
| import org.apache.solr.common.params.ModifiableSolrParams; |
| import org.apache.solr.common.params.SolrParams; |
| import org.apache.solr.common.util.Utils; |
| import org.apache.solr.core.SolrCore; |
| import org.apache.solr.parser.QueryParser; |
| import org.apache.solr.query.FilterQuery; |
| import org.apache.solr.request.SolrQueryRequest; |
| import org.apache.solr.schema.IndexSchema; |
| import org.apache.solr.schema.NumberType; |
| import org.apache.solr.schema.SchemaField; |
| import org.junit.AfterClass; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| |
| import static org.hamcrest.core.StringContains.containsString; |
| |
| public class TestSolrQueryParser extends SolrTestCaseJ4 { |
| @BeforeClass |
| public static void beforeClass() throws Exception { |
| System.setProperty("enable.update.log", "false"); // schema12 doesn't support _version_ |
| System.setProperty("solr.max.booleanClauses", "42"); // lower for testing |
| initCore("solrconfig.xml", "schema_syn.xml"); |
| createIndex(); |
| } |
| |
| private static final List<String> HAS_VAL_FIELDS = new ArrayList<String>(41); |
| private static final List<String> HAS_NAN_FIELDS = new ArrayList<String>(12); |
| |
| @AfterClass |
| public static void afterClass() throws Exception { |
| HAS_VAL_FIELDS.clear(); |
| HAS_NAN_FIELDS.clear(); |
| } |
| |
| public static void createIndex() { |
| String v; |
| v = "how now brown cow"; |
| assertU(adoc("id", "1", "text", v, "text_np", v, "foo_i","11")); |
| v = "now cow"; |
| assertU(adoc("id", "2", "text", v, "text_np", v, "foo_i","12")); |
| assertU(adoc("id", "3", "foo_s", "a ' \" \\ {! ) } ( { z")); // A value filled with special chars |
| |
| assertU(adoc("id", "10", "qqq_s", "X")); |
| assertU(adoc("id", "11", "www_s", "X")); |
| assertU(adoc("id", "12", "eee_s", "X")); |
| assertU(adoc("id", "13", "eee_s", "'balance'", "rrr_s", "/leading_slash")); |
| |
| assertU(adoc("id", "20", "syn", "wifi ATM")); |
| |
| { // make a doc that has a value in *lots* of fields that no other doc has |
| SolrInputDocument doc = sdoc("id", "999"); |
| |
| // numbers... |
| for (String t : Arrays.asList("i", "l", "f", "d")) { |
| for (String s : Arrays.asList("", "s", "_dv", "s_dv", "_dvo", "_norms")) { |
| final String f = "has_val_" + t + s; |
| HAS_VAL_FIELDS.add(f); |
| doc.addField(f, "42"); |
| |
| if (t.equals("f") || t.equals("d")) { |
| String nanField = "nan_val_" + t + s; |
| doc.addField(nanField, "NaN"); |
| HAS_NAN_FIELDS.add(nanField); |
| |
| // Add a NaN & non-NaN value for multivalue fields, these should match :* and :[* TO *] equivalently |
| if (s.startsWith("s")) { |
| String bothField = "both_val_" + t + s; |
| doc.addField(bothField, "42"); |
| doc.addField(bothField, "NaN"); |
| HAS_VAL_FIELDS.add(bothField); |
| } |
| } |
| } |
| } |
| // boolean...booleans |
| for (String s : Arrays.asList("", "s", "_dv", "_norms")) { |
| final String f = "has_val_b" + s; |
| HAS_VAL_FIELDS.add(f); |
| doc.addField(f, "false"); |
| } |
| |
| // dates (and strings/text -- they don't care about the format)... |
| for (String s : Arrays.asList("dt", "s", "s1", "t", "t_on", "dt_norms", "s_norms", "dt_dv", "s_dv")) { |
| final String f = "has_val_" + s; |
| HAS_VAL_FIELDS.add(f); |
| doc.addField(f, "2019-01-12T00:00:00Z"); |
| } |
| assertU(adoc(doc)); |
| } |
| |
| assertU(adoc("id", "30", "shingle23", "A B X D E")); |
| |
| assertU(commit()); |
| } |
| |
| public void testDocsWithValuesInField() throws Exception { |
| assertEquals("someone changed the test setup of HAS_VAL_FIELDS, w/o updating the sanity check", |
| 41, HAS_VAL_FIELDS.size()); |
| for (String f : HAS_VAL_FIELDS) { |
| // for all of these fields, these 2 syntaxes should be functionally equivilent |
| // in matching the one doc that contains these fields |
| for (String q : Arrays.asList( f + ":*", f + ":[* TO *]" )) { |
| assertJQ(req("q", q) |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='999'" |
| ); |
| // the same syntaxes should be valid even if no doc has the field... |
| assertJQ(req("q", "bogus___" + q) |
| , "/response/numFound==0" |
| ); |
| |
| } |
| } |
| } |
| |
| public void testDocsWithNaNInField() throws Exception { |
| assertEquals("someone changed the test setup of HAS_NAN_FIELDS, w/o updating the sanity check", |
| 12, HAS_NAN_FIELDS.size()); |
| for (String f : HAS_NAN_FIELDS) { |
| // for all of these fields, field:* should NOT be equivalent to field:[* TO *] |
| assertJQ(req("q", f + ":*") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='999'" |
| ); |
| assertJQ(req("q", f + ":[* TO *]") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("q", f + ":[-Infinity TO Infinity]") |
| , "/response/numFound==0" |
| ); |
| for (String q : Arrays.asList( f + ":*", f + ":[* TO *]", f + ":[-Infinity TO Infinity]" )) { |
| // the same syntaxes should be valid even if no doc has the field... |
| assertJQ(req("q", "bogus___" + q) |
| , "/response/numFound==0" |
| ); |
| |
| } |
| } |
| } |
| |
| @Test |
| public void testPhrase() { |
| // "text" field's type has WordDelimiterGraphFilter (WDGFF) and autoGeneratePhraseQueries=true |
| // should generate a phrase of "now cow" and match only one doc |
| assertQ(req("q", "text:now-cow", "indent", "true", "sow","true") |
| , "//*[@numFound='1']" |
| ); |
| // When sow=false, autoGeneratePhraseQueries=true only works when a graph is produced |
| // (i.e. overlapping terms, e.g. if WDGFF's preserveOriginal=1 or concatenateWords=1). |
| // The WDGFF config on the "text" field doesn't produce a graph, so the generated query |
| // is not a phrase query. As a result, docs can match that don't match phrase query "now cow" |
| assertQ(req("q", "text:now-cow", "indent", "true", "sow","false") |
| , "//*[@numFound='2']" |
| ); |
| assertQ(req("q", "text:now-cow", "indent", "true") // default sow=false |
| , "//*[@numFound='2']" |
| ); |
| |
| // "text_np" field's type has WDGFF and (default) autoGeneratePhraseQueries=false |
| // should generate a query of (now OR cow) and match both docs |
| assertQ(req("q", "text_np:now-cow", "indent", "true") |
| , "//*[@numFound='2']" |
| ); |
| } |
| |
| @Test |
| public void testLocalParamsInQP() throws Exception { |
| assertJQ(req("q", "qaz {!term f=text v=$qq} wsx", "qq", "now") |
| , "/response/numFound==2" |
| ); |
| |
| assertJQ(req("q", "qaz {!term f=text v=$qq} wsx", "qq", "nomatch") |
| , "/response/numFound==0" |
| ); |
| |
| assertJQ(req("q", "qaz {!term f=text}now wsx", "qq", "now") |
| , "/response/numFound==2" |
| ); |
| |
| assertJQ(req("q", "qaz {!term f=foo_s v='a \\' \" \\\\ {! ) } ( { z'} wsx") // single quote escaping |
| , "/response/numFound==1" |
| ); |
| |
| assertJQ(req("q", "qaz {!term f=foo_s v=\"a ' \\\" \\\\ {! ) } ( { z\"} wsx") // double quote escaping |
| , "/response/numFound==1" |
| ); |
| |
| // double-join to test back-to-back local params |
| assertJQ(req("q", "qaz {!join from=www_s to=eee_s}{!join from=qqq_s to=www_s}id:10") |
| , "/response/docs/[0]/id=='12'" |
| ); |
| } |
| |
| @Test |
| public void testSolr4121() throws Exception { |
| // At one point, balanced quotes messed up the parser(SOLR-4121) |
| assertJQ(req("q", "eee_s:'balance'", "indent", "true") |
| , "/response/numFound==1" |
| ); |
| } |
| |
| @Test |
| public void testSyntax() throws Exception { |
| // a bare * should be treated as *:* |
| assertJQ(req("q", "*", "df", "doesnotexist_s") |
| , "/response/docs/[0]==" // make sure we get something... |
| ); |
| assertJQ(req("q", "doesnotexist_s:*") |
| , "/response/numFound==0" // nothing should be found |
| ); |
| assertJQ(req("q", "doesnotexist_s:( * * * )") |
| , "/response/numFound==0" // nothing should be found |
| ); |
| |
| // length of date math caused issues... |
| String expected; |
| { |
| try (SolrCore core = h.getCore()) { |
| SchemaField foo_dt = core.getLatestSchema().getField("foo_dt"); |
| expected = "foo_dt:2013-09-11T00:00:00Z"; |
| if (foo_dt.getType().isPointField()) { |
| expected = "(foo_dt:[1378857600000 TO 1378857600000])"; |
| if (foo_dt.hasDocValues() && foo_dt.indexed()) { |
| expected = "IndexOrDocValuesQuery" + expected; |
| } |
| } |
| } |
| assertJQ(req("q", "foo_dt:\"2013-03-08T00:46:15Z/DAY+000MILLISECONDS+00SECONDS+00MINUTES+00HOURS+0000000000YEARS+6MONTHS+3DAYS\"", "debug", "query") |
| , "/debug/parsedquery=='"+expected+"'"); |
| } |
| } |
| |
| @Test |
| public void testNestedQueryModifiers() throws Exception { |
| // One previous error was that for nested queries, outer parameters overrode nested parameters. |
| // For example _query_:"\"a b\"~2" was parsed as "a b" |
| |
| String subqq = "_query_:\"{!v=$qq}\""; |
| |
| assertJQ(req("q", "_query_:\"\\\"how brown\\\"~2\"" |
| , "debug", "query" |
| ) |
| , "/response/docs/[0]/id=='1'" |
| ); |
| |
| assertJQ(req("q", subqq, "qq", "\"how brown\"~2" |
| , "debug", "query" |
| ) |
| , "/response/docs/[0]/id=='1'" |
| ); |
| |
| // Should explicit slop override? It currently does not, but that could be considered a bug. |
| assertJQ(req("q", subqq + "~1", "qq", "\"how brown\"~2" |
| , "debug", "query" |
| ) |
| , "/response/docs/[0]/id=='1'" |
| ); |
| |
| // Should explicit slop override? It currently does not, but that could be considered a bug. |
| assertJQ(req("q", " {!v=$qq}~1", "qq", "\"how brown\"~2" |
| , "debug", "query" |
| ) |
| , "/response/docs/[0]/id=='1'" |
| ); |
| |
| assertJQ(req("fq", "id:1", "fl", "id,score", "q", subqq + "^3", "qq", "text:x^2" |
| , "debug", "query" |
| ) |
| , "/debug/parsedquery_toString=='((text:x)^2.0)^3.0'" |
| ); |
| |
| assertJQ(req("fq", "id:1", "fl", "id,score", "q", " {!v=$qq}^3", "qq", "text:x^2" |
| , "debug", "query" |
| ) |
| , "/debug/parsedquery_toString=='((text:x)^2.0)^3.0'" |
| ); |
| |
| } |
| |
| |
| @Test |
| public void testCSQ() throws Exception { |
| SolrQueryRequest req = req(); |
| |
| QParser qParser = QParser.getParser("text:x^=3", req); |
| Query q = qParser.getQuery(); |
| assertTrue(q instanceof BoostQuery); |
| assertTrue(((BoostQuery) q).getQuery() instanceof ConstantScoreQuery); |
| assertEquals(3.0, ((BoostQuery) q).getBoost(), 0.0f); |
| |
| req.close(); |
| } |
| |
| |
| // automatically use TermsQuery when appropriate |
| @Test |
| public void testAutoTerms() throws Exception { |
| SolrQueryRequest req = req(); |
| QParser qParser; |
| Query q,qq; |
| |
| Map<String, String> sowFalseParamsMap = new HashMap<>(); |
| sowFalseParamsMap.put("sow", "false"); |
| Map<String, String> sowTrueParamsMap = new HashMap<>(); |
| sowTrueParamsMap.put("sow", "true"); |
| List<MapSolrParams> paramMaps = Arrays.asList |
| (new MapSolrParams(Collections.emptyMap()), // no sow param (i.e. the default sow value) |
| new MapSolrParams(sowFalseParamsMap), |
| new MapSolrParams(sowTrueParamsMap)); |
| |
| for (MapSolrParams params : paramMaps) { |
| // relevance query should not be a filter |
| qParser = QParser.getParser("foo_s:(a b c)", req); |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals(3, ((BooleanQuery) q).clauses().size()); |
| |
| // small filter query should still use BooleanQuery |
| if (QueryParser.TERMS_QUERY_THRESHOLD > 3) { |
| qParser = QParser.getParser("foo_s:(a b c)", req); |
| qParser.setParams(params); |
| qParser.setIsFilter(true); // this may change in the future |
| q = qParser.getQuery(); |
| assertEquals(3, ((BooleanQuery) q).clauses().size()); |
| } |
| |
| // large relevancy query should use BooleanQuery |
| // TODO: we may decide that string fields shouldn't have relevance in the future... change to a text field w/o a stop filter if so |
| qParser = QParser.getParser("foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z)", req); |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals(26, ((BooleanQuery)q).clauses().size()); |
| |
| // large filter query should use TermsQuery |
| qParser = QParser.getParser("foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z)", req); |
| qParser.setIsFilter(true); // this may change in the future |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals(26, ((TermInSetQuery)q).getTermData().size()); |
| |
| // large numeric filter query should use TermsQuery |
| qParser = QParser.getParser("foo_ti:(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 11)", req); |
| qParser.setIsFilter(true); // this may change in the future |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| if (Boolean.getBoolean(NUMERIC_POINTS_SYSPROP)) { |
| assertEquals(20, ((PointInSetQuery)q).getPackedPoints().size()); |
| } else { |
| assertEquals(20, ((TermInSetQuery)q).getTermData().size()); |
| } |
| |
| // for point fields large filter query should use PointInSetQuery |
| qParser = QParser.getParser("foo_pi:(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 11)", req); |
| qParser.setIsFilter(true); // this may change in the future |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertTrue(q instanceof PointInSetQuery); |
| assertEquals(20, ((PointInSetQuery)q).getPackedPoints().size()); |
| |
| // a filter() clause inside a relevancy query should be able to use a TermsQuery |
| qParser = QParser.getParser("foo_s:aaa filter(foo_s:(a b c d e f g h i j k l m n o p q r s t u v w x y z))", req); |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals(2, ((BooleanQuery)q).clauses().size()); |
| qq = ((BooleanQuery)q).clauses().get(0).getQuery(); |
| if (qq instanceof TermQuery) { |
| qq = ((BooleanQuery)q).clauses().get(1).getQuery(); |
| } |
| |
| if (qq instanceof FilterQuery) { |
| qq = ((FilterQuery)qq).getQuery(); |
| } |
| |
| assertEquals(26, ((TermInSetQuery) qq).getTermData().size()); |
| |
| // test mixed boolean query, including quotes (which shouldn't matter) |
| qParser = QParser.getParser("foo_s:(a +aaa b -bbb c d e f bar_s:(qqq www) g h i j k l m n o p q r s t u v w x y z)", req); |
| qParser.setIsFilter(true); // this may change in the future |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals(4, ((BooleanQuery)q).clauses().size()); |
| qq = null; |
| for (BooleanClause clause : ((BooleanQuery)q).clauses()) { |
| qq = clause.getQuery(); |
| if (qq instanceof TermInSetQuery) break; |
| } |
| assertEquals(26, ((TermInSetQuery)qq).getTermData().size()); |
| |
| // test terms queries of two different fields (LUCENE-7637 changed to require all terms be in the same field) |
| StringBuilder sb = new StringBuilder(); |
| for (int i=0; i<17; i++) { |
| char letter = (char)('a'+i); |
| sb.append("foo_s:" + letter + " bar_s:" + letter + " "); |
| } |
| qParser = QParser.getParser(sb.toString(), req); |
| qParser.setIsFilter(true); // this may change in the future |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals(2, ((BooleanQuery)q).clauses().size()); |
| for (BooleanClause clause : ((BooleanQuery)q).clauses()) { |
| qq = clause.getQuery(); |
| assertEquals(17, ((TermInSetQuery)qq).getTermData().size()); |
| } |
| } |
| req.close(); |
| } |
| |
| @Test |
| public void testManyClauses_Solr() throws Exception { |
| final String a = "1 a 2 b 3 c 10 d 11 12 "; // 10 terms |
| |
| // this should exceed our solrconfig.xml level (solr specific) maxBooleanClauses limit |
| // even though it's not long enough to trip the Lucene level (global) limit |
| final String too_long = "id:(" + a + a + a + a + a + ")"; |
| |
| final String expectedMsg = "Too many clauses"; |
| ignoreException(expectedMsg); |
| SolrException e; |
| SolrQueryRequest req = req("q", too_long); |
| e = SolrTestCaseUtil.expectThrows(SolrException.class, "expected SolrException", () -> assertJQ(req, "/response/numFound==6")); |
| |
| assertThat(e.getMessage(), containsString(expectedMsg)); |
| |
| // but should still work as a filter query since TermsQuery can be used... |
| assertJQ(req("q", "*:*", "fq", too_long), "/response/numFound==6"); |
| assertJQ(req("q", "*:*", "fq", too_long, "sow", "false"), "/response/numFound==6"); |
| assertJQ(req("q", "*:*", "fq", too_long, "sow", "true"), "/response/numFound==6"); |
| } |
| |
| @Test |
| public void testManyClauses_Lucene() throws Exception { |
| final int numZ = IndexSearcher.getMaxClauseCount(); |
| |
| final String a = "1 a 2 b 3 c 10 d 11 12 "; // 10 terms |
| final StringBuilder sb = new StringBuilder("id:("); |
| for (int i = 0; i < numZ; i++) { |
| sb.append('z').append(i).append(' '); |
| } |
| sb.append(a); |
| sb.append(")"); |
| |
| // this should trip the lucene level global BooleanQuery.getMaxClauseCount() limit, |
| // causing a parsing error, before Solr even get's a chance to enforce it's lower level limit |
| final String way_too_long = sb.toString(); |
| |
| final String expectedMsg = "too many boolean clauses"; |
| ignoreException(expectedMsg); |
| SolrException e = SolrTestCaseUtil.expectThrows(SolrException.class, "expected SolrException", () -> assertJQ(req("q", way_too_long), "/response/numFound==6")); |
| assertThat(e.getMessage(), containsString(expectedMsg)); |
| |
| assertNotNull(e.getCause()); |
| assertEquals(SyntaxError.class, e.getCause().getClass()); |
| |
| assertNotNull(e.getCause().getCause()); |
| assertEquals(IndexSearcher.TooManyClauses.class, e.getCause().getCause().getClass()); |
| |
| // but should still work as a filter query since TermsQuery can be used... |
| assertJQ(req("q","*:*", "fq", way_too_long) |
| ,"/response/numFound==6"); |
| assertJQ(req("q","*:*", "fq", way_too_long, "sow", "false") |
| ,"/response/numFound==6"); |
| assertJQ(req("q","*:*", "fq", way_too_long, "sow", "true") |
| ,"/response/numFound==6"); |
| } |
| |
| @Test |
| public void testComments() throws Exception { |
| assertJQ(req("q", "id:1 id:2 /* *:* */ id:3") |
| , "/response/numFound==3" |
| ); |
| |
| // |
| assertJQ(req("q", "id:1 /**.*/") |
| , "/response/numFound==1" // if it matches more than one, it's being treated as a regex. |
| ); |
| |
| |
| // don't match comment start in string |
| assertJQ(req("q", " \"/*\" id:1 id:2 \"*/\" id:3") |
| , "/response/numFound==3" |
| ); |
| |
| // don't match an end of comment within a string |
| // assertJQ(req("q","id:1 id:2 /* \"*/\" *:* */ id:3") |
| // ,"/response/numFound==3" |
| // ); |
| // removed this functionality - there's more of a danger to thinking we're in a string. |
| // can't do it */ ......... ' |
| |
| // nested comments |
| assertJQ(req("q", "id:1 /* id:2 /* */ /* /**/ id:3 */ id:10 */ id:11") |
| , "/response/numFound==2" |
| ); |
| |
| } |
| |
| @Test |
| public void testFilter() throws Exception { |
| |
| // normal test "solrconfig.xml" has autowarm set to 2... |
| for (int i = 0; i < 10; i++) { |
| assertJQ(req("q", "*:* " + i, "fq", "filter(just_to_clear_the_cache) filter(id:10000" + i + ") filter(id:10001" + i + ")") |
| , "/response/numFound==0" |
| ); |
| } |
| assertU(adoc("id", "777")); |
| delI("777"); |
| assertU(commit()); // arg... commit no longer "commits" unless there has been a change. |
| Gauge filterCacheStats; |
| try (SolrCore core = h.getCore()) { |
| filterCacheStats = (Gauge) core.getCoreMetricManager().getRegistry().getMetrics().get("CACHE.searcher.filterCache"); |
| if (filterCacheStats == null) { |
| Thread.sleep(250); |
| filterCacheStats = (Gauge) core.getCoreMetricManager().getRegistry().getMetrics().get("CACHE.searcher.filterCache"); |
| if (filterCacheStats == null) { |
| Thread.sleep(250); |
| filterCacheStats = (Gauge) core.getCoreMetricManager().getRegistry().getMetrics().get("CACHE.searcher.filterCache"); |
| } |
| } |
| assertNotNull(filterCacheStats); |
| final Gauge queryCacheStats = (Gauge) core.getCoreMetricManager().getRegistry().getMetrics().get("CACHE.searcher.queryResultCache"); |
| |
| assertNotNull(queryCacheStats); |
| } |
| |
| |
| long inserts = (Long) ((Map) filterCacheStats.getValue()).get("inserts"); |
| long hits = (Long) ((Map) filterCacheStats.getValue()).get("hits"); |
| |
| assertJQ(req("q", "doesnotexist filter(id:1) filter(qqq_s:X) filter(abcdefg)") |
| , "/response/numFound==2" |
| ); |
| |
| inserts += 3; |
| assertEquals(inserts, ((Long) ((Map) filterCacheStats.getValue()).get("inserts")).longValue()); |
| assertEquals(hits, ((Long) ((Map) filterCacheStats.getValue()).get("hits")).longValue()); |
| |
| assertJQ(req("q", "doesnotexist2 filter(id:1) filter(qqq_s:X) filter(abcdefg)") |
| , "/response/numFound==2" |
| ); |
| |
| hits += 3; |
| assertEquals(inserts, ((Long) ((Map) filterCacheStats.getValue()).get("inserts")).longValue()); |
| assertEquals(hits, ((Long) ((Map) filterCacheStats.getValue()).get("hits")).longValue()); |
| |
| // make sure normal "fq" parameters also hit the cache the same way |
| assertJQ(req("q", "doesnotexist3", "fq", "id:1", "fq", "qqq_s:X", "fq", "abcdefg") |
| , "/response/numFound==0" |
| ); |
| |
| hits += 3; |
| assertEquals(inserts, ((Long) ((Map) filterCacheStats.getValue()).get("inserts")).longValue()); |
| assertEquals(hits, ((Long) ((Map) filterCacheStats.getValue()).get("hits")).longValue()); |
| |
| // try a query deeply nested in a FQ |
| assertJQ(req("q", "*:* doesnotexist4", "fq", "(id:* +(filter(id:1) filter(qqq_s:X) filter(abcdefg)) )") |
| , "/response/numFound==2" |
| ); |
| |
| inserts += 1; // +1 for top level fq |
| hits += 3; |
| assertEquals(inserts, ((Long) ((Map) filterCacheStats.getValue()).get("inserts")).longValue()); |
| assertEquals(hits, ((Long) ((Map) filterCacheStats.getValue()).get("hits")).longValue()); |
| |
| // retry the complex FQ and make sure hashCode/equals works as expected w/ filter queries |
| assertJQ(req("q", "*:* doesnotexist5", "fq", "(id:* +(filter(id:1) filter(qqq_s:X) filter(abcdefg)) )") |
| , "/response/numFound==2" |
| ); |
| |
| hits += 1; // top-level fq should have been found. |
| assertEquals(inserts, ((Long) ((Map) filterCacheStats.getValue()).get("inserts")).longValue()); |
| assertEquals(hits, ((Long) ((Map) filterCacheStats.getValue()).get("hits")).longValue()); |
| |
| |
| // try nested filter with multiple top-level args (i.e. a boolean query) |
| assertJQ(req("q", "*:* +filter(id:1 filter(qqq_s:X) abcdefg)") |
| , "/response/numFound==2" |
| ); |
| |
| hits += 1; // the inner filter |
| inserts += 1; // the outer filter |
| assertEquals(inserts, ((Long) ((Map) filterCacheStats.getValue()).get("inserts")).longValue()); |
| assertEquals(hits, ((Long) ((Map) filterCacheStats.getValue()).get("hits")).longValue()); |
| |
| // test the score for a filter, and that default score is 0 |
| assertJQ(req("q", "+filter(*:*) +filter(id:1)", "fl", "id,score", "sort", "id asc") |
| , "/response/docs/[0]/score==0.0" |
| ); |
| |
| assertJQ(req("q", "+filter(*:*)^=10 +filter(id:1)", "fl", "id,score", "sort", "id asc") |
| , "/response/docs/[0]/score==10.0" |
| ); |
| |
| assertU(adoc("id", "40", "wdf_nocase", "just some text, don't want NPE")); |
| assertU(commit()); |
| |
| // See SOLR-11555. If wdff removes all the characters, an NPE occurs. |
| // try q and fq |
| assertJQ(req("q", "filter(wdf_nocase:&)", "fl", "id", "debug", "query") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("fq", "filter(wdf_nocase:.,)", "fl", "id", "debug", "query") |
| , "/response/numFound==0" |
| ); |
| |
| // Insure the same behavior as with bare clause, just not filter |
| assertJQ(req("q", "wdf_nocase:&", "fl", "id", "debug", "query") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("fq", "wdf_nocase:.,", "fl", "id", "debug", "query") |
| , "/response/numFound==0" |
| ); |
| |
| } |
| |
| |
| @Test |
| public void testRegex() throws Exception { |
| // leading slash in a regex fixed by SOLR-8605 |
| assertJQ(req("q", "rrr_s:/\\/lead.*/", "fl","id") |
| , "/response/docs==[{id:'13'}]" |
| ); |
| |
| } |
| |
| // parsing performance test |
| // Run from command line with ant test -Dtestcase=TestSolrQueryParser -Dtestmethod=testParsingPerformance -Dtests.asserts=false 2>/dev/null | grep QPS |
| @Test |
| public void testParsingPerformance() throws Exception { |
| String[] args = {"-queries","100" ,"-iter","1000", "-clauses","100", "-format","term%d", "-seed","0"}; |
| args = new String[] {"-queries","1000" ,"-iter","2000", "-clauses","10", "-format","term%d", "-seed","0"}; |
| // args = new String[] {"-queries","1000" ,"-iter","1000000000", "-clauses","10", "-format","term%d", "-seed","0"}; |
| |
| boolean assertOn = false; |
| assert assertOn = true; |
| if (assertOn) { |
| // System.out.println("WARNING! Assertions are enabled!!!! Will only execute small run. Change with -Dtests.asserts=false"); |
| args = new String[]{"-queries","10" ,"-iter","2", "-clauses","20", "-format","term%d", "-seed","0"}; |
| } |
| |
| |
| int iter = 1000; |
| int numQueries = 100; |
| int maxClauses = 5; |
| int maxTerm = 10000000; |
| String format = "term%d"; |
| String field = "foo_s"; |
| long seed = 0; |
| boolean isFilter = true; |
| boolean rewrite = false; |
| |
| String otherStuff = ""; |
| |
| for (int i = 0; i < args.length; i++) { |
| String a = args[i]; |
| if ("-queries".equals(a)) { |
| numQueries = Integer.parseInt(args[++i]); |
| } else if ("-iter".equals(a)) { |
| iter = Integer.parseInt(args[++i]); |
| } else if ("-clauses".equals(a)) { |
| maxClauses = Integer.parseInt(args[++i]); |
| } else if ("-format".equals(a)) { |
| format = args[++i]; |
| } else if ("-seed".equals(a)) { |
| seed = Long.parseLong(args[++i]); |
| } else { |
| otherStuff = otherStuff + " " + a; |
| } |
| } |
| |
| Random r = new Random(seed); |
| |
| String[] queries = new String[numQueries]; |
| for (int i = 0; i < queries.length; i++) { |
| StringBuilder sb = new StringBuilder(); |
| boolean explicitField = r.nextInt(5) == 0; |
| if (!explicitField) { |
| sb.append(field + ":("); |
| } |
| |
| sb.append(otherStuff).append(" "); |
| |
| int nClauses = r.nextInt(maxClauses) + 1; // TODO: query parse can't parse () for some reason??? |
| |
| for (int c = 0; c<nClauses; c++) { |
| String termString = String.format(Locale.US, format, r.nextInt(maxTerm)); |
| if (explicitField) { |
| sb.append(field).append(':'); |
| } |
| sb.append(termString); |
| sb.append(' '); |
| } |
| |
| if (!explicitField) { |
| sb.append(")"); |
| } |
| queries[i] = sb.toString(); |
| // System.out.println(queries[i]); |
| } |
| |
| SolrQueryRequest req = req(); |
| |
| long start = System.nanoTime(); |
| |
| int ret = 0; |
| for (int i=0; i<iter; i++) { |
| for (String qStr : queries) { |
| QParser parser = QParser.getParser(qStr,req); |
| parser.setIsFilter(isFilter); |
| Query q = parser.getQuery(); |
| if (rewrite) { |
| // TODO: do rewrite |
| } |
| ret += q.getClass().hashCode(); // use the query somehow |
| } |
| } |
| |
| long end = System.nanoTime(); |
| |
| //System.out.println((assertOn ? "WARNING, assertions enabled. " : "") + "ret=" + ret + " Parser QPS:" + ((long)numQueries * iter)*1000000000/(end-start)); |
| |
| req.close(); |
| } |
| |
| @Test |
| public void testSplitOnWhitespace_Basic() throws Exception { |
| // The "syn" field has synonyms loaded from synonyms.txt |
| |
| assertJQ(req("df", "syn", "q", "wifi", "sow", "true") // retrieve the single document containing literal "wifi" |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "wi fi", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "wi fi", "sow", "true") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi fi") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi fi") |
| , "/response/numFound==0" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "{!lucene}wi fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| } |
| |
| public void testSplitOnWhitespace_Comments() throws Exception { |
| // The "syn" field has synonyms loaded from synonyms.txt |
| |
| assertJQ(req("df", "syn", "q", "wifi", "sow", "true") // retrieve the single document containing literal "wifi" |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /* foo */ fi", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /* foo */ /* bar */ fi", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", " /* foo */ wi fi /* bar */", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", " /* foo */ wi /* bar */ fi /* baz */", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "wi fi", "sow", "true") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /* foo */ fi", "sow", "true") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /* foo */ /* bar */ fi", "sow", "true") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "/* foo */ wi fi /* bar */", "sow", "true") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "/* foo */ wi /* bar */ fi /* baz */", "sow", "true") |
| , "/response/numFound==0" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "wi fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /* foo */ fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /* foo */ /* bar */ fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", " /* foo */ wi fi /* bar */") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", " /* foo */ wi /* bar */ fi /* baz */") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| |
| assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi fi") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi /* foo */ fi") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=false}wi /* foo */ /* bar */ fi") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=false}/* foo */ wi fi /* bar */") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=false}/* foo */ wi /* bar */ fi /* baz */") |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi fi") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi /* foo */ fi") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=true}wi /* foo */ /* bar */ fi") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=true}/* foo */ wi fi /* bar */") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene sow=true}/* foo */ wi /* bar */ fi /* baz */") |
| , "/response/numFound==0" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "{!lucene}wi fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene}wi /* foo */ fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene}wi /* foo */ /* bar */ fi") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene}/* foo */ wi fi /* bar */") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "{!lucene}/* foo */ wi /* bar */ fi /* baz */") // default sow=false |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| } |
| |
| public void testOperatorsAndMultiWordSynonyms() throws Exception { |
| // The "syn" field has synonyms loaded from synonyms.txt |
| |
| assertJQ(req("df", "syn", "q", "wifi", "sow", "true") // retrieve the single document containing literal "wifi" |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi", "sow", "false") // trigger the "wi fi => wifi" synonym |
| , "/response/numFound==1" |
| , "/response/docs/[0]/id=='20'" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "+wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "-wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "!wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi* fi", "sow", "false") // matches because wi* matches wifi |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "w? fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi~1 fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi^2 fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi^=2 fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi +fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi -fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi !fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi*", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi?", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi~1", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi^2", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi^=2", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "syn:wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi syn:fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "NOT wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi NOT fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "wi fi AND ATM", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "ATM AND wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi && ATM", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "ATM && wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "(wi fi) AND ATM", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "ATM AND (wi fi)", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "(wi fi) && ATM", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "ATM && (wi fi)", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "wi fi OR NotThereAtAll", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "NotThereAtAll OR wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi fi || NotThereAtAll", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "NotThereAtAll || wi fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "(wi fi) OR NotThereAtAll", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "NotThereAtAll OR (wi fi)", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "(wi fi) || NotThereAtAll", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "NotThereAtAll || (wi fi)", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| |
| assertJQ(req("df", "syn", "q", "\"wi\" fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi \"fi\"", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "(wi) fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi (fi)", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "/wi/ fi", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "wi /fi/", "sow", "false") |
| , "/response/numFound==0" |
| ); |
| assertJQ(req("df", "syn", "q", "(wi fi)", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| assertJQ(req("df", "syn", "q", "+(wi fi)", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| try (SolrQueryRequest req = req("q", "*:*", "rows", "0", "wt", "json")) { |
| Map all = (Map) Utils.fromJSONString(h.query(req)); |
| int totalDocs = Integer.parseInt(((Map) all.get("response")).get("numFound").toString()); |
| int allDocsExceptOne = totalDocs - 1; |
| |
| assertJQ(req("df", "syn", "q", "-(wi fi)", "sow", "false"), "/response/numFound==" + allDocsExceptOne // one doc contains "wifi" in the syn field |
| ); |
| assertJQ(req("df", "syn", "q", "!(wi fi)", "sow", "false"), "/response/numFound==" + allDocsExceptOne // one doc contains "wifi" in the syn field |
| ); |
| assertJQ(req("df", "syn", "q", "NOT (wi fi)", "sow", "false"), "/response/numFound==" + allDocsExceptOne // one doc contains "wifi" in the syn field |
| ); |
| assertJQ(req("df", "syn", "q", "(wi fi)^2", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "(wi fi)^=2", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "syn:(wi fi)", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "+ATM wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "-ATM wi fi", "sow", "false"), "/response/numFound==0"); |
| assertJQ(req("df", "syn", "q", "-NotThereAtAll wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "!ATM wi fi", "sow", "false"), "/response/numFound==0"); |
| assertJQ(req("df", "syn", "q", "!NotThereAtAll wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "NOT ATM wi fi", "sow", "false"), "/response/numFound==0"); |
| assertJQ(req("df", "syn", "q", "NOT NotThereAtAll wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "AT* wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "AT? wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "\"ATM\" wi fi", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi +ATM", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi -ATM", "sow", "false"), "/response/numFound==0"); |
| assertJQ(req("df", "syn", "q", "wi fi -NotThereAtAll", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi !ATM", "sow", "false"), "/response/numFound==0"); |
| assertJQ(req("df", "syn", "q", "wi fi !NotThereAtAll", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi NOT ATM", "sow", "false"), "/response/numFound==0"); |
| assertJQ(req("df", "syn", "q", "wi fi NOT NotThereAtAll", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi AT*", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi AT?", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "wi fi \"ATM\"", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "\"wi fi\"~2", "sow", "false"), "/response/numFound==1"); |
| assertJQ(req("df", "syn", "q", "syn:\"wi fi\"", "sow", "false"), "/response/numFound==1"); |
| } |
| } |
| |
| @Test |
| public void testAutoGeneratePhraseQueries() throws Exception { |
| ModifiableSolrParams noSowParams = new ModifiableSolrParams(); |
| ModifiableSolrParams sowFalseParams = new ModifiableSolrParams(); |
| sowFalseParams.add("sow", "false"); |
| ModifiableSolrParams sowTrueParams = new ModifiableSolrParams(); |
| sowTrueParams.add("sow", "true"); |
| |
| // From synonyms.txt: |
| // |
| // crow blackbird, grackle |
| // |
| try (SolrQueryRequest req = req()) { |
| |
| for (SolrParams params : Arrays.asList(noSowParams, sowFalseParams)) { |
| QParser qParser = QParser.getParser("text:grackle", req); // "text" has autoGeneratePhraseQueries="true" |
| qParser.setParams(sowFalseParams); |
| Query q = qParser.getQuery(); |
| assertEquals("(text:\"crow blackbird\" text:grackl)", q.toString()); |
| } |
| |
| QParser qParser = QParser.getParser("text:grackle", req); |
| qParser.setParams(sowTrueParams); |
| Query q = qParser.getQuery(); |
| assertEquals("text:\"crow blackbird\" text:grackl", q.toString()); |
| |
| for (SolrParams params : Arrays.asList(noSowParams, sowTrueParams, sowFalseParams)) { |
| qParser = QParser.getParser("text_sw:grackle", req); // "text_sw" doesn't specify autoGeneratePhraseQueries => default false |
| qParser.setParams(params); |
| q = qParser.getQuery(); |
| assertEquals("((+text_sw:crow +text_sw:blackbird) text_sw:grackl)", q.toString()); |
| } |
| } |
| } |
| |
| @Test |
| public void testShingleQueries() throws Exception { |
| ModifiableSolrParams sowFalseParams = new ModifiableSolrParams(); |
| sowFalseParams.add("sow", "false"); |
| |
| try (SolrQueryRequest req = req(sowFalseParams)) { |
| QParser qParser = QParser.getParser("shingle23:(A B C)", req); |
| Query q = qParser.getQuery(); |
| assertEquals("Synonym(shingle23:A_B shingle23:A_B_C) shingle23:B_C", q.toString()); |
| } |
| |
| assertJQ(req("df", "shingle23", "q", "A B C", "sow", "false") |
| , "/response/numFound==1" |
| ); |
| } |
| |
| |
| public void testSynonymQueryStyle() throws Exception { |
| Query q; |
| try (SolrQueryRequest req = req(params("df", "t_pick_best_foo"))) { |
| q = QParser.getParser("tabby", req).getQuery(); |
| assertEquals("(t_pick_best_foo:tabbi | t_pick_best_foo:cat | t_pick_best_foo:felin | t_pick_best_foo:anim)", q.toString()); |
| } |
| |
| try (SolrQueryRequest req = req(params("df", "t_as_distinct_foo"))) { |
| q = QParser.getParser("tabby", req).getQuery(); |
| assertEquals("t_as_distinct_foo:tabbi t_as_distinct_foo:cat t_as_distinct_foo:felin t_as_distinct_foo:anim", q.toString()); |
| } |
| /*confirm autoGeneratePhraseQueries always builds OR queries*/ |
| try (SolrQueryRequest req = req(params("df", "t_as_distinct_foo", "sow", "false"))) { |
| q = QParser.getParser("jeans", req).getQuery(); |
| assertEquals("(t_as_distinct_foo:\"denim pant\" t_as_distinct_foo:jean)", q.toString()); |
| } |
| try (SolrQueryRequest req = req(params("df", "t_pick_best_foo", "sow", "false"))) { |
| q = QParser.getParser("jeans", req).getQuery(); |
| assertEquals("(t_pick_best_foo:\"denim pant\" | t_pick_best_foo:jean)", q.toString()); |
| } |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_singleTermQuerySingleTermSynonyms_shouldParseBoostedQuery() throws Exception { |
| //tiger, tigre|0.9 |
| Query q = QParser.getParser("tiger", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:tigre)^0.9 | t_pick_best_boosted_foo:tiger)", q.toString()); |
| |
| q = QParser.getParser("tiger", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("(t_as_distinct_boosted_foo:tigre)^0.9 t_as_distinct_boosted_foo:tiger", q.toString()); |
| |
| q = QParser.getParser("tiger", req(params("df", "t_as_same_term_boosted_foo"))).getQuery(); |
| assertEquals("Synonym(t_as_same_term_boosted_foo:tiger t_as_same_term_boosted_foo:tigre^0.9)", q.toString()); |
| |
| //lynx => lince|0.8, lynx_canadensis|0.9 |
| q = QParser.getParser("lynx", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:lince)^0.8 | (t_pick_best_boosted_foo:lynx_canadensis)^0.9)", q.toString()); |
| |
| q = QParser.getParser("lynx", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("(t_as_distinct_boosted_foo:lince)^0.8 (t_as_distinct_boosted_foo:lynx_canadensis)^0.9", q.toString()); |
| |
| q = QParser.getParser("lynx", req(params("df", "t_as_same_term_boosted_foo"))).getQuery(); |
| assertEquals("Synonym(t_as_same_term_boosted_foo:lince^0.8 t_as_same_term_boosted_foo:lynx_canadensis^0.9)", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_singleTermQueryMultiTermSynonyms_shouldParseBoostedQuery() throws Exception { |
| //leopard, big cat|0.8, bagheera|0.9, panthera pardus|0.85 |
| Query q = QParser.getParser("leopard", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"big cat\")^0.8 | (t_pick_best_boosted_foo:bagheera)^0.9 | (t_pick_best_boosted_foo:\"panthera pardus\")^0.85 | t_pick_best_boosted_foo:leopard)", q.toString()); |
| |
| q = QParser.getParser("leopard", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"big cat\")^0.8 (t_as_distinct_boosted_foo:bagheera)^0.9 (t_as_distinct_boosted_foo:\"panthera pardus\")^0.85 t_as_distinct_boosted_foo:leopard)", q.toString()); |
| |
| q = QParser.getParser("leopard", req(params("df", "t_as_same_term_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:\"big cat\")^0.8 (t_as_same_term_boosted_foo:bagheera)^0.9 (t_as_same_term_boosted_foo:\"panthera pardus\")^0.85 t_as_same_term_boosted_foo:leopard)", q.toString()); |
| |
| //lion => panthera leo|0.9, simba leo|0.8, kimba|0.75 |
| q = QParser.getParser("lion", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"panthera leo\")^0.9 | (t_pick_best_boosted_foo:\"simba leo\")^0.8 | (t_pick_best_boosted_foo:kimba)^0.75)", q.toString()); |
| |
| q = QParser.getParser("lion", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"panthera leo\")^0.9 (t_as_distinct_boosted_foo:\"simba leo\")^0.8 (t_as_distinct_boosted_foo:kimba)^0.75)", q.toString()); |
| |
| q = QParser.getParser("lion", req(params("df", "t_as_same_term_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:\"panthera leo\")^0.9 (t_as_same_term_boosted_foo:\"simba leo\")^0.8 (t_as_same_term_boosted_foo:kimba)^0.75)", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_multiTermQuerySingleTermSynonyms_shouldParseBoostedQuery() throws Exception { |
| //tiger, tigre|0.9 |
| //lynx => lince|0.8, lynx_canadensis|0.9 |
| Query q = QParser.getParser("tiger lynx", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:tigre)^0.9 | t_pick_best_boosted_foo:tiger)" + |
| " ((t_pick_best_boosted_foo:lince)^0.8 | (t_pick_best_boosted_foo:lynx_canadensis)^0.9)", q.toString()); |
| |
| q = QParser.getParser("tiger lynx", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:tigre)^0.9 t_as_distinct_boosted_foo:tiger)" + |
| " ((t_as_distinct_boosted_foo:lince)^0.8 (t_as_distinct_boosted_foo:lynx_canadensis)^0.9)", q.toString()); |
| |
| q = QParser.getParser("tiger lynx", req(params("df", "t_as_same_term_boosted_foo"))).getQuery(); |
| assertEquals("Synonym(t_as_same_term_boosted_foo:tiger t_as_same_term_boosted_foo:tigre^0.9)" + |
| " Synonym(t_as_same_term_boosted_foo:lince^0.8 t_as_same_term_boosted_foo:lynx_canadensis^0.9)", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_multiTermQueryMultiTermSynonyms_shouldParseBoostedQuery() throws Exception { |
| //leopard, big cat|0.8, bagheera|0.9, panthera pardus|0.85 |
| //lion => panthera leo|0.9, simba leo|0.8, kimba|0.75 |
| Query q = QParser.getParser("leopard lion", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"big cat\")^0.8 | (t_pick_best_boosted_foo:bagheera)^0.9 | (t_pick_best_boosted_foo:\"panthera pardus\")^0.85 | t_pick_best_boosted_foo:leopard)" + |
| " ((t_pick_best_boosted_foo:\"panthera leo\")^0.9 | (t_pick_best_boosted_foo:\"simba leo\")^0.8 | (t_pick_best_boosted_foo:kimba)^0.75)", q.toString()); |
| |
| q = QParser.getParser("leopard lion", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"big cat\")^0.8 (t_as_distinct_boosted_foo:bagheera)^0.9 (t_as_distinct_boosted_foo:\"panthera pardus\")^0.85 t_as_distinct_boosted_foo:leopard)" + |
| " ((t_as_distinct_boosted_foo:\"panthera leo\")^0.9 (t_as_distinct_boosted_foo:\"simba leo\")^0.8 (t_as_distinct_boosted_foo:kimba)^0.75)", q.toString()); |
| |
| q = QParser.getParser("leopard lion", req(params("df", "t_as_same_term_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:\"big cat\")^0.8 (t_as_same_term_boosted_foo:bagheera)^0.9 (t_as_same_term_boosted_foo:\"panthera pardus\")^0.85 t_as_same_term_boosted_foo:leopard)" + |
| " ((t_as_same_term_boosted_foo:\"panthera leo\")^0.9 (t_as_same_term_boosted_foo:\"simba leo\")^0.8 (t_as_same_term_boosted_foo:kimba)^0.75)", q.toString()); |
| |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_singleConceptQuerySingleTermSynonym_shouldParseBoostedQuery() throws Exception { |
| //panthera pardus, leopard|0.6 |
| Query q = QParser.getParser("panthera pardus story",req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:leopard)^0.6 | t_pick_best_boosted_foo:\"panthera pardus\") t_pick_best_boosted_foo:story", q.toString()); |
| |
| q = QParser.getParser("panthera pardus story", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:leopard)^0.6 t_as_distinct_boosted_foo:\"panthera pardus\") t_as_distinct_boosted_foo:story", q.toString()); |
| |
| q = QParser.getParser("panthera pardus story", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:leopard)^0.6 t_as_same_term_boosted_foo:\"panthera pardus\") t_as_same_term_boosted_foo:story", q.toString()); |
| |
| //panthera tigris => tiger|0.99 |
| q = QParser.getParser("panthera tigris story", req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("(t_pick_best_boosted_foo:tiger)^0.99 t_pick_best_boosted_foo:story", q.toString()); |
| |
| q = QParser.getParser("panthera tigris story", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("(t_as_distinct_boosted_foo:tiger)^0.99 t_as_distinct_boosted_foo:story", q.toString()); |
| |
| q = QParser.getParser("panthera tigris story", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("(t_as_same_term_boosted_foo:tiger)^0.99 t_as_same_term_boosted_foo:story", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_singleConceptQueryMultiTermSynonymWithMultipleBoost_shouldParseMultiplicativeBoostedQuery() throws Exception { |
| //panthera blytheae, oldest|0.5 ancient|0.9 panthera |
| Query q = QParser.getParser("panthera blytheae",req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"oldest ancient panthera\")^0.45 | t_pick_best_boosted_foo:\"panthera blytheae\")", q.toString()); |
| |
| q = QParser.getParser("panthera blytheae", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"oldest ancient panthera\")^0.45 t_as_distinct_boosted_foo:\"panthera blytheae\")", q.toString()); |
| |
| q = QParser.getParser("panthera blytheae", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:\"oldest ancient panthera\")^0.45 t_as_same_term_boosted_foo:\"panthera blytheae\")", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_singleConceptQueryMultiTermSynonyms_shouldParseBoostedQuery() throws Exception { |
| //snow leopard, panthera uncia|0.9, big cat|0.8, white_leopard|0.6 |
| Query q = QParser.getParser("snow leopard",req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"panthera uncia\")^0.9 | (t_pick_best_boosted_foo:\"big cat\")^0.8 | (t_pick_best_boosted_foo:white_leopard)^0.6 | t_pick_best_boosted_foo:\"snow leopard\")", q.toString()); |
| |
| q = QParser.getParser("snow leopard", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"panthera uncia\")^0.9 (t_as_distinct_boosted_foo:\"big cat\")^0.8 (t_as_distinct_boosted_foo:white_leopard)^0.6 t_as_distinct_boosted_foo:\"snow leopard\")", q.toString()); |
| |
| q = QParser.getParser("snow leopard", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:\"panthera uncia\")^0.9 (t_as_same_term_boosted_foo:\"big cat\")^0.8 (t_as_same_term_boosted_foo:white_leopard)^0.6 t_as_same_term_boosted_foo:\"snow leopard\")", q.toString()); |
| |
| //panthera onca => jaguar|0.95, big cat|0.85, black panther|0.65 |
| q = QParser.getParser("panthera onca", req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:jaguar)^0.95 | (t_pick_best_boosted_foo:\"big cat\")^0.85 | (t_pick_best_boosted_foo:\"black panther\")^0.65)", q.toString()); |
| |
| q = QParser.getParser("panthera onca", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:jaguar)^0.95 (t_as_distinct_boosted_foo:\"big cat\")^0.85 (t_as_distinct_boosted_foo:\"black panther\")^0.65)", q.toString()); |
| |
| q = QParser.getParser("panthera onca", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:jaguar)^0.95 (t_as_same_term_boosted_foo:\"big cat\")^0.85 (t_as_same_term_boosted_foo:\"black panther\")^0.65)", q.toString()); |
| |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_multiConceptQuerySingleTermSynonym_shouldParseBoostedQuery() throws Exception { |
| //panthera pardus, leopard|0.6 |
| //tiger, tigre|0.9 |
| Query q = QParser.getParser("panthera pardus tiger",req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:leopard)^0.6 | t_pick_best_boosted_foo:\"panthera pardus\") ((t_pick_best_boosted_foo:tigre)^0.9 | t_pick_best_boosted_foo:tiger)", q.toString()); |
| |
| q = QParser.getParser("panthera pardus tiger", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:leopard)^0.6 t_as_distinct_boosted_foo:\"panthera pardus\") ((t_as_distinct_boosted_foo:tigre)^0.9 t_as_distinct_boosted_foo:tiger)", q.toString()); |
| |
| q = QParser.getParser("panthera pardus tiger", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:leopard)^0.6 t_as_same_term_boosted_foo:\"panthera pardus\") Synonym(t_as_same_term_boosted_foo:tiger t_as_same_term_boosted_foo:tigre^0.9)", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_multiConceptsQueryMultiTermSynonyms_shouldParseBoostedQuery() throws Exception { |
| //snow leopard, panthera uncia|0.9, big cat|0.8, white_leopard|0.6 |
| //panthera onca => jaguar|0.95, big cat|0.85, black panther|0.65 |
| Query q = QParser.getParser("snow leopard panthera onca",req(params("df", "t_pick_best_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"panthera uncia\")^0.9 | (t_pick_best_boosted_foo:\"big cat\")^0.8 | (t_pick_best_boosted_foo:white_leopard)^0.6 | t_pick_best_boosted_foo:\"snow leopard\")" + |
| " ((t_pick_best_boosted_foo:jaguar)^0.95 | (t_pick_best_boosted_foo:\"big cat\")^0.85 | (t_pick_best_boosted_foo:\"black panther\")^0.65)", q.toString()); |
| |
| q = QParser.getParser("snow leopard panthera onca", req(params("df", "t_as_distinct_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"panthera uncia\")^0.9 (t_as_distinct_boosted_foo:\"big cat\")^0.8 (t_as_distinct_boosted_foo:white_leopard)^0.6 t_as_distinct_boosted_foo:\"snow leopard\")" + |
| " ((t_as_distinct_boosted_foo:jaguar)^0.95 (t_as_distinct_boosted_foo:\"big cat\")^0.85 (t_as_distinct_boosted_foo:\"black panther\")^0.65)", q.toString()); |
| |
| q = QParser.getParser("snow leopard panthera onca", req(params("df", "t_as_same_term_boosted_foo","sow", "false"))).getQuery(); |
| assertEquals("((t_as_same_term_boosted_foo:\"panthera uncia\")^0.9 (t_as_same_term_boosted_foo:\"big cat\")^0.8 (t_as_same_term_boosted_foo:white_leopard)^0.6 t_as_same_term_boosted_foo:\"snow leopard\")" + |
| " ((t_as_same_term_boosted_foo:jaguar)^0.95 (t_as_same_term_boosted_foo:\"big cat\")^0.85 (t_as_same_term_boosted_foo:\"black panther\")^0.65)", q.toString()); |
| |
| } |
| |
| public void testSynonymsBoost_edismaxBoost_shouldParseBoostedPhraseQuery() throws Exception { |
| SolrQueryRequest req = req(params("sow", "false", "qf", "t_pick_best_boosted_foo^10")); |
| Query q = QParser.getParser("snow leopard lion","edismax",true, req).getQuery(); |
| assertEquals("+(" + |
| "((((t_pick_best_boosted_foo:\"panthera uncia\")^0.9 | (t_pick_best_boosted_foo:\"big cat\")^0.8 | (t_pick_best_boosted_foo:white_leopard)^0.6 | t_pick_best_boosted_foo:\"snow leopard\"))^10.0)" + |
| " ((((t_pick_best_boosted_foo:\"panthera leo\")^0.9 | (t_pick_best_boosted_foo:\"simba leo\")^0.8 | (t_pick_best_boosted_foo:kimba)^0.75))^10.0)" + |
| ")", q.toString()); |
| |
| req.close(); |
| req = req(params("sow", "false","qf", "t_as_distinct_boosted_foo^10")); |
| q = QParser.getParser("snow leopard lion","edismax",true, req).getQuery(); |
| assertEquals("+(" + |
| "(((t_as_distinct_boosted_foo:\"panthera uncia\")^0.9 (t_as_distinct_boosted_foo:\"big cat\")^0.8 (t_as_distinct_boosted_foo:white_leopard)^0.6 t_as_distinct_boosted_foo:\"snow leopard\")^10.0)" + |
| " (((t_as_distinct_boosted_foo:\"panthera leo\")^0.9 (t_as_distinct_boosted_foo:\"simba leo\")^0.8 (t_as_distinct_boosted_foo:kimba)^0.75)^10.0))", q.toString()); |
| |
| req.close(); |
| req = req(params("sow", "false","qf", "t_as_same_term_boosted_foo^10")); |
| q = QParser.getParser("snow leopard lion","edismax",true, req).getQuery(); |
| assertEquals("+(" + |
| "(((t_as_same_term_boosted_foo:\"panthera uncia\")^0.9 (t_as_same_term_boosted_foo:\"big cat\")^0.8 (t_as_same_term_boosted_foo:white_leopard)^0.6 t_as_same_term_boosted_foo:\"snow leopard\")^10.0)" + |
| " (((t_as_same_term_boosted_foo:\"panthera leo\")^0.9 (t_as_same_term_boosted_foo:\"simba leo\")^0.8 (t_as_same_term_boosted_foo:kimba)^0.75)^10.0))", q.toString()); |
| req.close(); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_phraseQueryMultiTermSynonymsBoost() throws Exception { |
| Query q = QParser.getParser("\"snow leopard lion\"", req(params("df", "t_pick_best_boosted_foo", "sow", "false"))).getQuery(); |
| assertEquals("(t_pick_best_boosted_foo:\"panthera uncia panthera leo\")^0.80999994 " + |
| "(t_pick_best_boosted_foo:\"panthera uncia simba leo\")^0.71999997 " + |
| "(t_pick_best_boosted_foo:\"panthera uncia kimba\")^0.67499995 " + |
| "(t_pick_best_boosted_foo:\"big cat panthera leo\")^0.71999997 " + |
| "(t_pick_best_boosted_foo:\"big cat simba leo\")^0.64000005 " + |
| "(t_pick_best_boosted_foo:\"big cat kimba\")^0.6 " + |
| "(t_pick_best_boosted_foo:\"white_leopard panthera leo\")^0.54 " + |
| "(t_pick_best_boosted_foo:\"white_leopard simba leo\")^0.48000002 " + |
| "(t_pick_best_boosted_foo:\"white_leopard kimba\")^0.45000002 " + |
| "(t_pick_best_boosted_foo:\"snow leopard panthera leo\")^0.9 " + |
| "(t_pick_best_boosted_foo:\"snow leopard simba leo\")^0.8 " + |
| "(t_pick_best_boosted_foo:\"snow leopard kimba\")^0.75", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_phraseQueryMultiTermSynonymsMultipleBoost() throws Exception { |
| Query q = QParser.getParser("\"panthera blytheae lion\"", req(params("df", "t_pick_best_boosted_foo", "sow", "false"))).getQuery(); |
| assertEquals("(t_pick_best_boosted_foo:\"oldest ancient panthera panthera leo\")^0.40499997 " + |
| "(t_pick_best_boosted_foo:\"oldest ancient panthera simba leo\")^0.35999998 " + |
| "(t_pick_best_boosted_foo:\"oldest ancient panthera kimba\")^0.33749998 " + |
| "(t_pick_best_boosted_foo:\"panthera blytheae panthera leo\")^0.9 " + |
| "(t_pick_best_boosted_foo:\"panthera blytheae simba leo\")^0.8 " + |
| "(t_pick_best_boosted_foo:\"panthera blytheae kimba\")^0.75", q.toString()); |
| } |
| |
| @LuceneTestCase.AwaitsFix(bugUrl = "MRM TODO: - review difference") |
| public void testSynonymsBoost_BoostMissing_shouldAssignDefaultBoost() throws Exception { |
| //leopard, big cat|0.8, bagheera|0.9, panthera pardus|0.85 |
| Query q = QParser.getParser("leopard", req(params("df", "t_pick_best_boosted_foo"))).getQuery(); |
| assertEquals("((t_pick_best_boosted_foo:\"big cat\")^0.8 | (t_pick_best_boosted_foo:bagheera)^0.9 | (t_pick_best_boosted_foo:\"panthera pardus\")^0.85 | t_pick_best_boosted_foo:leopard)", q.toString()); |
| |
| q = QParser.getParser("leopard", req(params("df", "t_as_distinct_boosted_foo"))).getQuery(); |
| assertEquals("((t_as_distinct_boosted_foo:\"big cat\")^0.8 (t_as_distinct_boosted_foo:bagheera)^0.9 (t_as_distinct_boosted_foo:\"panthera pardus\")^0.85 t_as_distinct_boosted_foo:leopard)", q.toString()); |
| } |
| |
| @Test |
| public void testBadRequestInSetQuery() throws SyntaxError { |
| SolrQueryRequest req = req(); |
| QParser qParser; |
| String[] fieldSuffix = new String[] { |
| "ti", "tf", "td", "tl", |
| "i", "f", "d", "l", |
| "is", "fs", "ds", "ls", |
| "i_dv", "f_dv", "d_dv", "l_dv", |
| "is_dv", "fs_dv", "ds_dv", "ls_dv", |
| "i_dvo", "f_dvo", "d_dvo", "l_dvo", |
| }; |
| |
| for (String suffix:fieldSuffix) { |
| //Good queries |
| qParser = QParser.getParser("foo_" + suffix + ":(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 25)", req); |
| qParser.setIsFilter(true); |
| qParser.getQuery(); |
| } |
| req.close(); |
| req = req(); |
| for (String suffix:fieldSuffix) { |
| qParser = QParser.getParser("foo_" + suffix + ":(1 2 3 4 5 6 7 8 9 10 20 19 18 17 16 15 14 13 12 NOT_A_NUMBER)", req); |
| qParser.setIsFilter(true); // this may change in the future |
| SolrException e = SolrTestCaseUtil.expectThrows(SolrException.class, "Expecting exception", qParser::getQuery); |
| assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code()); |
| assertTrue("Unexpected exception: " + e.getMessage(), e.getMessage().contains("Invalid Number: NOT_A_NUMBER")); |
| } |
| |
| req.close(); |
| } |
| |
| @Test |
| public void testFieldExistsQueries() throws SyntaxError { |
| |
| String[] fieldSuffix = new String[] { |
| "ti", "tf", "td", "tl", "tdt", |
| "pi", "pf", "pd", "pl", "pdt", |
| "i", "f", "d", "l", "dt", "s", "b", |
| "is", "fs", "ds", "ls", "dts", "ss", "bs", |
| "i_dv", "f_dv", "d_dv", "l_dv", "dt_dv", "s_dv", "b_dv", |
| "is_dv", "fs_dv", "ds_dv", "ls_dv", "dts_dv", "ss_dv", "bs_dv", |
| "i_dvo", "f_dvo", "d_dvo", "l_dvo", "dt_dvo", |
| "t", |
| "t_on", "b_norms", "s_norms", "dt_norms", "i_norms", "l_norms", "f_norms", "d_norms" |
| }; |
| String[] existenceQueries = new String[] { |
| "*", "[* TO *]" |
| }; |
| |
| for (String existenceQuery : existenceQueries) { |
| for (String suffix : fieldSuffix) { |
| |
| String field = "foo_" + suffix; |
| String query = field + ":" + existenceQuery; |
| SolrQueryRequest req = req(); |
| IndexSchema indexSchema = req.getCore().getLatestSchema(); |
| QParser qParser = QParser.getParser(query, req); |
| req.close(); |
| Query createdQuery = qParser.getQuery(); |
| SchemaField schemaField = indexSchema.getField(field); |
| |
| // Test float & double realNumber queries differently |
| if ("[* TO *]".equals(existenceQuery) && (schemaField.getType().getNumberType() == NumberType.DOUBLE || schemaField.getType().getNumberType() == NumberType.FLOAT)) { |
| assertFalse("For float and double fields \"" + query + "\" is not an existence query, so the query returned should not be a DocValuesFieldExistsQuery.", |
| createdQuery instanceof DocValuesFieldExistsQuery); |
| assertFalse("For float and double fields \"" + query + "\" is not an existence query, so the query returned should not be a NormsFieldExistsQuery.", |
| createdQuery instanceof NormsFieldExistsQuery); |
| assertFalse("For float and double fields \"" + query + "\" is not an existence query, so NaN should not be matched via a ConstantScoreQuery.", createdQuery instanceof ConstantScoreQuery); |
| assertFalse("For float and double fields\"" + query + "\" is not an existence query, so NaN should not be matched via a BooleanQuery (NaN and [* TO *]).", |
| createdQuery instanceof BooleanQuery); |
| } else { |
| if (schemaField.hasDocValues()) { |
| assertTrue("Field has docValues, so existence query \"" + query + "\" should return DocValuesFieldExistsQuery", createdQuery instanceof DocValuesFieldExistsQuery); |
| } else if (!schemaField.omitNorms() && !schemaField.getType().isPointField()) { //TODO: Remove !isPointField() for SOLR-14199 |
| assertTrue("Field has norms and no docValues, so existence query \"" + query + "\" should return NormsFieldExistsQuery", createdQuery instanceof NormsFieldExistsQuery); |
| } else if (schemaField.getType().getNumberType() == NumberType.DOUBLE || schemaField.getType().getNumberType() == NumberType.FLOAT) { |
| assertTrue("PointField with NaN values must include \"exists or NaN\" if the field doesn't have norms or docValues: \"" + query + "\".", createdQuery instanceof ConstantScoreQuery); |
| assertTrue("PointField with NaN values must include \"exists or NaN\" if the field doesn't have norms or docValues: \"" + query + "\".", |
| ((ConstantScoreQuery) createdQuery).getQuery() instanceof BooleanQuery); |
| assertEquals("PointField with NaN values must include \"exists or NaN\" if the field doesn't have norms or docValues: \"" + query + "\". This boolean query must be an OR.", 1, |
| ((BooleanQuery) ((ConstantScoreQuery) createdQuery).getQuery()).getMinimumNumberShouldMatch()); |
| assertEquals("PointField with NaN values must include \"exists or NaN\" if the field doesn't have norms or docValues: \"" + query + "\". This boolean query must have 2 clauses.", 2, |
| ((BooleanQuery) ((ConstantScoreQuery) createdQuery).getQuery()).clauses().size()); |
| } else { |
| assertFalse("Field doesn't have docValues, so existence query \"" + query + "\" should not return DocValuesFieldExistsQuery", createdQuery instanceof DocValuesFieldExistsQuery); |
| assertFalse("Field doesn't have norms, so existence query \"" + query + "\" should not return NormsFieldExistsQuery", createdQuery instanceof NormsFieldExistsQuery); |
| } |
| } |
| |
| } |
| } |
| } |
| } |