| /* |
| * 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(); |
| }*/ |