mirror of https://github.com/apache/lucene.git
SOLR-14348: split TestJsonFacets to multiple test classes
* TestJsonFacet split into 3 classes, TestsJsonFacets, TestJsonFacetErrors and TestJsonRangeFacet * TestJsonFacets contains mainly terms faceting and stats * range facet covers distributed cases too
This commit is contained in:
parent
aaf08c9c4d
commit
06fd70fc0f
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* 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.facet;
|
||||
|
||||
import org.apache.solr.JSONTestUtil;
|
||||
import org.apache.solr.SolrTestCaseHS;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.core.StringContains.containsString;
|
||||
|
||||
|
||||
public class TestJsonFacetErrors extends SolrTestCaseHS {
|
||||
|
||||
private static SolrInstances servers; // for distributed testing
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@BeforeClass
|
||||
public static void beforeTests() throws Exception {
|
||||
systemSetPropertySolrDisableShardsWhitelist("true");
|
||||
JSONTestUtil.failRepeatedKeys = true;
|
||||
|
||||
// we need DVs on point fields to compute stats & facets
|
||||
if (Boolean.getBoolean(NUMERIC_POINTS_SYSPROP)) System.setProperty(NUMERIC_DOCVALUES_SYSPROP,"true");
|
||||
|
||||
initCore("solrconfig-tlog.xml","schema_latest.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start all servers for cluster if they don't already exist
|
||||
*/
|
||||
public static void initServers() throws Exception {
|
||||
if (servers == null) {
|
||||
servers = new SolrInstances(3, "solrconfig-tlog.xml", "schema_latest.xml");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@AfterClass
|
||||
public static void afterTests() throws Exception {
|
||||
systemClearPropertySolrDisableShardsWhitelist();
|
||||
JSONTestUtil.failRepeatedKeys = false;
|
||||
if (servers != null) {
|
||||
servers.stop();
|
||||
servers = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void indexSimple(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
client.add(sdoc("id", "1", "cat_s", "A", "where_s", "NY", "num_d", "4", "num_i", "2",
|
||||
"num_is", "4", "num_is", "2",
|
||||
"val_b", "true", "sparse_s", "one"), null);
|
||||
client.add(sdoc("id", "2", "cat_s", "B", "where_s", "NJ", "num_d", "-9", "num_i", "-5",
|
||||
"num_is", "-9", "num_is", "-5",
|
||||
"val_b", "false"), null);
|
||||
client.add(sdoc("id", "3"), null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "4", "cat_s", "A", "where_s", "NJ", "num_d", "2", "num_i", "3",
|
||||
"num_is", "2", "num_is", "3"), null);
|
||||
client.add(sdoc("id", "5", "cat_s", "B", "where_s", "NJ", "num_d", "11", "num_i", "7",
|
||||
"num_is", "11", "num_is", "7",
|
||||
"sparse_s", "two"),null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "6", "cat_s", "B", "where_s", "NY", "num_d", "-5", "num_i", "-5",
|
||||
"num_is", "-5"),null);
|
||||
client.commit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrors() throws Exception {
|
||||
doTestErrors(Client.localClient());
|
||||
}
|
||||
|
||||
public void doTestErrors(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
|
||||
try {
|
||||
client.testJQ(params("ignore_exception", "true", "q", "*:*"
|
||||
, "json.facet", "{f:{type:ignore_exception_aaa, field:bbbbbb}}"
|
||||
)
|
||||
);
|
||||
} catch (SolrException e) {
|
||||
assertTrue( e.getMessage().contains("ignore_exception_aaa") );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainErrors() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
// using assertQEx so that, status code and error message can be asserted
|
||||
assertQEx("Should Fail as filter with qparser in domain becomes null",
|
||||
"QParser yields null, perhaps unresolved parameter reference in: {!query v=$NOfilt}",
|
||||
req("q", "*:*", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{filter:'{!query v=$NOfilt}'}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST
|
||||
);
|
||||
|
||||
assertQEx("Should Fail as filter in domain becomes null",
|
||||
"QParser yields null, perhaps unresolved parameter reference in: {!v=$NOfilt}",
|
||||
req("q", "*:*", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{filter:'{!v=$NOfilt}'}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST
|
||||
);
|
||||
|
||||
// when domain type is invalid
|
||||
assertQEx("Should Fail as domain not of type map",
|
||||
"Expected Map for 'domain', received String=bleh , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:bleh}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// when domain = null, should not throw exception
|
||||
assertQ("Should pass as no domain is specified",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s}}"));
|
||||
|
||||
// when blockChildren or blockParent is passed but not of string
|
||||
assertQEx("Should Fail as blockChildren is of type map",
|
||||
"Expected string type for param 'blockChildren' but got LinkedHashMap = {} , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{blockChildren:{}}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should Fail as blockParent is of type map",
|
||||
"Expected string type for param 'blockParent' but got LinkedHashMap = {} , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{blockParent:{}}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetsErrorCases() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
SolrParams params = params("q", "*:*", "rows", "0");
|
||||
|
||||
// invalid format for ranges
|
||||
SolrException ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i,start:-10,end:10,gap:2," +
|
||||
"ranges:[{key:\"0-200\", to:200}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Cannot set gap/start/end and ranges params together", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:bleh}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected List for ranges but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[bleh]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected Map for range but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:0, to:200, inclusive_to:bleh}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected boolean type for param 'inclusive_to' but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:0, to:200, inclusive_from:bleh}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected boolean type for param 'inclusive_from' but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:bleh, to:200}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:0, to:bleh}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:200, to:0}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("'from' is higher than 'to' in range for key: [200,0)", ex.getMessage());
|
||||
|
||||
// with old format
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("empty facet range"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"bl\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Invalid start character b in facet range bl"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(bl\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Invalid end character l in facet range (bl"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(bleh,12)\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(12,bleh)\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(200,12)\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("'start' is higher than 'end' in range for key: (200,12)", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherErrorCases() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
// test for sort
|
||||
assertQEx("Should fail as sort is of type list",
|
||||
"Expected string/map for 'sort', received ArrayList=[count desc]",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:[\"count desc\"]}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as facet is not of type map",
|
||||
"Expected Map for 'facet', received ArrayList=[{}]",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "[{}]"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as queries is not of type map",
|
||||
"Expected Map for 'queries', received [{}]",
|
||||
req("q", "*:*", "rows", "0", "json.queries", "[{}]"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as queries are null in JSON",
|
||||
"Expected Map for 'queries', received null",
|
||||
req("json", "{query:\"*:*\", queries:null}"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// range facets
|
||||
assertQEx("Should fail as 'other' is of type Map",
|
||||
"Expected list of string or comma separated string values for 'other', " +
|
||||
"received LinkedHashMap={} , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10, end:12, gap:1, other:{}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as 'include' is of type Map",
|
||||
"Expected list of string or comma separated string values for 'include', " +
|
||||
"received LinkedHashMap={} , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10, end:12, gap:1, include:{}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// missing start parameter
|
||||
assertQEx("Should Fail with missing field error",
|
||||
"Missing required parameter: 'start' , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d}}"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// missing end parameter
|
||||
assertQEx("Should Fail with missing field error",
|
||||
"Missing required parameter: 'end' , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// missing gap parameter
|
||||
assertQEx("Should Fail with missing field error",
|
||||
"Missing required parameter: 'gap' , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10, end:12}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// invalid value for facet field
|
||||
assertQEx("Should Fail as args is of type long",
|
||||
"Expected string/map for facet field, received Long=2 , path=facet/facet",
|
||||
req("q", "*:*", "rows", "0", "json.facet.facet.field", "2"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// invalid value for facet query
|
||||
assertQEx("Should Fail as args is of type long for query",
|
||||
"Expected string/map for facet query, received Long=2 , path=facet/facet",
|
||||
req("q", "*:*", "rows", "0", "json.facet.facet.query", "2"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// valid facet field
|
||||
assertQ("Should pass as this is valid query",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s}}"));
|
||||
|
||||
// invalid perSeg
|
||||
assertQEx("Should fail as perSeg is not of type boolean",
|
||||
"Expected boolean type for param 'perSeg' but got Long = 2 , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,perSeg:2}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as sort is invalid",
|
||||
"Invalid sort option 'bleh' for field 'cat_s'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:bleh}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as sort order is invalid",
|
||||
"Unknown Sort direction 'bleh'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:{count: bleh}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// test for prelim_sort
|
||||
assertQEx("Should fail as prelim_sort is invalid",
|
||||
"Invalid prelim_sort option 'bleh' for field 'cat_s'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,prelim_sort:bleh}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as prelim_sort map is invalid",
|
||||
"Invalid prelim_sort option '{bleh=desc}' for field 'cat_s'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,prelim_sort:{bleh:desc}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// with nested facet
|
||||
assertQEx("Should fail as prelim_sort is invalid",
|
||||
"Invalid sort option 'bleh' for field 'id'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:bleh,facet:" +
|
||||
"{bleh:\"unique(cat_s)\",id:{type:terms,field:id,sort:bleh}}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQ("Should pass as sort is proper",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:bleh,facet:" +
|
||||
"{bleh:\"unique(cat_s)\",id:{type:terms,field:id,sort:{bleh:desc},facet:{bleh:\"unique(id)\"}}}}}")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAggErrors() {
|
||||
ignoreException("aggregation");
|
||||
|
||||
SolrException e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{bleh:'div(2,4)'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Expected multi-doc aggregation from 'div' but got per-doc function in input ('div(2,4)"));
|
||||
|
||||
e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{b:'agg(div(2,4))'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Expected multi-doc aggregation from 'div' but got per-doc function in input ('agg(div(2,4))"));
|
||||
|
||||
e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{b:'agg(bleh(2,4))'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Unknown aggregation 'bleh' in input ('agg(bleh(2,4))"));
|
||||
|
||||
e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{b:'bleh(2,4)'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Unknown aggregation 'bleh' in input ('bleh(2,4)"));
|
||||
|
||||
resetExceptionIgnores();
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@ import java.util.Map;
|
|||
import java.util.Random;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
|
||||
import com.tdunning.math.stats.AVLTreeDigest;
|
||||
import org.apache.lucene.util.LuceneTestCase;
|
||||
import org.apache.solr.JSONTestUtil;
|
||||
import org.apache.solr.SolrTestCaseHS;
|
||||
|
@ -42,14 +44,11 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
|
||||
import com.tdunning.math.stats.AVLTreeDigest;
|
||||
|
||||
import static org.hamcrest.core.StringContains.containsString;
|
||||
|
||||
// Related tests:
|
||||
// TestCloudJSONFacetJoinDomain for random field faceting tests with domain modifications
|
||||
// TestJsonFacetRefinement for refinement tests
|
||||
// TestJsonFacetErrors for error case tests
|
||||
// TestJsonRangeFacets for range facet tests
|
||||
|
||||
@LuceneTestCase.SuppressCodecs({"Lucene3x","Lucene40","Lucene41","Lucene42","Lucene45","Appending"})
|
||||
public class TestJsonFacets extends SolrTestCaseHS {
|
||||
|
@ -309,75 +308,7 @@ public class TestJsonFacets extends SolrTestCaseHS {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* whitebox sanity checks that a shard request range facet that returns "between" or "after"
|
||||
* will cause the correct "actual_end" to be returned
|
||||
*/
|
||||
public void testRangeOtherWhitebox() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
indexSimple(client);
|
||||
|
||||
// false is default, but randomly check explicit false as well
|
||||
final String nohardend = random().nextBoolean() ? "" : " hardend:false, ";
|
||||
|
||||
{ // first check some "phase #1" requests
|
||||
|
||||
final SolrParams p = params("q", "*:*", "rows", "0", "isShard", "true", "distrib", "false",
|
||||
"_facet_", "{}", "shards.purpose", ""+FacetModule.PURPOSE_GET_JSON_FACETS);
|
||||
final String basic_opts = "type:range, field:num_d, start:-5, end:10, gap:7, ";
|
||||
final String buckets = "buckets:[ {val:-5.0,count:1}, {val:2.0,count:2}, {val:9.0,count:1} ], ";
|
||||
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + nohardend + " other:before}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
// before doesn't need actual_end
|
||||
+ " before:{count:1}"
|
||||
+ "} }"
|
||||
);
|
||||
client.testJQ(params(p, "json.facet", "{f:{" + basic_opts + nohardend + "other:after}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
+ " after:{count:0}, _actual_end:'16.0'"
|
||||
+ "} }"
|
||||
);
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + nohardend + "other:between}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
+ " between:{count:4}, _actual_end:'16.0'"
|
||||
+ "} }"
|
||||
);
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + nohardend + "other:all}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
+ " before:{count:1},"
|
||||
+ " after:{count:0},"
|
||||
+ " between:{count:4},"
|
||||
+ " _actual_end:'16.0'"
|
||||
+ "} }"
|
||||
);
|
||||
// with hardend:true, not only do the buckets change, but actual_end should not need to be returned
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + " hardend:true, other:after}}")
|
||||
, "facets=={count:6, f:{"
|
||||
+ " buckets:[ {val:-5.0,count:1}, {val:2.0,count:2}, {val:9.0,count:0} ], "
|
||||
+ " after:{count:1}"
|
||||
+ "} }"
|
||||
);
|
||||
}
|
||||
|
||||
{ // now check some "phase #2" requests with refinement buckets already specified
|
||||
|
||||
final String facet
|
||||
= "{ top:{ type:range, field:num_i, start:-5, end:5, gap:7," + nohardend
|
||||
+ " other:all, facet:{ x:{ type:terms, field:cat_s, limit:1, refine:true } } } }";
|
||||
|
||||
// the behavior should be the same, regardless of wether we pass actual_end to the shards
|
||||
// because in a "mixed mode" rolling update, the shards should be smart enough to re-compute if
|
||||
// the merging node is running an older version that doesn't send it
|
||||
for (String actual_end : Arrays.asList(", _actual_end:'9'", "")) {
|
||||
client.testJQ(params("q", "*:*", "rows", "0", "isShard", "true", "distrib", "false",
|
||||
"shards.purpose", ""+FacetModule.PURPOSE_REFINE_JSON_FACETS,
|
||||
"json.facet", facet,
|
||||
"_facet_", "{ refine: { top: { between:{ x:{ _l:[B] } }" + actual_end + "} } }")
|
||||
, "facets=={top:{ buckets:[], between:{x:{buckets:[{val:B,count:3}] }} } }");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExplicitQueryDomain() throws Exception {
|
||||
|
@ -3023,8 +2954,6 @@ public class TestJsonFacets extends SolrTestCaseHS {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testBlockJoin() throws Exception {
|
||||
doBlockJoin(Client.localClient());
|
||||
|
@ -3354,518 +3283,6 @@ public class TestJsonFacets extends SolrTestCaseHS {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testErrors() throws Exception {
|
||||
doTestErrors(Client.localClient());
|
||||
}
|
||||
|
||||
public void doTestErrors(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
|
||||
try {
|
||||
client.testJQ(params("ignore_exception", "true", "q", "*:*"
|
||||
, "json.facet", "{f:{type:ignore_exception_aaa, field:bbbbbb}}"
|
||||
)
|
||||
);
|
||||
} catch (SolrException e) {
|
||||
assertTrue( e.getMessage().contains("ignore_exception_aaa") );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainErrors() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
// using assertQEx so that, status code and error message can be asserted
|
||||
assertQEx("Should Fail as filter with qparser in domain becomes null",
|
||||
"QParser yields null, perhaps unresolved parameter reference in: {!query v=$NOfilt}",
|
||||
req("q", "*:*", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{filter:'{!query v=$NOfilt}'}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST
|
||||
);
|
||||
|
||||
assertQEx("Should Fail as filter in domain becomes null",
|
||||
"QParser yields null, perhaps unresolved parameter reference in: {!v=$NOfilt}",
|
||||
req("q", "*:*", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{filter:'{!v=$NOfilt}'}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST
|
||||
);
|
||||
|
||||
// when domain type is invalid
|
||||
assertQEx("Should Fail as domain not of type map",
|
||||
"Expected Map for 'domain', received String=bleh , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:bleh}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// when domain = null, should not throw exception
|
||||
assertQ("Should pass as no domain is specified",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s}}"));
|
||||
|
||||
// when blockChildren or blockParent is passed but not of string
|
||||
assertQEx("Should Fail as blockChildren is of type map",
|
||||
"Expected string type for param 'blockChildren' but got LinkedHashMap = {} , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{blockChildren:{}}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should Fail as blockParent is of type map",
|
||||
"Expected string type for param 'blockParent' but got LinkedHashMap = {} , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,domain:{blockParent:{}}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetWithRanges() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
final SolrParams p = params("q", "*:*", "rows", "0");
|
||||
// with lower and upper include
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i, ranges:[{range:\" [-5,7] \"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7]\",count:5}]}}");
|
||||
|
||||
// with lower include and upper exclude
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"[-5,7)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7)\",count:4}]}}");
|
||||
|
||||
// with lower exclude and upper include
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(-5,7]\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// with lower and upper exclude
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(-5,7)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// with other and include, they are not supported
|
||||
// but wouldn't throw any error as they are not consumed
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(-5,7)\"}],include:\"lower\",other:[\"after\"]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// with mincount>0
|
||||
client.testJQ(
|
||||
params(p, "json.facet", "{price:{type : range,field : num_i,mincount:3," +
|
||||
"ranges:[{range:\"(-5,7)\"},{range:\"(-5,7]\"}]}}"
|
||||
),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// with multiple ranges
|
||||
client.testJQ(
|
||||
params(p, "json.facet", "{price:{type : range,field : num_i," +
|
||||
"ranges:[{range:\"(-5,7)\"},{range:\"(-5,7]\"}]}}"
|
||||
),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2},{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// with * as one of the values
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(*,10]\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(*,10]\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"[-5,*)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"[*,*]\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[*,*]\",count:5}]}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateFacets() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
boolean multiValue = random().nextBoolean();
|
||||
String dateField = multiValue? "b_dts": "b_dt";
|
||||
String dateRange = multiValue? "b_drfs": "b_drf";
|
||||
|
||||
client.add(sdoc("id", "1", "cat_s", "A", dateField, "2014-03-15T12:00:00Z",
|
||||
dateRange, "2014-03-15T12:00:00Z"), null);
|
||||
client.add(sdoc("id", "2", "cat_s", "B", dateField, "2015-01-03T00:00:00Z",
|
||||
dateRange, "2015-01-03T00:00:00Z"), null);
|
||||
client.add(sdoc("id", "3"), null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "4", "cat_s", "A", dateField, "2014-03-15T12:00:00Z",
|
||||
dateRange, "2014-03-15T12:00:00Z"), null);
|
||||
client.add(sdoc("id", "5", "cat_s", "B", dateField, "2015-01-03T00:00:00Z",
|
||||
dateRange, "2015-01-03T00:00:00Z"),null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "6", "cat_s", "B", dateField, "2014-03-15T12:00:00Z",
|
||||
dateRange, "2014-03-15T12:00:00Z"),null);
|
||||
client.commit();
|
||||
|
||||
SolrParams p = params("q", "*:*", "rows", "0");
|
||||
for (String s : new String[]{dateField, dateRange}) {
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{date:{type : range, mincount:1, field :" + s +
|
||||
",start:'2013-11-01T00:00:00Z',end:NOW,gap:'+90DAY'}}"),
|
||||
"facets=={count:6, date:{buckets:" +
|
||||
"[{val:\"2014-01-30T00:00:00Z\",count:3}, {val:\"2014-10-27T00:00:00Z\",count:2}]" +
|
||||
"}}");
|
||||
|
||||
// with ranges
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{date:{type : range, mincount:1, field :" + s +
|
||||
",ranges:[{from:'2013-11-01T00:00:00Z', to:'2014-04-30T00:00:00Z'}," +
|
||||
"{from:'2015-01-01T00:00:00Z', to:'2020-01-30T00:00:00Z'}]}}"),
|
||||
"facets=={count:6, date:{buckets:" +
|
||||
"[{val:\"[2013-11-01T00:00:00Z,2014-04-30T00:00:00Z)\",count:3}," +
|
||||
" {val:\"[2015-01-01T00:00:00Z,2020-01-30T00:00:00Z)\",count:2}]" +
|
||||
"}}");
|
||||
}
|
||||
|
||||
client.add(sdoc("id", "7", "cat_s", "B", dateRange, "[2010 TO 2014-05-21]"),null);
|
||||
client.commit();
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{date:{type : range, other:'before', field :" + dateRange +
|
||||
",start:'2011-11-01T00:00:00Z',end:'2016-01-30T00:00:00Z',gap:'+1YEAR'}}"),
|
||||
"facets=={count:7, date:{buckets:[" +
|
||||
"{val:\"2011-11-01T00:00:00Z\",count:1}, {val:\"2012-11-01T00:00:00Z\",count:1}," +
|
||||
"{val:\"2013-11-01T00:00:00Z\",count:4}, {val:\"2014-11-01T00:00:00Z\",count:2}," +
|
||||
"{val:\"2015-11-01T00:00:00Z\",count:0}" +
|
||||
"],before:{count:1}" +
|
||||
"}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetWithRangesInNewFormat() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
SolrParams p = params("q", "*:*", "rows", "0");
|
||||
|
||||
//case without inclusive params
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7)\",count:4}]}}");
|
||||
|
||||
//case without key param and to included
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:true ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7]\",count:5}]}}");
|
||||
|
||||
//case with all params
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:true ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7]\",count:5}]}}");
|
||||
|
||||
// from and to excluded
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// from excluded and to included
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// multiple ranges
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,include:[\"lower\"], outer:\"before\"," +
|
||||
"ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true},{from:-5, to:7,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3},{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// with mincount>0
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,mincount:3" +
|
||||
"ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true},{from:-5, to:7,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// mix of old and new formats
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i," +
|
||||
"ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true},{range:\"(-5,7)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3},{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// from==to
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:false ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,-5]\",count:0}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,-5)\",count:0}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,-5)\",count:0}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:true ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,-5]\",count:2}]}}");
|
||||
|
||||
// with * as one of the values
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:\"*\", to:10,inclusive_from:false ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(*,10]\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:\"*\",inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5,inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:\"*\", to:\"*\",inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[*,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[*,*)\",count:5}]}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetsErrorCases() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
SolrParams params = params("q", "*:*", "rows", "0");
|
||||
|
||||
// invalid format for ranges
|
||||
SolrException ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i,start:-10,end:10,gap:2," +
|
||||
"ranges:[{key:\"0-200\", to:200}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Cannot set gap/start/end and ranges params together", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:bleh}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected List for ranges but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[bleh]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected Map for range but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:0, to:200, inclusive_to:bleh}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected boolean type for param 'inclusive_to' but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:0, to:200, inclusive_from:bleh}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Expected boolean type for param 'inclusive_from' but got String"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:bleh, to:200}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:0, to:bleh}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{from:200, to:0}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("'from' is higher than 'to' in range for key: [200,0)", ex.getMessage());
|
||||
|
||||
// with old format
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("empty facet range"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"bl\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Invalid start character b in facet range bl"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(bl\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertTrue(ex.getMessage().contains("Invalid end character l in facet range (bl"));
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(bleh,12)\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(12,bleh)\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("Can't parse value bleh for field: num_i", ex.getMessage());
|
||||
|
||||
ex = expectThrows(SolrException.class,
|
||||
() -> h.query(req(params, "json.facet", "{price:{type :range, field : num_i," +
|
||||
"ranges:[{range:\"(200,12)\"}]}}"))
|
||||
);
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, ex.code());
|
||||
assertEquals("'start' is higher than 'end' in range for key: (200,12)", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOtherErrorCases() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
// test for sort
|
||||
assertQEx("Should fail as sort is of type list",
|
||||
"Expected string/map for 'sort', received ArrayList=[count desc]",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:[\"count desc\"]}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as facet is not of type map",
|
||||
"Expected Map for 'facet', received ArrayList=[{}]",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "[{}]"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as queries is not of type map",
|
||||
"Expected Map for 'queries', received [{}]",
|
||||
req("q", "*:*", "rows", "0", "json.queries", "[{}]"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as queries are null in JSON",
|
||||
"Expected Map for 'queries', received null",
|
||||
req("json", "{query:\"*:*\", queries:null}"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// range facets
|
||||
assertQEx("Should fail as 'other' is of type Map",
|
||||
"Expected list of string or comma separated string values for 'other', " +
|
||||
"received LinkedHashMap={} , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10, end:12, gap:1, other:{}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as 'include' is of type Map",
|
||||
"Expected list of string or comma separated string values for 'include', " +
|
||||
"received LinkedHashMap={} , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10, end:12, gap:1, include:{}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// missing start parameter
|
||||
assertQEx("Should Fail with missing field error",
|
||||
"Missing required parameter: 'start' , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d}}"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// missing end parameter
|
||||
assertQEx("Should Fail with missing field error",
|
||||
"Missing required parameter: 'end' , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// missing gap parameter
|
||||
assertQEx("Should Fail with missing field error",
|
||||
"Missing required parameter: 'gap' , path=facet/f",
|
||||
req("q", "*:*", "json.facet", "{f:{type:range, field:num_d, start:10, end:12}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// invalid value for facet field
|
||||
assertQEx("Should Fail as args is of type long",
|
||||
"Expected string/map for facet field, received Long=2 , path=facet/facet",
|
||||
req("q", "*:*", "rows", "0", "json.facet.facet.field", "2"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// invalid value for facet query
|
||||
assertQEx("Should Fail as args is of type long for query",
|
||||
"Expected string/map for facet query, received Long=2 , path=facet/facet",
|
||||
req("q", "*:*", "rows", "0", "json.facet.facet.query", "2"), SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// valid facet field
|
||||
assertQ("Should pass as this is valid query",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s}}"));
|
||||
|
||||
// invalid perSeg
|
||||
assertQEx("Should fail as perSeg is not of type boolean",
|
||||
"Expected boolean type for param 'perSeg' but got Long = 2 , path=facet/cat_s",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,perSeg:2}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as sort is invalid",
|
||||
"Invalid sort option 'bleh' for field 'cat_s'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:bleh}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as sort order is invalid",
|
||||
"Unknown Sort direction 'bleh'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:{count: bleh}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// test for prelim_sort
|
||||
assertQEx("Should fail as prelim_sort is invalid",
|
||||
"Invalid prelim_sort option 'bleh' for field 'cat_s'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,prelim_sort:bleh}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQEx("Should fail as prelim_sort map is invalid",
|
||||
"Invalid prelim_sort option '{bleh=desc}' for field 'cat_s'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,prelim_sort:{bleh:desc}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
// with nested facet
|
||||
assertQEx("Should fail as prelim_sort is invalid",
|
||||
"Invalid sort option 'bleh' for field 'id'",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:bleh,facet:" +
|
||||
"{bleh:\"unique(cat_s)\",id:{type:terms,field:id,sort:bleh}}}}"),
|
||||
SolrException.ErrorCode.BAD_REQUEST);
|
||||
|
||||
assertQ("Should pass as sort is proper",
|
||||
req("q", "*:*", "rows", "0", "json.facet", "{cat_s:{type:terms,field:cat_s,sort:bleh,facet:" +
|
||||
"{bleh:\"unique(cat_s)\",id:{type:terms,field:id,sort:{bleh:desc},facet:{bleh:\"unique(id)\"}}}}}")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAggErrors() {
|
||||
ignoreException("aggregation");
|
||||
|
||||
SolrException e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{bleh:'div(2,4)'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Expected multi-doc aggregation from 'div' but got per-doc function in input ('div(2,4)"));
|
||||
|
||||
e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{b:'agg(div(2,4))'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Expected multi-doc aggregation from 'div' but got per-doc function in input ('agg(div(2,4))"));
|
||||
|
||||
e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{b:'agg(bleh(2,4))'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Unknown aggregation 'bleh' in input ('agg(bleh(2,4))"));
|
||||
|
||||
e = expectThrows(SolrException.class, () -> {
|
||||
h.query(req("q", "*:*", "json.facet", "{b:'bleh(2,4)'}"));
|
||||
});
|
||||
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
|
||||
assertThat(e.getMessage(),
|
||||
containsString("Unknown aggregation 'bleh' in input ('bleh(2,4)"));
|
||||
|
||||
resetExceptionIgnores();
|
||||
}
|
||||
|
||||
|
||||
public void XtestPercentiles() {
|
||||
AVLTreeDigest catA = new AVLTreeDigest(100);
|
||||
catA.add(4);
|
||||
|
|
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* 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.facet;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.solr.JSONTestUtil;
|
||||
import org.apache.solr.SolrTestCaseHS;
|
||||
import org.apache.solr.common.params.SolrParams;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class TestJsonRangeFacets extends SolrTestCaseHS {
|
||||
|
||||
private static SolrInstances servers; // for distributed testing
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@BeforeClass
|
||||
public static void beforeTests() throws Exception {
|
||||
systemSetPropertySolrDisableShardsWhitelist("true");
|
||||
JSONTestUtil.failRepeatedKeys = true;
|
||||
|
||||
// we need DVs on point fields to compute stats & facets
|
||||
if (Boolean.getBoolean(NUMERIC_POINTS_SYSPROP)) System.setProperty(NUMERIC_DOCVALUES_SYSPROP,"true");
|
||||
|
||||
initCore("solrconfig-tlog.xml","schema_latest.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start all servers for cluster if they don't already exist
|
||||
*/
|
||||
public static void initServers() throws Exception {
|
||||
if (servers == null) {
|
||||
servers = new SolrInstances(3, "solrconfig-tlog.xml", "schema_latest.xml");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@AfterClass
|
||||
public static void afterTests() throws Exception {
|
||||
systemClearPropertySolrDisableShardsWhitelist();
|
||||
JSONTestUtil.failRepeatedKeys = false;
|
||||
if (servers != null) {
|
||||
servers.stop();
|
||||
servers = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void indexSimple(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
client.add(sdoc("id", "1", "cat_s", "A", "where_s", "NY", "num_d", "4", "num_i", "2",
|
||||
"num_is", "4", "num_is", "2",
|
||||
"val_b", "true", "sparse_s", "one"), null);
|
||||
client.add(sdoc("id", "2", "cat_s", "B", "where_s", "NJ", "num_d", "-9", "num_i", "-5",
|
||||
"num_is", "-9", "num_is", "-5",
|
||||
"val_b", "false"), null);
|
||||
client.add(sdoc("id", "3"), null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "4", "cat_s", "A", "where_s", "NJ", "num_d", "2", "num_i", "3",
|
||||
"num_is", "2", "num_is", "3"), null);
|
||||
client.add(sdoc("id", "5", "cat_s", "B", "where_s", "NJ", "num_d", "11", "num_i", "7",
|
||||
"num_is", "11", "num_is", "7",
|
||||
"sparse_s", "two"),null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "6", "cat_s", "B", "where_s", "NY", "num_d", "-5", "num_i", "-5",
|
||||
"num_is", "-5"),null);
|
||||
client.commit();
|
||||
}
|
||||
|
||||
public void testRangeOtherWhiteboxDistrib() throws Exception {
|
||||
initServers();
|
||||
Client client = servers.getClient(random().nextInt());
|
||||
client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
|
||||
}
|
||||
|
||||
public void testRangeOtherWhitebox() throws Exception {
|
||||
doRangeOtherWhitebox(Client.localClient());
|
||||
}
|
||||
|
||||
/**
|
||||
* whitebox sanity checks that a shard request range facet that returns "between" or "after"
|
||||
* will cause the correct "actual_end" to be returned
|
||||
*/
|
||||
private void doRangeOtherWhitebox(Client client) throws Exception {
|
||||
indexSimple(client);
|
||||
|
||||
// false is default, but randomly check explicit false as well
|
||||
final String nohardend = random().nextBoolean() ? "" : " hardend:false, ";
|
||||
|
||||
{ // first check some "phase #1" requests
|
||||
|
||||
final SolrParams p = params("q", "*:*", "rows", "0", "isShard", "true", "distrib", "false",
|
||||
"_facet_", "{}", "shards.purpose", ""+FacetModule.PURPOSE_GET_JSON_FACETS);
|
||||
final String basic_opts = "type:range, field:num_d, start:-5, end:10, gap:7, ";
|
||||
final String buckets = "buckets:[ {val:-5.0,count:1}, {val:2.0,count:2}, {val:9.0,count:1} ], ";
|
||||
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + nohardend + " other:before}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
// before doesn't need actual_end
|
||||
+ " before:{count:1}"
|
||||
+ "} }"
|
||||
);
|
||||
client.testJQ(params(p, "json.facet", "{f:{" + basic_opts + nohardend + "other:after}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
+ " after:{count:0}, _actual_end:'16.0'"
|
||||
+ "} }"
|
||||
);
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + nohardend + "other:between}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
+ " between:{count:4}, _actual_end:'16.0'"
|
||||
+ "} }"
|
||||
);
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + nohardend + "other:all}}")
|
||||
, "facets=={count:6, f:{" + buckets
|
||||
+ " before:{count:1},"
|
||||
+ " after:{count:0},"
|
||||
+ " between:{count:4},"
|
||||
+ " _actual_end:'16.0'"
|
||||
+ "} }"
|
||||
);
|
||||
// with hardend:true, not only do the buckets change, but actual_end should not need to be returned
|
||||
client.testJQ(params(p, "json.facet", "{f:{ " + basic_opts + " hardend:true, other:after}}")
|
||||
, "facets=={count:6, f:{"
|
||||
+ " buckets:[ {val:-5.0,count:1}, {val:2.0,count:2}, {val:9.0,count:0} ], "
|
||||
+ " after:{count:1}"
|
||||
+ "} }"
|
||||
);
|
||||
}
|
||||
|
||||
{ // now check some "phase #2" requests with refinement buckets already specified
|
||||
|
||||
final String facet
|
||||
= "{ top:{ type:range, field:num_i, start:-5, end:5, gap:7," + nohardend
|
||||
+ " other:all, facet:{ x:{ type:terms, field:cat_s, limit:1, refine:true } } } }";
|
||||
|
||||
// the behavior should be the same, regardless of wether we pass actual_end to the shards
|
||||
// because in a "mixed mode" rolling update, the shards should be smart enough to re-compute if
|
||||
// the merging node is running an older version that doesn't send it
|
||||
for (String actual_end : Arrays.asList(", _actual_end:'9'", "")) {
|
||||
client.testJQ(params("q", "*:*", "rows", "0", "isShard", "true", "distrib", "false",
|
||||
"shards.purpose", ""+FacetModule.PURPOSE_REFINE_JSON_FACETS,
|
||||
"json.facet", facet,
|
||||
"_facet_", "{ refine: { top: { between:{ x:{ _l:[B] } }" + actual_end + "} } }")
|
||||
, "facets=={top:{ buckets:[], between:{x:{buckets:[{val:B,count:3}] }} } }");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateFacetsDistrib() throws Exception {
|
||||
initServers();
|
||||
Client client = servers.getClient(random().nextInt());
|
||||
client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
|
||||
doDateFacets(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateFacets() throws Exception {
|
||||
doDateFacets(Client.localClient());
|
||||
}
|
||||
|
||||
private void doDateFacets(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
boolean multiValue = random().nextBoolean();
|
||||
String dateField = multiValue? "b_dts": "b_dt";
|
||||
String dateRange = multiValue? "b_drfs": "b_drf";
|
||||
|
||||
client.add(sdoc("id", "1", "cat_s", "A", dateField, "2014-03-15T12:00:00Z",
|
||||
dateRange, "2014-03-15T12:00:00Z"), null);
|
||||
client.add(sdoc("id", "2", "cat_s", "B", dateField, "2015-01-03T00:00:00Z",
|
||||
dateRange, "2015-01-03T00:00:00Z"), null);
|
||||
client.add(sdoc("id", "3"), null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "4", "cat_s", "A", dateField, "2014-03-15T12:00:00Z",
|
||||
dateRange, "2014-03-15T12:00:00Z"), null);
|
||||
client.add(sdoc("id", "5", "cat_s", "B", dateField, "2015-01-03T00:00:00Z",
|
||||
dateRange, "2015-01-03T00:00:00Z"),null);
|
||||
client.commit();
|
||||
client.add(sdoc("id", "6", "cat_s", "B", dateField, "2014-03-15T12:00:00Z",
|
||||
dateRange, "2014-03-15T12:00:00Z"),null);
|
||||
client.commit();
|
||||
|
||||
SolrParams p = params("q", "*:*", "rows", "0");
|
||||
for (String s : new String[]{dateField, dateRange}) {
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{date:{type : range, mincount:1, field :" + s +
|
||||
",start:'2013-11-01T00:00:00Z',end:NOW,gap:'+90DAY'}}"),
|
||||
"facets=={count:6, date:{buckets:" +
|
||||
"[{val:\"2014-01-30T00:00:00Z\",count:3}, {val:\"2014-10-27T00:00:00Z\",count:2}]" +
|
||||
"}}");
|
||||
|
||||
// with ranges
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{date:{type : range, mincount:1, field :" + s +
|
||||
",ranges:[{from:'2013-11-01T00:00:00Z', to:'2014-04-30T00:00:00Z'}," +
|
||||
"{from:'2015-01-01T00:00:00Z', to:'2020-01-30T00:00:00Z'}]}}"),
|
||||
"facets=={count:6, date:{buckets:" +
|
||||
"[{val:\"[2013-11-01T00:00:00Z,2014-04-30T00:00:00Z)\",count:3}," +
|
||||
" {val:\"[2015-01-01T00:00:00Z,2020-01-30T00:00:00Z)\",count:2}]" +
|
||||
"}}");
|
||||
}
|
||||
|
||||
client.add(sdoc("id", "7", "cat_s", "B", dateRange, "[2010 TO 2014-05-21]"),null);
|
||||
client.commit();
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{date:{type : range, other:'before', field :" + dateRange +
|
||||
",start:'2011-11-01T00:00:00Z',end:'2016-01-30T00:00:00Z',gap:'+1YEAR'}}"),
|
||||
"facets=={count:7, date:{buckets:[" +
|
||||
"{val:\"2011-11-01T00:00:00Z\",count:1}, {val:\"2012-11-01T00:00:00Z\",count:1}," +
|
||||
"{val:\"2013-11-01T00:00:00Z\",count:4}, {val:\"2014-11-01T00:00:00Z\",count:2}," +
|
||||
"{val:\"2015-11-01T00:00:00Z\",count:0}" +
|
||||
"],before:{count:1}" +
|
||||
"}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetWithRangesDistrib() throws Exception {
|
||||
initServers();
|
||||
Client client = servers.getClient(random().nextInt());
|
||||
client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
|
||||
doRangeFacetWithRanges(client);
|
||||
}
|
||||
|
||||
public void testRangeFacetWithRanges() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
doRangeFacetWithRanges(client);
|
||||
}
|
||||
|
||||
private void doRangeFacetWithRanges(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
|
||||
final SolrParams p = params("q", "*:*", "rows", "0");
|
||||
// with lower and upper include
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i, ranges:[{range:\" [-5,7] \"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7]\",count:5}]}}");
|
||||
|
||||
// with lower include and upper exclude
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"[-5,7)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7)\",count:4}]}}");
|
||||
|
||||
// with lower exclude and upper include
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(-5,7]\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// with lower and upper exclude
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(-5,7)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// with other and include, they are not supported
|
||||
// but wouldn't throw any error as they are not consumed
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(-5,7)\"}],include:\"lower\",other:[\"after\"]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// with mincount>0
|
||||
client.testJQ(
|
||||
params(p, "json.facet", "{price:{type : range,field : num_i,mincount:3," +
|
||||
"ranges:[{range:\"(-5,7)\"},{range:\"(-5,7]\"}]}}"
|
||||
),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// with multiple ranges
|
||||
client.testJQ(
|
||||
params(p, "json.facet", "{price:{type : range,field : num_i," +
|
||||
"ranges:[{range:\"(-5,7)\"},{range:\"(-5,7]\"}]}}"
|
||||
),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2},{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// with * as one of the values
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"(*,10]\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(*,10]\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"[-5,*)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{range:\"[*,*]\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[*,*]\",count:5}]}}");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetWithRangesInNewFormatDistrib() throws Exception {
|
||||
initServers();
|
||||
Client client = servers.getClient(random().nextInt());
|
||||
client.queryDefaults().set( "shards", servers.getShards(), "debugQuery", Boolean.toString(random().nextBoolean()) );
|
||||
doRangeFacetWithRangesInNewFormat(client);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeFacetWithRangesInNewFormat() throws Exception {
|
||||
Client client = Client.localClient();
|
||||
doRangeFacetWithRangesInNewFormat(client);
|
||||
}
|
||||
|
||||
private void doRangeFacetWithRangesInNewFormat(Client client) throws Exception {
|
||||
client.deleteByQuery("*:*", null);
|
||||
indexSimple(client);
|
||||
SolrParams p = params("q", "*:*", "rows", "0");
|
||||
|
||||
//case without inclusive params
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7)\",count:4}]}}");
|
||||
|
||||
//case without key param and to included
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:true ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7]\",count:5}]}}");
|
||||
|
||||
//case with all params
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:true ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,7]\",count:5}]}}");
|
||||
|
||||
// from and to excluded
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// from excluded and to included
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// multiple ranges
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,include:[\"lower\"], outer:\"before\"," +
|
||||
"ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true},{from:-5, to:7,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3},{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// with mincount>0
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,mincount:3" +
|
||||
"ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true},{from:-5, to:7,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3}]}}");
|
||||
|
||||
// mix of old and new formats
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i," +
|
||||
"ranges:[{from:-5, to:7,inclusive_from:false ,inclusive_to:true},{range:\"(-5,7)\"}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,7]\",count:3},{val:\"(-5,7)\",count:2}]}}");
|
||||
|
||||
// from==to
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:false ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,-5]\",count:0}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:false ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(-5,-5)\",count:0}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,-5)\",count:0}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:-5,inclusive_from:true ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,-5]\",count:2}]}}");
|
||||
|
||||
// with * as one of the values
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:\"*\", to:10,inclusive_from:false ,inclusive_to:true}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"(*,10]\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5, to:\"*\",inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:-5,inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[-5,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{from:\"*\", to:\"*\",inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[*,*)\",count:5}]}}");
|
||||
client.testJQ(params(p, "json.facet"
|
||||
, "{price:{type : range,field : num_i,ranges:[{inclusive_from:true ,inclusive_to:false}]}}"),
|
||||
"facets=={count:6, price:{buckets:[{val:\"[*,*)\",count:5}]}}");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue