| /* |
| * 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.request; |
| |
| import java.io.IOException; |
| import java.lang.invoke.MethodHandles; |
| import java.text.SimpleDateFormat; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.HashSet; |
| import java.util.Locale; |
| import java.util.Set; |
| |
| import org.apache.lucene.util.BytesRef; |
| import org.apache.solr.SolrTestCaseJ4; |
| import org.apache.solr.client.solrj.SolrClient; |
| import org.apache.solr.client.solrj.SolrQuery; |
| import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer; |
| import org.apache.solr.client.solrj.response.QueryResponse; |
| import org.apache.solr.common.SolrException; |
| import org.apache.solr.common.params.ModifiableSolrParams; |
| import org.apache.solr.common.util.NamedList; |
| import org.apache.solr.request.IntervalFacets.FacetInterval; |
| import org.apache.solr.request.IntervalFacets.IntervalCompareResult; |
| import org.apache.solr.response.SolrQueryResponse; |
| import org.apache.solr.schema.FieldType; |
| import org.apache.solr.schema.NumberType; |
| import org.apache.solr.schema.SchemaField; |
| import org.apache.solr.schema.StrField; |
| import org.apache.solr.search.SyntaxError; |
| import org.junit.BeforeClass; |
| import org.junit.Test; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| public class TestIntervalFaceting extends SolrTestCaseJ4 { |
| |
| private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); |
| |
| private final static long DATE_START_TIME_RANDOM_TEST = 1499797224224L; |
| private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ROOT); |
| |
| @BeforeClass |
| public static void beforeTests() throws Exception { |
| // we need DVs on point fields to compute stats & facets |
| if (Boolean.getBoolean(NUMERIC_POINTS_SYSPROP)) System.setProperty(NUMERIC_DOCVALUES_SYSPROP,"true"); |
| initCore("solrconfig-basic.xml", "schema-docValuesFaceting.xml"); |
| } |
| |
| @Override |
| public void tearDown() throws Exception { |
| assertU(delQ("*:*")); |
| assertU(commit()); |
| assertU(optimize()); |
| assertQ(req("*:*"), "//*[@numFound='0']"); |
| super.tearDown(); |
| } |
| |
| @Test |
| public void testMultiValueFields() { |
| assertU(adoc("id", "1", "test_ss_dv", "dog")); |
| assertU(adoc("id", "2", "test_ss_dv", "cat")); |
| assertU(adoc("id", "3", "test_ss_dv", "bird")); |
| assertU(adoc("id", "4", "test_ss_dv", "turtle")); |
| assertU(commit()); |
| assertU(adoc("id", "5", "test_ss_dv", "\\goodbye,")); |
| assertU(adoc("id", "6", "test_ss_dv", ",hello\\")); |
| assertU(adoc("id", "7", "test_ss_dv", "dog")); |
| assertU(commit()); |
| assertU(adoc("id", "8", "test_ss_dv", "dog")); |
| assertU(adoc("id", "9", "test_ss_dv", "cat")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertIntervalQueriesString("test_ss_dv"); |
| assertU(delQ("*:*")); |
| assertU(commit()); |
| assertU(optimize()); |
| |
| assertU(adoc("id", "1", "test_ss_dv", "dog", "test_ss_dv", "cat")); |
| assertU(adoc("id", "2", "test_ss_dv", "cat", "test_ss_dv", "bird")); |
| assertU(commit()); |
| |
| assertIntervalQuery("test_ss_dv", "[hello,hello]", "0"); |
| assertIntervalQuery("test_ss_dv", "[dog,dog]", "1"); |
| assertIntervalQuery("test_ss_dv", "[cat,cat]", "2"); |
| assertIntervalQuery("test_ss_dv", "[*,*]", "2", "[*,cat)", "1", "[cat,dog)", "2", "[dog,*)", "1"); |
| } |
| |
| @Test |
| public void testMultipleSegments() { |
| assertU(adoc("id", "1", "test_s_dv", "dog")); |
| assertU(adoc("id", "2", "test_s_dv", "cat")); |
| assertU(adoc("id", "3", "test_s_dv", "bird")); |
| assertU(adoc("id", "4", "test_s_dv", "turtle")); |
| assertU(commit()); |
| assertU(adoc("id", "5", "test_s_dv", "\\goodbye,")); |
| assertU(adoc("id", "6", "test_s_dv", ",hello\\")); |
| assertU(adoc("id", "7", "test_s_dv", "dog")); |
| assertU(commit()); |
| assertU(adoc("id", "8", "test_s_dv", "dog")); |
| assertU(adoc("id", "9", "test_s_dv", "cat")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| int i = 11; |
| while (getNumberOfReaders() < 2 && i < 20) { |
| //try to get more than one segment |
| assertU(adoc("id", String.valueOf(i), "test_i_dv", String.valueOf(i))); |
| assertU(commit()); |
| i++; |
| } |
| if (getNumberOfReaders() < 2) { |
| // It is OK if for some seeds we fall into this case (for example, TieredMergePolicy with |
| // segmentsPerTier=2). Most of the case we shouldn't and the test should proceed. |
| log.warn("Could not generate more than 1 segment for this seed. Will skip the test"); |
| return; |
| } |
| |
| assertIntervalQueriesString("test_s_dv"); |
| |
| } |
| |
| @Test |
| public void testMultipleTerms() { |
| assertU(adoc("id", "1", "test_s_dv", "Buenos Aires")); |
| assertU(adoc("id", "2", "test_s_dv", "New York")); |
| assertU(adoc("id", "3", "test_s_dv", "Los Angeles")); |
| assertU(adoc("id", "4", "test_s_dv", "San Francisco")); |
| assertU(adoc("id", "5", "test_s_dv", "Las Vegas")); |
| assertU(adoc("id", "6", "test_s_dv", "São Paulo")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertIntervalQuery("test_s_dv", "[*,*]", "6"); |
| assertIntervalQuery("test_s_dv", "[A,C]", "1"); |
| assertIntervalQuery("test_s_dv", "[Buenos Aires,Buenos Aires]", "1"); |
| assertIntervalQuery("test_s_dv", "[Las,Los]", "1"); |
| assertIntervalQuery("test_s_dv", "[Las,Los Angeles]", "2"); |
| assertIntervalQuery("test_s_dv", "[Las,Los Angeles)", "1"); |
| assertIntervalQuery("test_s_dv", "[Las\\,,Los Angeles]", "1"); |
| } |
| |
| private int getNumberOfReaders() { |
| try { |
| return h.getCore().withSearcher(searcher -> searcher.getTopReaderContext().leaves().size()); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| |
| } |
| |
| @Test |
| public void testBasic() { |
| assertU(adoc("id", "1", "test_s_dv", "dog")); |
| assertU(adoc("id", "2", "test_s_dv", "cat")); |
| assertU(adoc("id", "3", "test_s_dv", "bird")); |
| assertU(adoc("id", "4", "test_s_dv", "turtle")); |
| assertU(adoc("id", "5", "test_s_dv", "\\goodbye,")); |
| assertU(adoc("id", "6", "test_s_dv", ",hello\\")); |
| assertU(adoc("id", "7", "test_s_dv", "dog")); |
| assertU(adoc("id", "8", "test_s_dv", "dog")); |
| assertU(adoc("id", "9", "test_s_dv", "cat")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertIntervalQueriesString("test_s_dv"); |
| |
| // error cases |
| assertQEx("missing beginning of range", |
| req("fl", "test_s_dv", "q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "bird,bird]"), |
| SolrException.ErrorCode.BAD_REQUEST |
| ); |
| assertQEx("only separator is escaped", |
| req("fl", "test_s_dv", "q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "(bird\\,turtle]"), |
| SolrException.ErrorCode.BAD_REQUEST |
| ); |
| assertQEx("missing separator", |
| req("fl", "test_s_dv", "q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "(bird]"), |
| SolrException.ErrorCode.BAD_REQUEST |
| ); |
| assertQEx("missing end of range", |
| req("fl", "test_s_dv", "q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "(bird,turtle"), |
| SolrException.ErrorCode.BAD_REQUEST |
| ); |
| } |
| |
| @Test |
| public void testMultipleFields() { |
| assertU(adoc("id", "1", "test_s_dv", "dog", "test_l_dv", "1")); |
| assertU(adoc("id", "2", "test_s_dv", "cat", "test_l_dv", "2")); |
| assertU(adoc("id", "3", "test_s_dv", "bird", "test_l_dv", "3")); |
| assertU(adoc("id", "4", "test_s_dv", "turtle", "test_l_dv", "4")); |
| assertU(adoc("id", "5", "test_s_dv", "\\goodbye,", "test_l_dv", "5")); |
| assertU(adoc("id", "6", "test_s_dv", ",hello\\", "test_l_dv", "6")); |
| assertU(adoc("id", "7", "test_s_dv", "dog", "test_l_dv", "7")); |
| assertU(adoc("id", "8", "test_s_dv", "dog", "test_l_dv", "8")); |
| assertU(adoc("id", "9", "test_s_dv", "cat", "test_l_dv", "9")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "facet.interval", "test_l_dv", "f.test_s_dv.facet.interval.set", "[cat,dog]", |
| "f.test_l_dv.facet.interval.set", "[3,6]", |
| "f.test_l_dv.facet.interval.set", "[5,9]"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[cat,dog]'][.=5]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[3,6]'][.=4]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[5,9]'][.=5]"); |
| |
| } |
| |
| @Test |
| public void testWithFieldCache() { |
| assertU(adoc("id", "1", "test_s", "dog", "test_l", "1")); |
| assertU(adoc("id", "2", "test_s", "cat", "test_l", "2")); |
| assertU(adoc("id", "3", "test_s", "bird", "test_l", "3")); |
| assertU(adoc("id", "4", "test_s", "turtle", "test_l", "4")); |
| assertU(adoc("id", "5", "test_s", "\\goodbye,", "test_l", "5")); |
| assertU(adoc("id", "6", "test_s", ",hello\\", "test_l", "6")); |
| assertU(adoc("id", "7", "test_s", "dog", "test_l", "7")); |
| assertU(adoc("id", "8", "test_s", "dog", "test_l", "8")); |
| assertU(adoc("id", "9", "test_s", "cat", "test_l", "9")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s", |
| "facet.interval", "test_l", "f.test_s.facet.interval.set", "[cat,dog]", |
| "f.test_l.facet.interval.set", "[3,6]", |
| "f.test_l.facet.interval.set", "[5,9]"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s']/int[@name='[cat,dog]'][.=5]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l']/int[@name='[3,6]'][.=4]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l']/int[@name='[5,9]'][.=5]"); |
| |
| } |
| |
| @Test |
| @Slow |
| public void testRandom() throws Exception { |
| // All field values will be a number between 0 and cardinality |
| int cardinality = 10000; |
| // Fields to use for interval faceting |
| String[] fields = new String[]{ |
| "test_s_dv", "test_i_dv", "test_l_dv", "test_f_dv", "test_d_dv", "test_dt_dv", |
| "test_ss_dv", "test_is_dv", "test_fs_dv", "test_ls_dv", "test_ds_dv", "test_dts_dv", "test_s", "test_i", |
| "test_l", "test_f", "test_d", "test_dt", "test_ss", "test_is", "test_fs", "test_ls", "test_ds", "test_dts", |
| "test_i_p", "test_is_p", "test_l_p", "test_ls_p", "test_f_p", "test_fs_p", "test_d_p", "test_ds_p", "test_dts_p" |
| }; |
| for (int i = 0; i < atLeast(500); i++) { |
| if (random().nextInt(50) == 0) { |
| //have some empty docs |
| assertU(adoc("id", String.valueOf(i))); |
| continue; |
| } |
| |
| if (random().nextInt(100) == 0 && i > 0) { |
| //delete some docs |
| assertU(delI(String.valueOf(i - 1))); |
| } |
| String[] docFields = new String[(random().nextInt(5)) * 12 + 14]; |
| docFields[0] = "id"; |
| docFields[1] = String.valueOf(i * (random().nextBoolean()?1:-1)); // in the queries we do positive and negative |
| docFields[2] = "test_s"; |
| docFields[3] = String.valueOf(randomInt(cardinality)); |
| docFields[4] = "test_i"; |
| docFields[5] = String.valueOf(randomInt(cardinality)); |
| docFields[6] = "test_l"; |
| docFields[7] = String.valueOf(randomLong(cardinality)); |
| docFields[8] = "test_f"; |
| docFields[9] = String.valueOf(randomFloat(cardinality)); |
| docFields[10] = "test_d"; |
| docFields[11] = String.valueOf(raondomDouble(cardinality)); |
| docFields[12] = "test_dt"; |
| docFields[13] = dateFormat.format(new Date(randomMs(cardinality))); |
| for (int j = 14; j < docFields.length; ) { |
| docFields[j++] = "test_ss"; |
| docFields[j++] = String.valueOf(randomInt(cardinality)); |
| docFields[j++] = "test_is"; |
| docFields[j++] = String.valueOf(randomInt(cardinality)); |
| docFields[j++] = "test_ls"; |
| docFields[j++] = String.valueOf(randomLong(cardinality)); |
| docFields[j++] = "test_fs"; |
| docFields[j++] = String.valueOf(randomFloat(cardinality)); |
| docFields[j++] = "test_ds"; |
| docFields[j++] = String.valueOf(raondomDouble(cardinality)); |
| docFields[j++] = "test_dts"; |
| docFields[j++] = dateFormat.format(new Date(randomMs(cardinality))); |
| } |
| assertU(adoc(docFields)); |
| if (random().nextInt(50) == 0) { |
| assertU(commit()); |
| } |
| } |
| assertU(commit()); |
| |
| for (int i = 0; i < atLeast(10000); i++) { |
| doTestQuery(cardinality, fields); |
| } |
| |
| } |
| |
| long randomMs(int cardinality) { |
| return DATE_START_TIME_RANDOM_TEST + random().nextInt(cardinality) * 1000 * (random().nextBoolean()?1:-1); |
| } |
| |
| double raondomDouble(int cardinality) { |
| if (rarely()) { |
| int num = random().nextInt(4); |
| if (num == 0) return Double.NEGATIVE_INFINITY; |
| if (num == 1) return Double.POSITIVE_INFINITY; |
| if (num == 2) return Double.MIN_VALUE; |
| if (num == 3) return Double.MAX_VALUE; |
| } |
| Double d = Double.NaN; |
| while (d.isNaN()) { |
| d = random().nextDouble(); |
| } |
| return d * cardinality * (random().nextBoolean()?1:-1); |
| } |
| |
| float randomFloat(int cardinality) { |
| if (rarely()) { |
| int num = random().nextInt(4); |
| if (num == 0) return Float.NEGATIVE_INFINITY; |
| if (num == 1) return Float.POSITIVE_INFINITY; |
| if (num == 2) return Float.MIN_VALUE; |
| if (num == 3) return Float.MAX_VALUE; |
| } |
| Float f = Float.NaN; |
| while (f.isNaN()) { |
| f = random().nextFloat(); |
| } |
| return f * cardinality * (random().nextBoolean()?1:-1); |
| } |
| |
| int randomInt(int cardinality) { |
| if (rarely()) { |
| int num = random().nextInt(2); |
| if (num == 0) return Integer.MAX_VALUE; |
| if (num == 1) return Integer.MIN_VALUE; |
| } |
| return random().nextInt(cardinality) * (random().nextBoolean()?1:-1); |
| } |
| |
| long randomLong(int cardinality) { |
| if (rarely()) { |
| int num = random().nextInt(2); |
| if (num == 0) return Long.MAX_VALUE; |
| if (num == 1) return Long.MIN_VALUE; |
| } |
| return randomInt(cardinality); |
| } |
| |
| /** |
| * Executes one query using interval faceting and compares with the same query using |
| * facet query with the same range |
| */ |
| @SuppressWarnings("unchecked") |
| private void doTestQuery(int cardinality, String[] fields) throws Exception { |
| String[] startOptions = new String[]{"(", "["}; |
| String[] endOptions = new String[]{")", "]"}; |
| ModifiableSolrParams params = new ModifiableSolrParams(); |
| if (rarely()) { |
| params.set("q", "*:*"); |
| } else { |
| // the query should match some documents in most cases |
| String[] qRange = getRandomRange(cardinality, "id"); |
| params.set("q", "id:[" + qRange[0] + " TO " + qRange[1] + "]"); |
| } |
| params.set("facet", "true"); |
| String field = pickRandom(fields); //choose from any of the fields |
| params.set("facet.interval", field); |
| // number of intervals |
| for (int i = 0; i < 1 + random().nextInt(20); i++) { |
| String[] interval = getRandomRange(cardinality, field); |
| String open = pickRandom(startOptions); |
| String close = pickRandom(endOptions); |
| params.add("f." + field + ".facet.interval.set", open + interval[0] + "," + interval[1] + close); |
| params.add("facet.query", field + ":" + open.replace('(', '{') + interval[0] + " TO " + interval[1] + close.replace(')', '}')); |
| } |
| SolrQueryRequest req = req(params); |
| try { |
| SolrQueryResponse rsp = h.queryAndResponse("", req); |
| NamedList<Object> facetQueries = (NamedList<Object>) ((NamedList<Object>) rsp.getValues().get("facet_counts")).get("facet_queries"); |
| NamedList<Object> facetIntervals = (NamedList<Object>) ((NamedList<Object>) ((NamedList<Object>) rsp.getValues().get("facet_counts")) |
| .get("facet_intervals")).get(field); |
| assertEquals("Responses don't have the same number of facets: \n" + facetQueries + "\n" + facetIntervals, |
| facetQueries.size(), getCountDistinctIntervals(facetIntervals)); |
| for (int i = 0; i < facetIntervals.size(); i++) { |
| assertEquals("Interval did not match: " + field + ": " + facetIntervals.getName(i) + "\nResponse: " + rsp.getValues().get("facet_counts"), |
| facetQueries.get(field + ":" + facetIntervals.getName(i).replace(",", " TO ").replace('(', '{').replace(')', '}')).toString(), |
| facetIntervals.getVal(i).toString()); |
| } |
| } finally { |
| req.close(); |
| } |
| |
| } |
| |
| private int getCountDistinctIntervals(NamedList<Object> facetIntervals) { |
| Set<String> distinctIntervals = new HashSet<>(facetIntervals.size()); |
| for (int i = 0; i < facetIntervals.size(); i++) { |
| distinctIntervals.add(facetIntervals.getName(i)); |
| } |
| return distinctIntervals.size(); |
| } |
| |
| /** |
| * Returns a random range. It's guaranteed that the first |
| * number will be lower than the second. The range could have values greater than "max", |
| * for example [Integer/Long/Float/Double].[MIN/MAX_VALUE,POSITIVE/NEGATIVE_INFINITY] |
| * If the fieldName is "test_s_dv" or "test_ss_dv" (the |
| * two fields used for Strings), the comparison will be done |
| * alphabetically |
| * If the field is a Date, a date range will be returned |
| * The range could also contain "*" as beginning and/or end of the range |
| */ |
| private String[] getRandomRange(int max, String fieldName) { |
| Number[] values = new Number[2]; |
| FieldType ft = h.getCore().getLatestSchema().getField(fieldName).getType(); |
| if (ft.getNumberType() == null) { |
| assert ft instanceof StrField; |
| values[0] = randomInt(max); |
| values[1] = randomInt(max); |
| Arrays.sort(values, (o1, o2) -> String.valueOf(o1).compareTo(String.valueOf(o2))); |
| } else { |
| switch (ft.getNumberType()) { |
| case DOUBLE: |
| values[0] = raondomDouble(max); |
| values[1] = raondomDouble(max); |
| break; |
| case FLOAT: |
| values[0] = randomFloat(max); |
| values[1] = randomFloat(max); |
| break; |
| case INTEGER: |
| values[0] = randomInt(max); |
| values[1] = randomInt(max); |
| break; |
| case LONG: |
| values[0] = randomLong(max); |
| values[1] = randomLong(max); |
| break; |
| case DATE: |
| values[0] = randomMs(max); |
| values[1] = randomMs(max); |
| break; |
| default: |
| throw new AssertionError("Unexpected number type"); |
| |
| } |
| Arrays.sort(values); |
| } |
| String[] stringValues = new String[2]; |
| if (rarely()) { |
| stringValues[0] = "*"; |
| } else { |
| if (ft.getNumberType() == NumberType.DATE) { |
| stringValues[0] = dateFormat.format(values[0]); |
| } else { |
| stringValues[0] = String.valueOf(values[0]); |
| } |
| } |
| if (rarely()) { |
| stringValues[1] = "*"; |
| } else { |
| if (ft.getNumberType() == NumberType.DATE) { |
| stringValues[1] = dateFormat.format(values[1]); |
| } else { |
| stringValues[1] = String.valueOf(values[1]); |
| } |
| } |
| return stringValues; |
| } |
| |
| @Test |
| public void testParse() throws SyntaxError { |
| assertInterval("test_l_dv", "(0,2)", new long[]{1}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "(0,2]", new long[]{1, 2}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "[0,2]", new long[]{0, 1, 2}, new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "[0,2)", new long[]{0, 1}, new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| |
| assertInterval("test_l_dv", "(0,*)", new long[]{1, 2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}, new long[]{-1, 0, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{}); |
| assertInterval("test_l_dv", "(*,2)", new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE, 0, 1}, new long[]{}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "(*,*)", new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE, 0, 1, 2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}, new long[]{}, new long[]{}); |
| |
| assertInterval("test_l_dv", "[0,*]", new long[]{0, 1, 2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}, new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{}); |
| assertInterval("test_l_dv", "[*,2]", new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE, 0, 1, 2}, new long[]{}, new long[]{3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "[*,*]", new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE, 0, 1, 2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}, new long[]{}, new long[]{}); |
| |
| assertInterval("test_l_dv", "(2,2)", new long[]{}, new long[]{2, 1, 0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "(0,0)", new long[]{}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{1, 2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| |
| assertInterval("test_l_dv", "(0," + Long.MAX_VALUE + "]", new long[]{1, 2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{}); |
| assertInterval("test_l_dv", "(0," + Long.MAX_VALUE + ")", new long[]{1, 2, 3, Integer.MAX_VALUE}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "(" + Long.MIN_VALUE + ",0)", new long[]{-1, Integer.MIN_VALUE}, new long[]{Long.MIN_VALUE}, new long[]{1, 2, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "[" + Long.MIN_VALUE + ",0)", new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{}, new long[]{1, 2, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "[" + Long.MIN_VALUE + "," + Long.MAX_VALUE + "]", new long[]{-1, Integer.MIN_VALUE, Long.MIN_VALUE, 1, 2, Integer.MAX_VALUE, Long.MAX_VALUE}, new long[]{}, new long[]{}); |
| assertInterval("test_l_dv", "(" + Long.MIN_VALUE + "," + Long.MAX_VALUE + ")", new long[]{-1, Integer.MIN_VALUE, 1, 2, Integer.MAX_VALUE}, new long[]{Long.MIN_VALUE}, new long[]{Long.MAX_VALUE}); |
| |
| assertInterval("test_l_dv", "( 0,2)", new long[]{1}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "( 0,2)", new long[]{1}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "(0, 2)", new long[]{1}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", "( 0 , 2 )", new long[]{1}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| assertInterval("test_l_dv", " ( 0 , 2 ) ", new long[]{1}, new long[]{0, -1, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| |
| assertInterval("test_l_dv", "[-1,1]", new long[]{-1, 0, 1}, new long[]{-2, Integer.MIN_VALUE, Long.MIN_VALUE}, new long[]{2, 3, Integer.MAX_VALUE, Long.MAX_VALUE}); |
| |
| assertStringInterval("test_s_dv", "[A,B]", "A", "B"); |
| assertStringInterval("test_s_dv", "[A,b]", "A", "b"); |
| assertStringInterval("test_s_dv", "[A\\,,B]", "A,", "B"); |
| assertStringInterval("test_s_dv", "[A\\),B]", "A)", "B"); |
| assertStringInterval("test_s_dv", "['A',B]", "'A'", "B"); |
| assertStringInterval("test_s_dv", "[\"A\",B]", "\"A\"", "B"); |
| assertStringInterval("test_s_dv", "[A B C,B]", "A B C", "B"); |
| assertStringInterval("test_s_dv", "[ A B C ,B]", "A B C", "B"); |
| // These two are currently not possible |
| // assertStringInterval("test_s_dv", "[\\ A B C ,B]", " A B C", "B"); |
| // assertStringInterval("test_s_dv", "[\\*,B]", "*", "B"); |
| |
| //invalid intervals |
| assertBadInterval("test_l_dv", "0,2)", "Invalid start character"); |
| assertBadInterval("test_l_dv", "{0,2)", "Invalid start character"); |
| assertBadInterval("test_l_dv", "(0,2", "Invalid end character"); |
| assertBadInterval("test_l_dv", "(0,2}", "Invalid end character"); |
| assertBadInterval("test_l_dv", "(0, )", "Empty interval limit"); |
| assertBadInterval("test_l_dv", "(0)", "Missing unescaped comma separating interval"); |
| assertBadInterval("test_l_dv", "(,0)", "Empty interval limit"); |
| assertBadInterval("test_l_dv", "(0 2)", "Missing unescaped comma separating interval"); |
| assertBadInterval("test_l_dv", "(0 TO 2)", "Missing unescaped comma separating interval"); |
| assertBadInterval("test_l_dv", "(0 \\, 2)", "Missing unescaped comma separating interval"); |
| assertBadInterval("test_l_dv", "(A, 2)", "Invalid start interval for key"); |
| assertBadInterval("test_l_dv", "(2, A)", "Invalid end interval for key"); |
| assertBadInterval("test_l_dv", "(0,)", "Empty interval limit"); |
| assertBadInterval("test_l_dv", "(0,-1)", "Start is higher than end in interval for key"); |
| |
| assertBadInterval("test_s_dv", "A,B)", "Invalid start character"); |
| assertBadInterval("test_s_dv", "(B,A)", "Start is higher than end in interval for key"); |
| assertBadInterval("test_s_dv", "(a,B)", "Start is higher than end in interval for key"); |
| |
| assertIntervalKey("test_s_dv", "[A,B]", "[A,B]"); |
| assertIntervalKey("test_s_dv", "(A,*]", "(A,*]"); |
| assertIntervalKey("test_s_dv", "{!}(A,*]", "(A,*]"); |
| assertIntervalKey("test_s_dv", "{!key=foo}(A,*]", "foo"); |
| assertIntervalKey("test_s_dv", "{!key='foo'}(A,*]", "foo"); |
| assertIntervalKey("test_s_dv", "{!key='foo bar'}(A,*]", "foo bar"); |
| assertIntervalKey("test_s_dv", "{!key='foo' bar}(A,*]", "foo"); |
| assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "foo", "i", "foo"); |
| assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "foo bar", "i", "foo bar"); |
| assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "'foo'", "i", "'foo'"); |
| assertIntervalKey("test_s_dv", "{!key=$i}(A,*]", "\"foo\"", "i", "\"foo\""); |
| assertIntervalKey("test_s_dv", "{!key='[A,B]'}(A,B)", "[A,B]"); |
| assertIntervalKey("test_s_dv", "{!key='\\{\\{\\{'}(A,B)", "{{{"); |
| assertIntervalKey("test_s_dv", "{!key='\\{A,B\\}'}(A,B)", "{A,B}"); |
| assertIntervalKey("test_s_dv", "{!key='\"A,B\"'}(A,B)", "\"A,B\""); |
| assertIntervalKey("test_s_dv", "{!key='A..B'}(A,B)", "A..B"); |
| assertIntervalKey("test_s_dv", "{!key='A TO B'}(A,B)", "A TO B"); |
| |
| |
| assertU(adoc("id", "1", "test_s_dv", "dog", "test_l_dv", "1")); |
| assertU(adoc("id", "2", "test_s_dv", "cat", "test_l_dv", "2")); |
| assertU(adoc("id", "3", "test_s_dv", "bird", "test_l_dv", "3")); |
| assertU(adoc("id", "4", "test_s_dv", "turtle", "test_l_dv", "4")); |
| assertU(adoc("id", "5", "test_s_dv", "\\goodbye,", "test_l_dv", "5")); |
| assertU(adoc("id", "6", "test_s_dv", ",hello\\", "test_l_dv", "6")); |
| assertU(adoc("id", "7", "test_s_dv", "dog", "test_l_dv", "7")); |
| assertU(adoc("id", "8", "test_s_dv", "dog", "test_l_dv", "8")); |
| assertU(adoc("id", "9", "test_s_dv", "cat", "test_l_dv", "9")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| // facet.interval not set |
| assertQ(req("q", "*:*", "facet", "true", |
| "f.test_s_dv.facet.interval.set", "[cat,dog]", |
| "f.test_l_dv.facet.interval.set", "[3,6]", |
| "f.test_l_dv.facet.interval.set", "[5,9]"), |
| "count(//lst[@name='facet_intervals']/lst)=0"); |
| |
| // facet.interval only on one of the fields |
| assertQ(req("q", "*:*", "facet", "true", |
| "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "[cat,dog]", |
| "f.test_l_dv.facet.interval.set", "[3,6]", |
| "f.test_l_dv.facet.interval.set", "[5,9]"), |
| "count(//lst[@name='facet_intervals']/lst)=1", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[cat,dog]'][.=5]"); |
| |
| // existing fields in facet.interval with no intervals defined |
| assertQEx("Unexpected exception", |
| "Missing required parameter: f.test_l_dv.facet.interval.set (or default: facet.interval.set)", |
| req("q", "*:*", "facet", "true", |
| "facet.interval", "test_s_dv", |
| "facet.interval", "test_l_dv", |
| "f.test_s_dv.facet.interval.set", "[cat,dog]"), |
| SolrException.ErrorCode.BAD_REQUEST); |
| |
| // use of facet.interval.set |
| assertQ(req("q", "*:*", "facet", "true", |
| "facet.interval", "test_s_dv", |
| "facet.interval", "test_l_dv", |
| "facet.interval.set", "[1,2]"), |
| "count(//lst[@name='facet_intervals']/lst)=2", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[1,2]'][.=0]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[1,2]'][.=2]" |
| ); |
| |
| // multiple facet.interval.set |
| assertQ(req("q", "*:*", "facet", "true", |
| "facet.interval", "test_s_dv", |
| "facet.interval", "test_l_dv", |
| "facet.interval.set", "[1,2]", |
| "facet.interval.set", "[2,3]", |
| "facet.interval.set", "[3,4]"), |
| "count(//lst[@name='facet_intervals']/lst)=2", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[1,2]'][.=0]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[2,3]'][.=0]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[3,4]'][.=0]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[1,2]'][.=2]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[2,3]'][.=2]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[3,4]'][.=2]" |
| ); |
| |
| // use of facet.interval.set and override |
| assertQ(req("q", "*:*", "facet", "true", |
| "facet.interval", "test_s_dv", |
| "facet.interval", "test_l_dv", |
| "facet.interval.set", "[1,2]", |
| "f.test_l_dv.facet.interval.set", "[3,4]", |
| "f.test_l_dv.facet.interval.set", "[4,5]"), |
| "count(//lst[@name='facet_intervals']/lst)=2", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[1,2]'][.=0]", |
| "count(//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int)=2", // interval [1,2] not present |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[3,4]'][.=2]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[4,5]'][.=2]" |
| ); |
| |
| assertQ(req("q", "*:*", "facet", "true", |
| "facet.interval", "test_s_dv", |
| "facet.interval", "test_l_dv", |
| "facet.interval.set", "[1,2]", |
| "facet.interval.set", "[2,3]", |
| "facet.interval.set", "[3,4]", |
| "f.test_s_dv.facet.interval.set", "[cat,dog]"), |
| "count(//lst[@name='facet_intervals']/lst)=2", |
| "count(//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int)=1", // only [cat,dog] in test_s_dv |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[cat,dog]'][.=5]", |
| "count(//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int)=3", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[1,2]'][.=2]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[2,3]'][.=2]", |
| "//lst[@name='facet_intervals']/lst[@name='test_l_dv']/int[@name='[3,4]'][.=2]" |
| ); |
| |
| // use of facet.interval.set with wrong field type |
| assertQEx("Unexpected Exception", |
| "Invalid start interval", |
| req("q", "*:*", "facet", "true", |
| "facet.interval", "test_l_dv", |
| "f.test_l_dv.facet.interval.set", "[cat,dog]"), |
| SolrException.ErrorCode.BAD_REQUEST); |
| |
| } |
| |
| private void assertStringInterval(String fieldName, String intervalStr, |
| String expectedStart, String expectedEnd) throws SyntaxError { |
| SchemaField f = h.getCore().getLatestSchema().getField(fieldName); |
| FacetInterval interval = new FacetInterval(f, intervalStr, new ModifiableSolrParams()); |
| |
| assertEquals("Expected start " + expectedStart + " but found " + f.getType().toObject(f, interval.start), |
| interval.start, new BytesRef(f.getType().toInternal(expectedStart))); |
| |
| assertEquals("Expected end " + expectedEnd + " but found " + f.getType().toObject(f, interval.end), |
| interval.end, new BytesRef(f.getType().toInternal(expectedEnd))); |
| } |
| |
| private void assertBadInterval(String fieldName, String intervalStr, String errorMsg) { |
| SchemaField f = h.getCore().getLatestSchema().getField(fieldName); |
| SyntaxError e = expectThrows(SyntaxError.class, () -> new FacetInterval(f, intervalStr, new ModifiableSolrParams())); |
| assertTrue("Unexpected error message for interval String: " + intervalStr + ": " + |
| e.getMessage(), e.getMessage().contains(errorMsg)); |
| } |
| |
| private void assertInterval(String fieldName, String intervalStr, long[] included, long[] lowerThanStart, long[] graterThanEnd) throws SyntaxError { |
| SchemaField f = h.getCore().getLatestSchema().getField(fieldName); |
| FacetInterval interval = new FacetInterval(f, intervalStr, new ModifiableSolrParams()); |
| for (long l : included) { |
| assertEquals("Value " + l + " should be INCLUDED for interval" + interval, |
| IntervalCompareResult.INCLUDED, interval.includes(l)); |
| } |
| for (long l : lowerThanStart) { |
| assertEquals("Value " + l + " should be LOWER_THAN_START for inteval " + interval, |
| IntervalCompareResult.LOWER_THAN_START, interval.includes(l)); |
| } |
| for (long l : graterThanEnd) { |
| assertEquals("Value " + l + " should be GRATER_THAN_END for inteval " + interval, |
| IntervalCompareResult.GREATER_THAN_END, interval.includes(l)); |
| } |
| |
| } |
| |
| private void assertIntervalKey(String fieldName, String intervalStr, |
| String expectedKey, String...params) throws SyntaxError { |
| assert (params.length&1)==0:"Params must have an even number of elements"; |
| SchemaField f = h.getCore().getLatestSchema().getField(fieldName); |
| ModifiableSolrParams solrParams = new ModifiableSolrParams(); |
| for (int i = 0; i < params.length - 1;) { |
| solrParams.set(params[i], params[i+1]); |
| i+=2; |
| } |
| FacetInterval interval = new FacetInterval(f, intervalStr, solrParams); |
| |
| assertEquals("Expected key " + expectedKey + " but found " + interval.getKey(), |
| expectedKey, interval.getKey()); |
| } |
| |
| public void testChangeKey() { |
| assertU(adoc("id", "1", "test_s_dv", "dog")); |
| assertU(adoc("id", "2", "test_s_dv", "cat")); |
| assertU(adoc("id", "3", "test_s_dv", "bird")); |
| assertU(adoc("id", "4", "test_s_dv", "cat")); |
| assertU(adoc("id", "5", "test_s_dv", "turtle")); |
| assertU(adoc("id", "6", "test_s_dv", "dog")); |
| assertU(adoc("id", "7", "test_s_dv", "dog")); |
| assertU(adoc("id", "8", "test_s_dv", "dog")); |
| assertU(adoc("id", "9", "test_s_dv", "cat")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "{!key=foo}[bird,bird]", |
| "f.test_s_dv.facet.interval.set", "{!key='bar'}(bird,dog)"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo'][.=1]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='bar'][.=3]"); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "{!key=Birds}[bird,bird]", |
| "f.test_s_dv.facet.interval.set", "{!key='foo bar'}(bird,dog)"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='Birds'][.=1]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo bar'][.=3]"); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "{!key=$p}[bird,bird]", |
| "p", "foo bar"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo bar'][.=1]"); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", |
| "f.test_s_dv.facet.interval.set", "{!key='[bird,\\}'}[bird,*]", |
| "f.test_s_dv.facet.interval.set", "{!key='\\{bird,dog\\}'}(bird,dog)", |
| "f.test_s_dv.facet.interval.set", "{!key='foo'}(bird,dog})"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[bird,}'][.=9]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='{bird,dog}'][.=3]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='foo'][.=7]"); |
| |
| } |
| |
| @Test |
| public void testLongFields() { |
| assertU(adoc("id", "1", "test_l_dv", "0")); |
| assertU(adoc("id", "2", "test_l_dv", "1")); |
| assertU(adoc("id", "3", "test_l_dv", "2")); |
| assertU(adoc("id", "4", "test_l_dv", "3")); |
| assertU(adoc("id", "5", "test_l_dv", "4")); |
| assertU(adoc("id", "6", "test_l_dv", "5")); |
| assertU(adoc("id", "7", "test_l_dv", "6")); |
| assertU(adoc("id", "8", "test_l_dv", "7")); |
| assertU(adoc("id", "9", "test_l_dv", "8")); |
| assertU(adoc("id", "10")); |
| assertU(adoc("id", "11", "test_l_dv", "10")); |
| assertU(commit()); |
| |
| assertIntervalQueriesNumeric("test_l_dv"); |
| assertU(adoc("id", "12", "test_l_dv", String.valueOf(Long.MAX_VALUE - 3))); |
| assertU(adoc("id", "13", "test_l_dv", String.valueOf(Long.MAX_VALUE - 2))); |
| assertU(adoc("id", "14", "test_l_dv", String.valueOf(Long.MAX_VALUE - 1))); |
| assertU(adoc("id", "15", "test_l_dv", String.valueOf(Long.MAX_VALUE))); |
| assertU(adoc("id", "16", "test_l_dv", String.valueOf(Long.MIN_VALUE))); |
| assertU(commit()); |
| |
| assertIntervalQuery("test_l_dv", "[0," + Integer.MAX_VALUE + "]", "10"); |
| assertIntervalQuery("test_l_dv", "(10," + Long.MAX_VALUE + "]", "4"); |
| assertIntervalQuery("test_l_dv", "[" + Long.MAX_VALUE + "," + Long.MAX_VALUE + "]", "1"); |
| assertIntervalQuery("test_l_dv", "[" + Long.MAX_VALUE + ",*]", "1"); |
| assertIntervalQuery("test_l_dv", "(" + Long.MAX_VALUE + ",*]", "0"); |
| assertIntervalQuery("test_l_dv", "(*, " + Long.MIN_VALUE + "]", "1"); |
| assertIntervalQuery("test_l_dv", "(*, " + Long.MIN_VALUE + ")", "0"); |
| assertIntervalQuery("test_l_dv", "(" + (Long.MAX_VALUE - 1) + ",*]", "1"); |
| assertIntervalQuery("test_l_dv", "[" + (Long.MAX_VALUE - 1) + ",*]", "2"); |
| } |
| |
| @Test |
| public void testFloatFields() { |
| doTestFloat("test_f_dv", false); |
| } |
| |
| private void doTestFloat(String field, boolean testDouble) { |
| assertU(adoc("id", "1", field, "0")); |
| assertU(adoc("id", "2", field, "1")); |
| assertU(adoc("id", "3", field, "2")); |
| assertU(adoc("id", "4", field, "3")); |
| assertU(adoc("id", "5", field, "4")); |
| assertU(adoc("id", "6", field, "5")); |
| assertU(adoc("id", "7", field, "6")); |
| assertU(adoc("id", "8", field, "7")); |
| assertU(adoc("id", "9", field, "8")); |
| assertU(adoc("id", "10")); |
| assertU(adoc("id", "11", field, "10")); |
| assertU(commit()); |
| |
| assertIntervalQueriesNumeric(field); |
| |
| assertU(adoc("id", "12", field, "1.3")); |
| assertU(adoc("id", "13", field, "4.5")); |
| assertU(adoc("id", "14", field, "6.7")); |
| assertU(adoc("id", "15", field, "123.45")); |
| assertU(commit()); |
| |
| assertIntervalQuery(field, "[0," + Integer.MAX_VALUE + "]", "14"); |
| assertIntervalQuery(field, "[0,1]", "2"); |
| assertIntervalQuery(field, "[0,2]", "4"); |
| assertIntervalQuery(field, "(1,2)", "1"); |
| assertIntervalQuery(field, "(1,1)", "0"); |
| assertIntervalQuery(field, "(4,7)", "4"); |
| assertIntervalQuery(field, "(123,*)", "1"); |
| |
| clearIndex(); |
| assertU(adoc("id", "16", field, "-1.3")); |
| assertU(adoc("id", "17", field, "0.0")); |
| assertU(adoc("id", "18", field, "-0.0")); |
| assertU(adoc("id", "19", field, String.valueOf(Float.MIN_VALUE))); |
| assertU(adoc("id", "20", field, String.valueOf(Float.MAX_VALUE))); |
| assertU(adoc("id", "21", field, String.valueOf(Float.NEGATIVE_INFINITY))); |
| assertU(adoc("id", "22", field, String.valueOf(Float.POSITIVE_INFINITY))); |
| assertU(commit()); |
| |
| assertIntervalQuery(field, "[*,*]", "7"); |
| assertIntervalQuery(field, "(*,*)", "7"); |
| assertIntervalQuery(field, "(-1,1)", "3"); |
| assertIntervalQuery(field, "(-2,1)", "4"); |
| assertIntervalQuery(field, "(-1.3,0)", "1"); |
| assertIntervalQuery(field, "[-1.3,0)", "2"); |
| assertIntervalQuery(field, "[-1.3,0]", "3"); |
| assertIntervalQuery(field, "(" + Float.NEGATIVE_INFINITY + ",0)", "2"); |
| assertIntervalQuery(field, "(* ,0)", "3"); |
| assertIntervalQuery(field, "[" + Float.NEGATIVE_INFINITY + ",0)", "3"); |
| assertIntervalQuery(field, "(0, " + Float.MIN_VALUE + ")", "0"); |
| assertIntervalQuery(field, "(0, " + Float.MIN_VALUE + "]", "1"); |
| assertIntervalQuery(field, "(0, " + Float.MAX_VALUE + ")", "1"); |
| assertIntervalQuery(field, "(0, " + Float.MAX_VALUE + "]", "2"); |
| assertIntervalQuery(field, "(0, " + Float.POSITIVE_INFINITY + ")", "2"); |
| assertIntervalQuery(field, "(0, " + Float.POSITIVE_INFINITY + "]", "3"); |
| assertIntervalQuery(field, "[-0.0, 0.0]", "2"); |
| assertIntervalQuery(field, "[-0.0, 0.0)", "1"); |
| assertIntervalQuery(field, "(-0.0, 0.0]", "1"); |
| |
| if (testDouble) { |
| clearIndex(); |
| assertU(adoc("id", "16", field, "-1.3")); |
| assertU(adoc("id", "17", field, "0.0")); |
| assertU(adoc("id", "18", field, "-0.0")); |
| assertU(adoc("id", "19", field, String.valueOf(Double.MIN_VALUE))); |
| assertU(adoc("id", "20", field, String.valueOf(Double.MAX_VALUE))); |
| assertU(adoc("id", "21", field, String.valueOf(Double.NEGATIVE_INFINITY))); |
| assertU(adoc("id", "22", field, String.valueOf(Double.POSITIVE_INFINITY))); |
| assertU(commit()); |
| |
| assertIntervalQuery(field, "[*,*]", "7"); |
| assertIntervalQuery(field, "(*,*)", "7"); |
| assertIntervalQuery(field, "(-1,1)", "3"); |
| assertIntervalQuery(field, "(-2,1)", "4"); |
| assertIntervalQuery(field, "(-1.3,0)", "1"); |
| assertIntervalQuery(field, "[-1.3,0)", "2"); |
| assertIntervalQuery(field, "[-1.3,0]", "3"); |
| assertIntervalQuery(field, "(" + Double.NEGATIVE_INFINITY + ",0)", "2"); |
| assertIntervalQuery(field, "(* ,0)", "3"); |
| assertIntervalQuery(field, "[" + Double.NEGATIVE_INFINITY + ",0)", "3"); |
| assertIntervalQuery(field, "(0, " + Double.MIN_VALUE + ")", "0"); |
| assertIntervalQuery(field, "(0, " + Double.MIN_VALUE + "]", "1"); |
| assertIntervalQuery(field, "(0, " + Double.MAX_VALUE + ")", "1"); |
| assertIntervalQuery(field, "(0, " + Double.MAX_VALUE + "]", "2"); |
| assertIntervalQuery(field, "(0, " + Double.POSITIVE_INFINITY + ")", "2"); |
| assertIntervalQuery(field, "(0, " + Double.POSITIVE_INFINITY + "]", "3"); |
| } |
| } |
| |
| @Test |
| public void testDoubleFields() { |
| doTestFloat("test_d_dv", true); |
| } |
| |
| @Test |
| public void testIntFields() { |
| assertU(adoc("id", "1", "test_i_dv", "0")); |
| assertU(adoc("id", "2", "test_i_dv", "1")); |
| assertU(adoc("id", "3", "test_i_dv", "2")); |
| assertU(adoc("id", "4", "test_i_dv", "3")); |
| assertU(adoc("id", "5", "test_i_dv", "4")); |
| assertU(adoc("id", "6", "test_i_dv", "5")); |
| assertU(adoc("id", "7", "test_i_dv", "6")); |
| assertU(adoc("id", "8", "test_i_dv", "7")); |
| assertU(adoc("id", "9", "test_i_dv", "8")); |
| assertU(adoc("id", "10")); |
| assertU(adoc("id", "11", "test_i_dv", "10")); |
| assertU(commit()); |
| |
| assertIntervalQueriesNumeric("test_i_dv"); |
| } |
| |
| @Test |
| public void testIntFieldsMultipleSegments() { |
| assertU(adoc("id", "1", "test_i_dv", "0")); |
| assertU(adoc("id", "2", "test_i_dv", "1")); |
| assertU(adoc("id", "3", "test_i_dv", "2")); |
| assertU(commit()); |
| assertU(adoc("id", "4", "test_i_dv", "3")); |
| assertU(adoc("id", "5", "test_i_dv", "4")); |
| assertU(adoc("id", "6", "test_i_dv", "5")); |
| assertU(adoc("id", "7", "test_i_dv", "6")); |
| assertU(commit()); |
| assertU(adoc("id", "8", "test_i_dv", "7")); |
| assertU(adoc("id", "9", "test_i_dv", "8")); |
| assertU(adoc("id", "10")); |
| assertU(adoc("id", "11", "test_i_dv", "10")); |
| assertU(commit()); |
| |
| int i = 12; |
| while (getNumberOfReaders() < 2 && i < 20) { |
| //try to get more than one segment |
| assertU(adoc("id", String.valueOf(i), "test_s_dv", String.valueOf(i))); |
| assertU(commit()); |
| i++; |
| } |
| if (getNumberOfReaders() < 2) { |
| // It is OK if for some seeds we fall into this case (for example, TieredMergePolicy with |
| // segmentsPerTier=2). Most of the case we shouldn't and the test should proceed. |
| log.warn("Could not generate more than 1 segment for this seed. Will skip the test"); |
| return; |
| } |
| |
| assertIntervalQueriesNumeric("test_i_dv"); |
| } |
| |
| @Test |
| public void testIntMultivaluedFields() { |
| assertU(adoc("id", "1", "test_is_dv", "0")); |
| assertU(adoc("id", "2", "test_is_dv", "1")); |
| assertU(adoc("id", "3", "test_is_dv", "2")); |
| assertU(adoc("id", "4", "test_is_dv", "3")); |
| assertU(adoc("id", "5", "test_is_dv", "4")); |
| assertU(adoc("id", "6", "test_is_dv", "5")); |
| assertU(adoc("id", "7", "test_is_dv", "6")); |
| assertU(adoc("id", "8", "test_is_dv", "7")); |
| assertU(adoc("id", "9", "test_is_dv", "8")); |
| assertU(adoc("id", "10")); |
| assertU(adoc("id", "11", "test_is_dv", "10")); |
| assertU(commit()); |
| |
| assertIntervalQueriesNumeric("test_is_dv"); |
| |
| assertU(adoc("id", "1", "test_is_dv", "0", "test_is_dv", "1", "test_is_dv", "2", "test_is_dv", "3")); |
| assertU(adoc("id", "2", "test_is_dv", "1", "test_is_dv", "2", "test_is_dv", "3", "test_is_dv", "4")); |
| assertU(adoc("id", "3", "test_is_dv", "2", "test_is_dv", "3", "test_is_dv", "4", "test_is_dv", "5")); |
| assertU(adoc("id", "4", "test_is_dv", "3", "test_is_dv", "4", "test_is_dv", "5", "test_is_dv", "6")); |
| assertU(commit()); |
| |
| assertIntervalQuery("test_is_dv", "[1,3]", "4"); |
| assertIntervalQuery("test_is_dv", "[3,3]", "4"); |
| assertIntervalQuery("test_is_dv", "[5,9]", "6"); |
| assertIntervalQuery("test_is_dv", "(5,9)", "4"); |
| assertIntervalQuery("test_is_dv", "[*,*]", "10"); |
| } |
| |
| @Test |
| public void testDateFields() { |
| assertU(adoc("id", "1", "test_dt_dv", "2013-01-01T00:00:00Z")); |
| assertU(adoc("id", "2", "test_dt_dv", "2013-01-02T00:00:00Z")); |
| assertU(adoc("id", "3", "test_dt_dv", "2013-02-01T00:00:00Z")); |
| assertU(adoc("id", "4", "test_dt_dv", "2014-01-01T00:00:00Z")); |
| assertU(adoc("id", "5", "test_dt_dv", "2100-01-01T00:00:00Z")); |
| assertU(adoc("id", "6", "test_dt_dv", "2013-01-01T10:00:00Z")); |
| assertU(adoc("id", "7", "test_dt_dv", "2013-01-01T00:10:00Z")); |
| assertU(adoc("id", "8", "test_dt_dv", "2013-01-01T00:00:10Z")); |
| assertU(adoc("id", "9")); |
| assertU(commit()); |
| |
| assertIntervalQuery("test_dt_dv", "[*,*]", "8"); |
| assertIntervalQuery("test_dt_dv", "[*,2014-01-01T00:00:00Z]", "7"); |
| assertIntervalQuery("test_dt_dv", "[*,2014-01-01T00:00:00Z)", "6"); |
| assertIntervalQuery("test_dt_dv", "[*,2014-01-01T00:00:00.001Z)", "7"); |
| assertIntervalQuery("test_dt_dv", "[*,2013-12-31T23:59:59.999Z]", "6"); |
| assertIntervalQuery("test_dt_dv", "[2013-12-31T23:59:59.9999Z,2014-01-01T00:00:00.001Z]", "1"); |
| |
| assertIntervalQuery("test_dt_dv", "[NOW,*]", "1"); |
| assertIntervalQuery("test_dt_dv", "[*,NOW]", "7"); |
| |
| assertU(adoc("id", "5", "test_dt_dv", "NOW")); |
| assertU(commit()); |
| assertIntervalQuery("test_dt_dv", "[NOW/DAY-1DAY,NOW+2DAY]", "1"); |
| |
| } |
| |
| @Test |
| public void testWithDeletedDocs() { |
| assertU(adoc("id", "1", "test_s_dv", "dog")); |
| assertU(adoc("id", "2", "test_s_dv", "cat")); |
| assertU(adoc("id", "3", "test_s_dv", "bird")); |
| assertU(adoc("id", "16", "test_s_dv", "cat")); |
| assertU(adoc("id", "4", "test_s_dv", "turtle")); |
| assertU(adoc("id", "5", "test_s_dv", "\\goodbye,")); |
| assertU(adoc("id", "6", "test_s_dv", ",hello\\")); |
| assertU(adoc("id", "7", "test_s_dv", "dog")); |
| assertU(adoc("id", "15", "test_s_dv", "dog")); |
| assertU(adoc("id", "8", "test_s_dv", "dog")); |
| assertU(adoc("id", "9", "test_s_dv", "cat")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertU(adoc("id", "11", "test_s_dv", "the")); |
| assertU(adoc("id", "12", "test_s_dv", "quick brown")); |
| assertU(adoc("id", "13", "test_s_dv", "fox")); |
| assertU(adoc("id", "14", "test_s_dv", "jumped over the lazy dog")); |
| assertU(commit()); |
| |
| assertU(delI("16")); |
| assertU(delI("15")); |
| assertU(delQ("id:[11 TO 14]")); |
| assertU(commit()); |
| |
| assertIntervalQueriesString("test_s_dv"); |
| } |
| |
| @Test |
| public void testChangeFieldKey() { |
| assertU(adoc("id", "1", "test_s_dv", "dog", "test_l_dv", "1")); |
| assertU(adoc("id", "2", "test_s_dv", "cat", "test_l_dv", "2")); |
| assertU(commit()); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "{!key=foo}test_s_dv", |
| "facet.interval", "{!key=bar}test_l_dv", "f.test_s_dv.facet.interval.set", "[cat,dog]", |
| "f.test_l_dv.facet.interval.set", "[0,1]", |
| "f.test_l_dv.facet.interval.set", "[2,*]"), |
| "//lst[@name='facet_intervals']/lst[@name='foo']/int[@name='[cat,dog]'][.=2]", |
| "//lst[@name='facet_intervals']/lst[@name='bar']/int[@name='[0,1]'][.=1]", |
| "//lst[@name='facet_intervals']/lst[@name='bar']/int[@name='[2,*]'][.=1]"); |
| } |
| |
| |
| @Test |
| public void testFilterExclusion() { |
| assertU(adoc("id", "1", "test_s_dv", "dog")); |
| assertU(adoc("id", "2", "test_s_dv", "cat")); |
| assertU(adoc("id", "3", "test_s_dv", "bird")); |
| assertU(adoc("id", "4", "test_s_dv", "cat")); |
| assertU(adoc("id", "5", "test_s_dv", "turtle")); |
| assertU(adoc("id", "6", "test_s_dv", "dog")); |
| assertU(adoc("id", "7", "test_s_dv", "dog")); |
| assertU(adoc("id", "8", "test_s_dv", "dog")); |
| assertU(adoc("id", "9", "test_s_dv", "cat")); |
| assertU(adoc("id", "10")); |
| assertU(commit()); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", "rows", "0", |
| "f.test_s_dv.facet.interval.set", "[a,d]", |
| "f.test_s_dv.facet.interval.set", "[d,z]"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[a,d]'][.=4]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[d,z]'][.=5]"); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "test_s_dv", "rows", "0", |
| "f.test_s_dv.facet.interval.set", "[a,d]", |
| "f.test_s_dv.facet.interval.set", "[d,z]", |
| "fq", "test_s_dv:dog"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[a,d]'][.=0]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[d,z]'][.=4]"); |
| |
| assertQ(req("q", "*:*", "facet", "true", "facet.interval", "{!ex=dogs}test_s_dv", "rows", "0", |
| "f.test_s_dv.facet.interval.set", "[a,d]", |
| "f.test_s_dv.facet.interval.set", "[d,z]", |
| "fq", "{!tag='dogs'}test_s_dv:dog"), |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[a,d]'][.=4]", |
| "//lst[@name='facet_intervals']/lst[@name='test_s_dv']/int[@name='[d,z]'][.=5]"); |
| } |
| |
| @Test |
| public void testSolrJ() throws Exception { |
| assertU(adoc("id", "1", "test_i_dv", "0")); |
| assertU(adoc("id", "2", "test_i_dv", "1")); |
| assertU(adoc("id", "3", "test_i_dv", "2")); |
| assertU(commit()); |
| |
| // Don't close this client, it would shutdown the CoreContainer |
| @SuppressWarnings("resource") |
| SolrClient client = new EmbeddedSolrServer(h.getCoreContainer(), h.coreName); |
| |
| SolrQuery q = new SolrQuery(); |
| q.setQuery("*:*"); |
| q.addIntervalFacets("test_i_dv", new String[]{"[0,1]","[2,*]"}); |
| QueryResponse response = client.query(q); |
| assertEquals(1, response.getIntervalFacets().size()); |
| assertEquals("test_i_dv", response.getIntervalFacets().get(0).getField()); |
| assertEquals(2, response.getIntervalFacets().get(0).getIntervals().size()); |
| assertEquals("[0,1]", response.getIntervalFacets().get(0).getIntervals().get(0).getKey()); |
| assertEquals("[2,*]", response.getIntervalFacets().get(0).getIntervals().get(1).getKey()); |
| |
| q = new SolrQuery(); |
| q.setQuery("*:*"); |
| q.setFacet(true); |
| q.add("facet.interval", "{!key=foo}test_i_dv"); |
| q.add("f.test_i_dv.facet.interval.set", "{!key=first}[0,1]"); |
| q.add("f.test_i_dv.facet.interval.set", "{!key=second}[2,*]"); |
| response = client.query(q); |
| assertEquals(1, response.getIntervalFacets().size()); |
| assertEquals("foo", response.getIntervalFacets().get(0).getField()); |
| assertEquals(2, response.getIntervalFacets().get(0).getIntervals().size()); |
| assertEquals("first", response.getIntervalFacets().get(0).getIntervals().get(0).getKey()); |
| assertEquals("second", response.getIntervalFacets().get(0).getIntervals().get(1).getKey()); |
| |
| } |
| |
| |
| |
| private void assertIntervalQueriesNumeric(String field) { |
| assertIntervalQuery(field, "[0,1]", "2"); |
| assertIntervalQuery(field, "(0,2)", "1"); |
| assertIntervalQuery(field, "[0,2)", "2"); |
| assertIntervalQuery(field, "(0,2]", "2"); |
| assertIntervalQuery(field, "[*,5]", "6"); |
| assertIntervalQuery(field, "[*,3)", "3", "[2,5)", "3", "[6,8)", "2", "[3,*]", "7", "[10,10]", "1", "[10,10]", "1", "[10,10]", "1"); |
| assertIntervalQuery(field, "(5,*]", "4", "[5,5]", "1", "(*,5)", "5"); |
| assertIntervalQuery(field, "[5,5]", "1", "(*,5)", "5", "(5,*]", "4"); |
| assertIntervalQuery(field, "(5,*]", "4", "(*,5)", "5", "[5,5]", "1"); |
| |
| } |
| |
| private void assertIntervalQueriesString(String field) { |
| assertIntervalQuery(field, "[bird,bird]", "1"); |
| assertIntervalQuery(field, "(bird,dog)", "2"); |
| assertIntervalQuery(field, "[bird,dog)", "3"); |
| assertIntervalQuery(field, "(bird,turtle]", "6"); |
| assertIntervalQuery(field, "[*,bird]", "3"); |
| assertIntervalQuery(field, "[*,bird)", "2", "[bird,cat)", "1", "[cat,dog)", "2", "[dog,*]", "4"); |
| assertIntervalQuery(field, "[*,*]", "9", "[*,dog)", "5", "[*,dog]", "8", "[dog,*]", "4"); |
| assertIntervalQuery(field, field + ":dog", 3, "[*,*]", "3", "[*,dog)", "0", "[*,dog]", "3", "[dog,*]", "3", "[bird,cat]", "0"); |
| assertIntervalQuery(field, "(*,dog)", "5", "[dog, dog]", "3", "(dog,*)", "1"); |
| assertIntervalQuery(field, "[dog, dog]", "3", "(dog,*)", "1", "(*,dog)", "5"); |
| assertIntervalQuery(field, "(dog,*)", "1", "(*,dog)", "5", "[dog, dog]", "3"); |
| } |
| |
| /** |
| * Will run a match all query, and ask for interval facets in the specified field. |
| * The intervals facet are indicated in the <code>intervals</code> parameter, followed |
| * by the expected count result. For example: |
| * <code>assertIntervalQuery("my_string_field", "[0,10]", "3", "(20,*), "12");</code> |
| * |
| * @param field The field in which the interval facet should be asked |
| * @param intervals a variable array of intervals followed by the expected count (also a string) |
| */ |
| private void assertIntervalQuery(String field, String... intervals) { |
| assertIntervalQuery(field, "*:*", -1, intervals); |
| } |
| |
| private void assertIntervalQuery(String field, String query, int resultCount, String... intervals) { |
| assert (intervals.length & 1) == 0; |
| int idx = 0; |
| String[] params = new String[intervals.length + 6]; |
| params[idx++] = "q"; |
| params[idx++] = query; |
| params[idx++] = "facet"; |
| params[idx++] = "true"; |
| params[idx++] = "facet.interval"; |
| params[idx++] = field; |
| |
| for (int i = 0; i < intervals.length; i += 2) { |
| params[idx++] = "f." + field + ".facet.interval.set"; |
| params[idx++] = intervals[i]; |
| } |
| |
| String[] tests = new String[intervals.length / 2 + (resultCount > 0 ? 1 : 0)]; |
| idx = 0; |
| for (int i = 0; i < intervals.length; i += 2) { |
| tests[idx++] = "//lst[@name='facet_intervals']/lst[@name='" + field + "']/int[@name='" + intervals[i] + "'][.=" + intervals[i + 1] + "]"; |
| } |
| if (resultCount >= 0) { |
| tests[idx++] = "//*[@numFound='" + resultCount + "']"; |
| } |
| |
| assertQ("Unexpected facet iterval count. Field:" + field + ", Intervals: " + Arrays.toString(intervals) + "Query: " + query, |
| req(params), tests); |
| } |
| } |