blob: 97b995285f52d35b13ddc6e5d71b6bccfd4ffeba [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.search;
import org.apache.lucene.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.util.BaseTestHarness;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
@LuceneTestCase.SuppressCodecs({"Lucene3x", "Lucene40","Lucene41","Lucene42","Lucene45"})
public class TestHashQParserPlugin extends SolrTestCaseJ4 {
@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig-hash.xml", "schema-hash.xml");
}
@Override
@Before
public void setUp() throws Exception {
// if you override setUp or tearDown, you better call
// the super classes version
super.setUp();
clearIndex();
assertU(commit());
}
public int getCost(Random random) {
int i = random.nextInt(2);
if(i == 0) {
return 200;
} else {
return 1;
}
}
@Test
public void testManyHashPartitions() throws Exception {
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=2 cost="+getCost(random())+"}");
params.add("partitionKeys", "a_i,a_s,a_i,a_s");
params.add("wt", "xml");
String response = h.query(req(params));
BaseTestHarness.validateXPath(response, "//*[@numFound='0']");
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=2 cost="+getCost(random())+"}");
params.add("partitionKeys", "a_i,a_s,a_i,a_s,a_i");
params.add("wt", "xml");
ModifiableSolrParams finalParams = params;
expectThrows(SolrException.class, () -> h.query(req(finalParams)));
}
@Test
public void testLessWorkers() {
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=1 cost="+getCost(random())+"}");
params.add("partitionKeys", "a_i");
params.add("wt", "xml");
ModifiableSolrParams finalParams = params;
expectThrows(SolrException.class, () -> h.query(req(finalParams)));
}
@Test
public void testHashPartitionWithEmptyValues() throws Exception {
assertU(adoc("id", "1", "a_s", "one", "a_i" , "1"));
assertU(adoc("id", "2", "a_s", "one", "a_i" , "1"));
assertU(adoc("id", "3"));
assertU(adoc("id", "4"));
assertU(commit());
//Test with string hash
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=2 cost="+getCost(random())+"}");
params.add("partitionKeys", "a_s");
params.add("wt", "xml");
String response = h.query(req(params));
BaseTestHarness.validateXPath(response, "//*[@numFound='4']");
//Test with int hash
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=2 cost="+getCost(random())+"}");
params.add("partitionKeys", "a_i");
params.add("wt", "xml");
response = h.query(req(params));
BaseTestHarness.validateXPath(response, "//*[@numFound='4']");
}
@Test
@SuppressWarnings({"unchecked", "rawtypes"})
public void testHashPartition() throws Exception {
Random random = random();
HashSet<String> set = new HashSet();
for (int i=0; i<50; i++) {
int v = random.nextInt(1000000);
String val = Integer.toString(v);
if(!set.contains(val)){
set.add(val);
String[] doc = {"id", val, "a_s", val, "a_i", val, "a_l", val};
assertU(adoc(doc));
if(i % 10 == 0)
assertU(commit());
}
}
assertU(commit());
//Test with 3 worker and String hash ID.
ModifiableSolrParams params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=3 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_s");
params.add("rows","50");
params.add("wt", "xml");
HashSet set1 = new HashSet();
String response = h.query(req(params));
Iterator<String> it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set1.add(s);
}
}
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=1 workers=3 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_s");
params.add("rows","50");
params.add("wt", "xml");
HashSet set2 = new HashSet();
response = h.query(req(params));
it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set2.add(s);
}
}
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=2 workers=3 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_s");
params.add("rows","50");
params.add("wt", "xml");
HashSet set3 = new HashSet();
response = h.query(req(params));
it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set3.add(s);
}
}
assert(set1.size() > 0);
assert(set2.size() > 0);
assert(set3.size() > 0);
assert(set1.size()+set2.size()+set3.size()==set.size());
assertNoOverLap(set1, set2);
assertNoOverLap(set1, set3);
assertNoOverLap(set2, set3);
//Test with 2 workers and int partition Key
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=2 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_i");
params.add("rows","50");
params.add("wt", "xml");
set1 = new HashSet();
response = h.query(req(params));
it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set1.add(s);
}
}
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=1 workers=2 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_i");
params.add("rows","50");
params.add("wt", "xml");
set2 = new HashSet();
response = h.query(req(params));
it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set2.add(s);
}
}
assert(set1.size() > 0);
assert(set2.size() > 0);
assert(set1.size()+set2.size()==set.size());
assertNoOverLap(set1, set2);
//Test with 2 workers and compound partition Key
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=0 workers=2 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_s, a_i, a_l");
params.add("rows","50");
params.add("wt", "xml");
set1 = new HashSet();
response = h.query(req(params));
it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set1.add(s);
}
}
params = new ModifiableSolrParams();
params.add("q", "*:*");
params.add("fq", "{!hash worker=1 workers=2 cost="+getCost(random)+"}");
params.add("partitionKeys", "a_s, a_i, a_l");
params.add("rows","50");
params.add("wt", "xml");
set2 = new HashSet();
response = h.query(req(params));
it = set.iterator();
while(it.hasNext()) {
String s = it.next();
String results = BaseTestHarness.validateXPath(response, "*[count(//str[@name='id'][.='"+s+"'])=1]");
if(results == null) {
set2.add(s);
}
}
assert(set1.size() > 0);
assert(set2.size() > 0);
assert(set1.size()+set2.size()==set.size());
assertNoOverLap(set1, set2);
}
private void assertNoOverLap(@SuppressWarnings({"rawtypes"})Set setA,
@SuppressWarnings({"rawtypes"})Set setB) throws Exception {
@SuppressWarnings({"rawtypes"})
Iterator it = setA.iterator();
while(it.hasNext()) {
Object o = it.next();
if(setB.contains(o)) {
throw new Exception("Overlapping sets for value:"+o.toString());
}
}
}
}