blob: 7cbd372e01562c9308a7ed16ff33930e95974de0 [file] [log] [blame]
/*
* 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;
import java.util.Arrays;
import java.util.List;
import org.apache.lucene.util.LuceneTestCase.Slow;
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.response.IntervalFacet.Count;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.junit.BeforeClass;
import org.junit.Test;
@Slow
@SuppressSSL(bugUrl="https://issues.apache.org/jira/browse/SOLR-9182 - causes OOM")
// See: https://issues.apache.org/jira/browse/SOLR-12028 Tests cannot remove files on Windows machines occasionally
public class DistributedIntervalFacetingTest extends
BaseDistributedSearchTestCase {
@BeforeClass
public static void beforeSuperClass() throws Exception {
schemaString = "schema-distrib-interval-faceting.xml";
configString = "solrconfig-basic.xml";
}
@Test
public void test() throws Exception {
del("*:*");
commit();
testRandom();
del("*:*");
commit();
testSolrJ();
}
private void testSolrJ() throws Exception {
indexr("id", "0", "test_i_dv", "0", "test_s_dv", "AAA");
indexr("id", "1", "test_i_dv", "1", "test_s_dv", "BBB");
indexr("id", "2", "test_i_dv", "2", "test_s_dv", "AAA");
indexr("id", "3", "test_i_dv", "3", "test_s_dv", "CCC");
commit();
QueryResponse response = controlClient.query(new SolrQuery("*:*"));
assertEquals(4, response.getResults().getNumFound());
SolrQuery q = new SolrQuery("*:*");
String[] intervals = new String[]{"[0,1)","[1,2)", "[2,3)", "[3,*)"};
q.addIntervalFacets("test_i_dv", intervals);
response = controlClient.query(q);
assertEquals(1, response.getIntervalFacets().size());
assertEquals("test_i_dv", response.getIntervalFacets().get(0).getField());
assertEquals(4, response.getIntervalFacets().get(0).getIntervals().size());
for (int i = 0; i < response.getIntervalFacets().get(0).getIntervals().size(); i++) {
Count count = response.getIntervalFacets().get(0).getIntervals().get(i);
assertEquals(intervals[i], count.getKey());
assertEquals(1, count.getCount());
}
q = new SolrQuery("*:*");
q.addIntervalFacets("test_i_dv", intervals);
q.addIntervalFacets("test_s_dv", new String[]{"{!key='AAA'}[AAA,AAA]", "{!key='BBB'}[BBB,BBB]", "{!key='CCC'}[CCC,CCC]"});
response = controlClient.query(q);
assertEquals(2, response.getIntervalFacets().size());
int stringIntervalIndex = "test_s_dv".equals(response.getIntervalFacets().get(0).getField())?0:1;
assertEquals("test_i_dv", response.getIntervalFacets().get(1-stringIntervalIndex).getField());
assertEquals("test_s_dv", response.getIntervalFacets().get(stringIntervalIndex).getField());
for (int i = 0; i < response.getIntervalFacets().get(1-stringIntervalIndex).getIntervals().size(); i++) {
Count count = response.getIntervalFacets().get(1-stringIntervalIndex).getIntervals().get(i);
assertEquals(intervals[i], count.getKey());
assertEquals(1, count.getCount());
}
List<Count> stringIntervals = response.getIntervalFacets().get(stringIntervalIndex).getIntervals();
assertEquals(3, stringIntervals.size());
assertEquals("AAA", stringIntervals.get(0).getKey());
assertEquals(2, stringIntervals.get(0).getCount());
assertEquals("BBB", stringIntervals.get(1).getKey());
assertEquals(1, stringIntervals.get(1).getCount());
assertEquals("CCC", stringIntervals.get(2).getKey());
assertEquals(1, stringIntervals.get(2).getCount());
}
private void testRandom() throws Exception {
// All field values will be a number between 0 and cardinality
int cardinality = 1000000;
// 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_ss_dv", "test_is_dv", "test_fs_dv", "test_ls_dv", "test_ds_dv"};
for (int i = 0; i < atLeast(500); i++) {
if (random().nextInt(50) == 0) {
//have some empty docs
indexr("id", String.valueOf(i));
continue;
}
if (random().nextInt(100) == 0 && i > 0) {
//delete some docs
del("id:" + String.valueOf(i - 1));
}
Object[] docFields = new Object[(random().nextInt(5)) * 10 + 12];
docFields[0] = "id";
docFields[1] = String.valueOf(i);
docFields[2] = "test_s_dv";
docFields[3] = String.valueOf(random().nextInt(cardinality));
docFields[4] = "test_i_dv";
docFields[5] = String.valueOf(random().nextInt(cardinality));
docFields[6] = "test_l_dv";
docFields[7] = String.valueOf(random().nextInt(cardinality));
docFields[8] = "test_f_dv";
docFields[9] = String.valueOf(random().nextFloat() * cardinality);
docFields[10] = "test_d_dv";
docFields[11] = String.valueOf(random().nextDouble() * cardinality);
for (int j = 12; j < docFields.length; ) {
docFields[j++] = "test_ss_dv";
docFields[j++] = String.valueOf(random().nextInt(cardinality));
docFields[j++] = "test_is_dv";
docFields[j++] = String.valueOf(random().nextInt(cardinality));
docFields[j++] = "test_ls_dv";
docFields[j++] = String.valueOf(random().nextInt(cardinality));
docFields[j++] = "test_fs_dv";
docFields[j++] = String.valueOf(random().nextFloat() * cardinality);
docFields[j++] = "test_ds_dv";
docFields[j++] = String.valueOf(random().nextDouble() * cardinality);
}
indexr(docFields);
if (random().nextInt(50) == 0) {
commit();
}
}
commit();
handle.clear();
handle.put("QTime", SKIPVAL);
handle.put("timestamp", SKIPVAL);
handle.put("maxScore", SKIPVAL);
for (int i = 0; i < atLeast(100); i++) {
doTestQuery(cardinality, fields);
}
}
/**
* Executes one query using interval faceting and compares with the same query using
* facet query with the same range
*/
private void doTestQuery(int cardinality, String[] fields) throws Exception {
String[] startOptions = new String[]{"(", "["};
String[] endOptions = new String[]{")", "]"};
// the query should match some documents in most cases
Integer[] qRange = getRandomRange(cardinality, "id");
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("q", "id:[" + qRange[0] + " TO " + qRange[1] + "]");
params.set("facet", "true");
params.set("rows", "0");
String field = fields[random().nextInt(fields.length)]; //choose from any of the fields
if (random().nextBoolean()) {
params.set("facet.interval", field);
} else {
params.set("facet.interval", getFieldWithKey(field));
}
// number of intervals
for (int i = 0; i < 1 + random().nextInt(20); i++) {
Integer[] interval = getRandomRange(cardinality, field);
String open = startOptions[interval[0] % 2];
String close = endOptions[interval[1] % 2];
params.add("f." + field + ".facet.interval.set", open + interval[0] + "," + interval[1] + close);
}
query(params);
}
private String getFieldWithKey(String field) {
return "{!key='_some_key_for_" + field + "_" + random().nextInt() + "'}" + field;
}
/**
* Returns a random range. It's guaranteed that the first
* number will be lower than the second, and both of them
* between 0 (inclusive) and <code>max</code> (exclusive).
* If the fieldName is "test_s_dv" or "test_ss_dv" (the
* two fields used for Strings), the comparison will be done
* alphabetically
*/
private Integer[] getRandomRange(int max, String fieldName) {
Integer[] values = new Integer[2];
values[0] = random().nextInt(max);
values[1] = random().nextInt(max);
if ("test_s_dv".equals(fieldName) || "test_ss_dv".equals(fieldName)) {
Arrays.sort(values, (o1, o2) -> String.valueOf(o1).compareTo(String.valueOf(o2)));
} else {
Arrays.sort(values);
}
return values;
}
}