blob: 66034c94854b78800da75fd30565beb848d24c8b [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.solr.SolrTestCaseJ4;
import org.junit.BeforeClass;
import org.junit.Test;
/**
*
*
**/
public class SpatialFilterTest extends SolrTestCaseJ4 {
@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig.xml", "schema.xml");
}
private void setupDocs(String fieldName) {
clearIndex();
assertU(adoc("id", "1", fieldName, "32.7693246, -79.9289094"));
assertU(adoc("id", "2", fieldName, "33.7693246, -80.9289094"));
assertU(adoc("id", "3", fieldName, "-32.7693246, 50.9289094"));
assertU(adoc("id", "4", fieldName, "-50.7693246, 60.9289094"));
assertU(adoc("id", "5", fieldName, "0,0"));
assertU(adoc("id", "6", fieldName, "0.1,0.1"));
assertU(adoc("id", "7", fieldName, "-0.1,-0.1"));
assertU(adoc("id", "8", fieldName, "0,179.9"));
assertU(adoc("id", "9", fieldName, "0,-179.9"));
assertU(adoc("id", "10", fieldName, "89.9,50"));
assertU(adoc("id", "11", fieldName, "89.9,-130"));
assertU(adoc("id", "12", fieldName, "-89.9,50"));
assertU(adoc("id", "13", fieldName, "-89.9,-130"));
assertU(commit());
}
@Test
public void testPoints() throws Exception {
String fieldName = "home";
setupDocs(fieldName);
//Try some edge cases
checkHits(fieldName, "1,1", 100, 5, 3, 4, 5, 6, 7);
checkHits(fieldName, "0,179.8", 200, 5, 3, 4, 8, 10, 12);
checkHits(fieldName, "89.8, 50", 200, 9);
//try some normal cases
checkHits(fieldName, "33.0,-80.0", 300, 12);
//large distance
checkHits(fieldName, "33.0,-80.0", 5000, 13);
}
@Test
public void testGeoHash() throws Exception {
String fieldName = "home_gh";
setupDocs(fieldName);
//try some normal cases
checkHits(fieldName, "33.0,-80.0", 300, 2, 1, 2);
//large distance
checkHits(fieldName, "33.0,-80.0", 5000, 2, 1, 2);
//Try some edge cases
checkHits(fieldName, "0,179.8", 200, 2);
checkHits(fieldName, "1,1", 180, 3, 5, 6, 7);
checkHits(fieldName, "89.8, 50", 200, 2);
checkHits(fieldName, "-89.8, 50", 200, 2);//this goes over the south pole
}
@Test
public void testLatLonType() throws Exception {
String fieldName = "home_ll";
setupDocs(fieldName);
//Try some edge cases
checkHits(fieldName, "1,1", 175, 3, 5, 6, 7);
checkHits(fieldName, "0,179.8", 200, 2, 8, 9);
checkHits(fieldName, "89.8, 50", 200, 2, 10, 11);//this goes over the north pole
checkHits(fieldName, "-89.8, 50", 200, 2, 12, 13);//this goes over the south pole
//try some normal cases
checkHits(fieldName, "33.0,-80.0", 300, 2);
//large distance
checkHits(fieldName, "1,1", 5000, 3, 5, 6, 7);
//Because we are generating a box based on the west/east longitudes and the south/north latitudes, which then
//translates to a range query, which is slightly more inclusive. Thus, even though 0.0 is 15.725 kms away,
//it will be included, b/c of the box calculation.
checkHits(fieldName, false, "0.1,0.1", 15, 2, 5, 6);
//try some more
clearIndex();
assertU(adoc("id", "14", fieldName, "0,5"));
assertU(adoc("id", "15", fieldName, "0,15"));
//3000KM from 0,0, see http://www.movable-type.co.uk/scripts/latlong.html
assertU(adoc("id", "16", fieldName, "18.71111,19.79750"));
assertU(adoc("id", "17", fieldName, "44.043900,-95.436643"));
assertU(commit());
checkHits(fieldName, "0,0", 1000, 1, 14);
checkHits(fieldName, "0,0", 2000, 2, 14, 15);
checkHits(fieldName, false, "0,0", 3000, 3, 14, 15, 16);
checkHits(fieldName, "0,0", 3001, 3, 14, 15, 16);
checkHits(fieldName, "0,0", 3000.1, 3, 14, 15, 16);
//really fine grained distance and reflects some of the vagaries of how we are calculating the box
checkHits(fieldName, "43.517030,-96.789603", 109, 0);
// falls outside of the real distance, but inside the bounding box
checkHits(fieldName, true, "43.517030,-96.789603", 110, 0);
checkHits(fieldName, false, "43.517030,-96.789603", 110, 1, 17);
// Tests SOLR-2829
String fieldNameHome = "home_ll";
String fieldNameWork = "work_ll";
clearIndex();
assertU(adoc("id", "1", fieldNameHome, "52.67,7.30", fieldNameWork,"48.60,11.61"));
assertU(commit());
checkHits(fieldNameHome, "52.67,7.30", 1, 1);
checkHits(fieldNameWork, "48.60,11.61", 1, 1);
checkHits(fieldNameWork, "52.67,7.30", 1, 0);
checkHits(fieldNameHome, "48.60,11.61", 1, 0);
}
private void checkHits(String fieldName, String pt, double distance, int count, int ... docIds) {
checkHits(fieldName, true, pt, distance, count, docIds);
}
private void checkHits(String fieldName, boolean exact, String pt, double distance, int count, int ... docIds) {
String [] tests = new String[docIds != null && docIds.length > 0 ? docIds.length + 1 : 1];
tests[0] = "*[count(//doc)=" + count + "]";
if (docIds != null && docIds.length > 0) {
int i = 1;
for (int docId : docIds) {
tests[i++] = "//result/doc/str[@name='id'][.='" + docId + "']";
}
}
String method = exact ? "geofilt" : "bbox";
int postFilterCount = DelegatingCollector.setLastDelegateCount;
// throw in a random into the main query to prevent most cache hits
assertQ(req("fl", "id", "q","*:* OR foo_i:" + random().nextInt(100), "rows", "1000", "fq", "{!"+method+" sfield=" +fieldName +"}",
"pt", pt, "d", String.valueOf(distance)),
tests);
assertEquals(postFilterCount, DelegatingCollector.setLastDelegateCount); // post filtering shouldn't be used
// try uncached
assertQ(req("fl", "id", "q","*:* OR foo_i:" + random().nextInt(100), "rows", "1000", "fq", "{!"+method+" sfield=" +fieldName + " cache=false" + "}",
"pt", pt, "d", String.valueOf(distance)),
tests);
assertEquals(postFilterCount, DelegatingCollector.setLastDelegateCount); // post filtering shouldn't be used
// try post filtered for fields that support it
if (fieldName.endsWith("ll")) {
assertQ(req("fl", "id", "q","*:* OR foo_i:" + random().nextInt(100)+100, "rows", "1000", "fq", "{!"+method+" sfield=" +fieldName + " cache=false cost=150" + "}",
"pt", pt, "d", String.valueOf(distance)),
tests);
assertEquals(postFilterCount + 1, DelegatingCollector.setLastDelegateCount); // post filtering *should* have been used
}
}
}
/*public void testSpatialQParser() throws Exception {
ModifiableSolrParams local = new ModifiableSolrParams();
local.add(CommonParams.FL, "home");
ModifiableSolrParams params = new ModifiableSolrParams();
params.add(SpatialParams.POINT, "5.0,5.0");
params.add(SpatialParams.DISTANCE, "3");
SolrQueryRequest req = new LocalSolrQueryRequest(h.getCore(), "", "", 0, 10, new HashMap());
SpatialFilterQParserPlugin parserPlugin;
Query query;
parserPlugin = new SpatialFilterQParserPlugin();
QParser parser = parserPlugin.createParser("'foo'", local, params, req);
query = parser.parse();
assertNotNull("Query is null", query);
assertTrue("query is not an instanceof "
+ BooleanQuery.class,
query instanceof BooleanQuery);
local = new ModifiableSolrParams();
local.add(CommonParams.FL, "x");
params = new ModifiableSolrParams();
params.add(SpatialParams.POINT, "5.0");
params.add(SpatialParams.DISTANCE, "3");
req = new LocalSolrQueryRequest(h.getCore(), "", "", 0, 10, new HashMap());
parser = parserPlugin.createParser("'foo'", local, params, req);
query = parser.parse();
assertNotNull("Query is null", query);
assertTrue(query.getClass() + " is not an instanceof "
+ LegacyNumericRangeQuery.class,
query instanceof LegacyNumericRangeQuery);
req.close();
}*/