blob: 0975bcfce2ff0a158535888a8f2f5072b88b2955 [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.handler.component;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import org.apache.solr.BaseDistributedSearchTestCase;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.junit.BeforeClass;
/**
* Test for distributed ExpandComponent
*
* @see org.apache.solr.handler.component.ExpandComponent
*/
public class DistributedExpandComponentTest extends BaseDistributedSearchTestCase {
public DistributedExpandComponentTest() {
stress = 0;
}
@BeforeClass
public static void setUpBeforeClass() throws Exception {
initCore("solrconfig-collapseqparser.xml", "schema11.xml");
}
@ShardsFixed(num = 3)
public void test() throws Exception {
_test("group_s", "g1", "g2", "g3", "g4");
_test("group_s_dv", "g1", "g2", "g3", "g4");
_test("group_i", "1", "0", "3", "-1"); // NOTE: using 0 to explicitly confim we don't assume null
_test("group_ti_dv", "1", "-2", "0", "4"); // NOTE: using 0 to explicitly confim we don't assume null
}
private void _test(final String group,
final String aaa, final String bbb, final String ccc, final String ddd) throws Exception {
del("*:*");
index_specific(0,"id","1", "term_s", "YYYY", group, aaa, "test_i", "5", "test_l", "10", "test_f", "2000");
index_specific(0,"id","2", "term_s", "YYYY", group, aaa, "test_i", "50", "test_l", "100", "test_f", "200");
index_specific(1,"id","5", "term_s", "YYYY", group, bbb, "test_i", "4", "test_l", "10", "test_f", "2000");
index_specific(1,"id","6", "term_s", "YYYY", group, bbb, "test_i", "10", "test_l", "100", "test_f", "200");
index_specific(0,"id","7", "term_s", "YYYY", group, aaa, "test_i", "1", "test_l", "100000", "test_f", "2000");
index_specific(1,"id","8", "term_s", "YYYY", group, bbb, "test_i", "2", "test_l", "100000", "test_f", "200");
index_specific(2,"id","9", "term_s", "YYYY", group, ccc, "test_i", "1000", "test_l", "1005", "test_f", "3000");
index_specific(2,"id","10","term_s", "YYYY", group, ccc, "test_i", "1500", "test_l", "1001", "test_f", "3200");
// NOTE: nullPolicy=collapse will only be viable because all null docs are in collocated in shard #2
index_specific(2,"id","88", "test_i", "1001", "test_l", "1001", "test_f", "3200");
index_specific(2,"id","99", "test_i", "11", "test_l", "100", "test_f", "200");
index_specific(2,"id","11","term_s", "YYYY", group, ccc, "test_i", "1300", "test_l", "1002", "test_f", "3300");
index_specific(1,"id","12","term_s", "YYYY", group, ddd, "test_i", "15", "test_l", "10", "test_f", "2000");
index_specific(1,"id","13","term_s", "YYYY", group, ddd, "test_i", "16", "test_l", "9", "test_f", "2000");
index_specific(1,"id","14","term_s", "YYYY", group, ddd, "test_i", "1", "test_l", "20", "test_f", "2000");
commit();
handle.put("explain", SKIPVAL);
handle.put("timestamp", SKIPVAL);
handle.put("score", SKIPVAL);
handle.put("wt", SKIP);
handle.put("distrib", SKIP);
handle.put("shards.qt", SKIP);
handle.put("shards", SKIP);
handle.put("q", SKIP);
handle.put("maxScore", SKIPVAL);
handle.put("_version_", SKIP);
handle.put("expanded", UNORDERED);
query("q", "*:*", "fq", "{!collapse field="+group+"}", "defType", "edismax", "bf", "field(test_i)", "expand", "true", "fl","*,score");
query("q", "*:*", "fq", "{!collapse field="+group+"}", "defType", "edismax", "bf", "field(test_i)", "expand", "true", "expand.sort", "test_l desc", "fl","*,score");
query("q", "*:*", "fq", "{!collapse field="+group+"}", "defType", "edismax", "bf", "field(test_i)", "expand", "true", "expand.sort", "test_l desc", "expand.rows", "1", "fl","*,score");
//Test no expand results
query("q", "test_i:5", "fq", "{!collapse field="+group+"}", "defType", "edismax", "bf", "field(test_i)", "expand", "true", "expand.sort", "test_l desc", "expand.rows", "1", "fl","*,score");
//Test zero results
query("q", "test_i:5434343", "fq", "{!collapse field="+group+"}", "defType", "edismax", "bf", "field(test_i)", "expand", "true", "expand.sort", "test_l desc", "expand.rows", "1", "fl","*,score");
//Test page 2
query("q", "*:*", "start","1", "rows", "1", "fq", "{!collapse field="+group+"}", "defType", "edismax", "bf", "field(test_i)", "expand", "true", "fl","*,score");
// multiple collapse and equal cost
ModifiableSolrParams baseParams = params("q", "term_s:YYYY", "defType", "edismax", "expand", "true", "fl", "*,score",
"bf", "field(test_i)", "expand.sort", "id asc");
baseParams.set("fq", "{!collapse field="+group+"}", "{!collapse field=test_i}");
query(baseParams);
// multiple collapse and unequal cost case1
baseParams.set("fq", "{!collapse cost=1000 field="+group+"}", "{!collapse cost=2000 field=test_i}");
query(baseParams);
// multiple collapse and unequal cost case2
baseParams.set("fq", "{!collapse cost=1000 field="+group+"}", "{!collapse cost=200 field=test_i}");
query(baseParams);
ignoreException("missing expand field");
SolrException e = expectThrows(SolrException.class, () -> query("q", "*:*", "expand", "true"));
assertEquals(SolrException.ErrorCode.BAD_REQUEST.code, e.code());
assertTrue(e.getMessage().contains("missing expand field"));
resetExceptionIgnores();
// Since none of these queries will match any doc w/null in the group field, it shouldn't matter what nullPolicy is used...
for (String np : Arrays.asList("", " nullPolicy=ignore", " nullPolicy=expand", " nullPolicy=collapse")) {
//First basic test case.
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "{!collapse field="+group+np+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
setDistributedParams(params);
QueryResponse rsp = queryServer(params);
assertCountAndOrder(4, rsp.getResults(), "10" /* c */, "2" /* a */, "13" /* d */, "6" /* b */);
Map<String, SolrDocumentList> results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(bbb, 2, results, "5", "8");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(ddd, 2, results, "12", "14");
//Test expand.sort
params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "{!collapse field="+group+np+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
params.add("expand.sort", "test_l desc");
setDistributedParams(params);
rsp = queryServer(params);
assertCountAndOrder(4, rsp.getResults(), "10" /* c */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 2, results, "7", "1");
assertExpandGroupCountAndOrder(bbb, 2, results, "8", "5");
assertExpandGroupCountAndOrder(ccc, 2, results, "9", "11");
assertExpandGroupCountAndOrder(ddd, 2, results, "14", "12");
//Test expand.rows
params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "{!collapse field="+group+np+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
params.add("expand.sort", "test_l desc");
params.add("expand.rows", "1");
setDistributedParams(params);
rsp = queryServer(params);
assertCountAndOrder(4, rsp.getResults(), "10" /* c */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 1, results, "7");
assertExpandGroupCountAndOrder(bbb, 1, results, "8");
assertExpandGroupCountAndOrder(ccc, 1, results, "9");
assertExpandGroupCountAndOrder(ddd, 1, results, "14");
//Test expand.rows = 0 - no docs only expand count
params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "{!collapse field="+group+np+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
params.add("expand.rows", "0");
params.add("fl", "id");
setDistributedParams(params);
rsp = queryServer(params);
assertCountAndOrder(4, rsp.getResults(), "10" /* c */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 0, results);
assertExpandGroupCountAndOrder(bbb, 0, results);
assertExpandGroupCountAndOrder(ccc, 0, results);
assertExpandGroupCountAndOrder(ddd, 0, results);
//Test expand.rows = 0 with expand.field
params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "test_l:10");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
params.add("expand.fq", "test_f:2000");
params.add("expand.field", group);
params.add("expand.rows", "0");
params.add("fl", "id,score");
setDistributedParams(params);
rsp = queryServer(params);
assertCountAndOrder(3, rsp.getResults(), "12" /* d */, "1" /* a */, "5" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, ddd);
assertExpandGroupCountAndOrder(aaa, 0, results);
assertExpandGroupCountAndOrder(ddd, 0, results);
//Test key-only fl
params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "{!collapse field="+group+np+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
params.add("fl", "id");
setDistributedParams(params);
rsp = queryServer(params);
assertCountAndOrder(4, rsp.getResults(), "10" /* c */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(bbb, 2, results, "5", "8");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(ddd, 2, results, "12", "14");
//Test distrib.singlePass true
params = new ModifiableSolrParams();
params.add("q", "term_s:YYYY");
params.add("fq", "{!collapse field="+group+np+"}");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
params.add("distrib.singlePass", "true");
setDistributedParams(params);
rsp = queryServer(params);
assertCountAndOrder(4, rsp.getResults(), "10" /* c */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(bbb, 2, results, "5", "8");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(ddd, 2, results, "12", "14");
}
{ // queries matching all docs to test null groups from collapse and how it affects expand
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("defType", "edismax");
params.add("bf", "field(test_i)");
params.add("expand", "true");
setDistributedParams(params);
// nullPolicy=expand
params.add("fq", "{!collapse field="+group+" nullPolicy=expand}");
QueryResponse rsp = queryServer(params);
assertCountAndOrder(6, rsp.getResults(), "10" /* c */, "88" /* null */, "2" /* a */, "13" /* d */, "99" /* null */, "6" /* b */);
Map<String, SolrDocumentList> results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(bbb, 2, results, "5", "8");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(ddd, 2, results, "12", "14");
// nullPolicy=collapse
params.set("fq", "{!collapse field="+group+" nullPolicy=collapse}");
rsp = queryServer(params);
assertCountAndOrder(5, rsp.getResults(), "10" /* c */, "88" /* null */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(bbb, 2, results, "5", "8");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(ddd, 2, results, "12", "14");
// nullPolicy=collapse w/ expand.nullGroup=true...
params.set("fq", "{!collapse field="+group+" nullPolicy=collapse}");
params.set("expand.nullGroup", "true");
rsp = queryServer(params);
assertCountAndOrder(5, rsp.getResults(), "10" /* c */, "88" /* null */, "2" /* a */, "13" /* d */, "6" /* b */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, bbb, ccc, ddd, null);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(bbb, 2, results, "5", "8");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(ddd, 2, results, "12", "14");
assertExpandGroupCountAndOrder(null, 1, results, "99");
// nullPolicy=expand w/ expand.nullGroup=true (use small rows to ensure null expanded group)
params.set("fq", "{!collapse field="+group+" nullPolicy=expand}");
params.set("rows", "3");
rsp = queryServer(params);
assertCountAndOrder(3, rsp.getResults(), "10" /* c */, "88" /* null */, "2" /* a */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, ccc, null);
assertExpandGroupCountAndOrder(aaa, 2, results, "1", "7");
assertExpandGroupCountAndOrder(ccc, 2, results, "11", "9");
assertExpandGroupCountAndOrder(null, 1, results, "99");
// nullPolicy=expand w/ expand.nullGroup=true & expand.rows = 0
params.set("expand.rows", "0");
rsp = queryServer(params);
assertCountAndOrder(3, rsp.getResults(), "10" /* c */, "88" /* null */, "2" /* a */);
results = rsp.getExpandedResults();
assertExpandGroups(results, aaa, ccc, null);
assertExpandGroupCountAndOrder(aaa, 0, results);
assertExpandGroupCountAndOrder(ccc, 0, results);
assertExpandGroupCountAndOrder(null, 0, results);
}
}
private void assertExpandGroups(Map<String, SolrDocumentList> expandedResults, String... groups) throws Exception {
for(int i=0; i<groups.length; i++) {
if(!expandedResults.containsKey(groups[i])) {
throw new Exception("Expanded Group Not Found:"+groups[i]+", Found:"+exportGroups(expandedResults));
}
}
}
private String exportGroups(Map<String, SolrDocumentList> groups) {
StringBuilder buf = new StringBuilder();
Iterator<String> it = groups.keySet().iterator();
while(it.hasNext()) {
String group = it.next();
buf.append(group);
if(it.hasNext()) {
buf.append(",");
}
}
return buf.toString();
}
private void assertExpandGroupCountAndOrder(final String group, final int count,
final Map<String, SolrDocumentList>expandedResults,
final String... docs) throws Exception {
SolrDocumentList results = expandedResults.get(group);
if(results == null) {
throw new Exception("Group Not Found:"+group);
}
assertCountAndOrder(count, results, docs);
}
private void assertCountAndOrder(final int count, final SolrDocumentList results,
final String... docs) throws Exception {
assertEquals(results.toString(), count, results.size());
for(int i=0; i<docs.length;i++) {
String id = docs[i];
SolrDocument doc = results.get(i);
assertEquals("Id not in results or out of order", id, doc.getFieldValue("id").toString());
}
}
}