You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ds...@apache.org on 2014/01/24 20:40:15 UTC
svn commit: r1561129 [3/4] - in /lucene/dev/trunk: lucene/ lucene/benchmark/
lucene/benchmark/src/java/org/apache/lucene/benchmark/byTask/feeds/
lucene/licenses/ lucene/spatial/src/java/org/apache/lucene/spatial/query/
lucene/spatial/src/test-files/ lu...
Modified: lucene/dev/trunk/lucene/spatial/src/test-files/simple-Queries-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test-files/simple-Queries-BBox.txt?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test-files/simple-Queries-BBox.txt (original)
+++ lucene/dev/trunk/lucene/spatial/src/test-files/simple-Queries-BBox.txt Fri Jan 24 19:40:14 2014
@@ -1,13 +1,8 @@
-C5 @ IsWithin(-6 -6 6 6)
-C5 @ BBoxWithin(-6 -6 6 6)
-C10 @ Contains(-6 -6 6 6)
-C10 @ IsEqualTo(-10 -10 10 10)
-C5 C10 @ Intersects(-2 -2 2 2)
-C5 C10 @ Overlaps(-2 -2 2 2)
-C5 C10 @ BBoxIntersects(-2 -2 2 2)
-NW15 @ IsDisjointTo(-10 -10 10 10)
-
-
-
-
-
+C5 @ IsWithin(ENVELOPE(-6, 6, 6, -6))
+C5 @ BBoxWithin(ENVELOPE(-6, 6, 6, -6))
+C10 @ Contains(ENVELOPE(-6, 6, 6, -6))
+C10 @ IsEqualTo(ENVELOPE(-10, 10, 10, -10))
+C5 C10 @ Intersects(ENVELOPE(-2, 2, 2, -2))
+C5 C10 @ Overlaps(ENVELOPE(-2, 2, 2, -2))
+C5 C10 @ BBoxIntersects(ENVELOPE(-2, 2, 2, -2))
+NW15 @ IsDisjointTo(ENVELOPE(-10, 10, 10, -10))
\ No newline at end of file
Modified: lucene/dev/trunk/lucene/spatial/src/test-files/states-Intersects-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test-files/states-Intersects-BBox.txt?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test-files/states-Intersects-BBox.txt (original)
+++ lucene/dev/trunk/lucene/spatial/src/test-files/states-Intersects-BBox.txt Fri Jan 24 19:40:14 2014
@@ -1,3 +1,3 @@
-WY CO @ Intersects(-106.964844 39.460938 -105.734375 42.800781)
-TX @ Intersects(-99.669922 30.583984 -98.439453 32.253906)
-MS TX LA @ Intersects(-95.363281 29.792969 -90.133789 32.473633)
+WY CO @ Intersects(ENVELOPE(-106.964844, -105.734375, 42.800781, 39.460938))
+TX @ Intersects(ENVELOPE(-99.669922, -98.439453, 32.253906, 30.583984))
+MS TX LA @ Intersects(ENVELOPE(-95.363281, -90.133789, 32.473633, 29.792969))
\ No newline at end of file
Modified: lucene/dev/trunk/lucene/spatial/src/test-files/states-IsWithin-BBox.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test-files/states-IsWithin-BBox.txt?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test-files/states-IsWithin-BBox.txt (original)
+++ lucene/dev/trunk/lucene/spatial/src/test-files/states-IsWithin-BBox.txt Fri Jan 24 19:40:14 2014
@@ -1,4 +1,4 @@
-KS @ IsWithin(-103.493164 36.208984 -93.825195 41.086914)
-WA @ IsWithin(-126.916016 44.36084 -115.314453 50.688965)
-MA CT RI @ IsWithin(-73.894043 40.825195 -69.521484 43.198242)
-AL GA @ IsWithin(-89.472656 29.311523 -80.244141 35.90332)
\ No newline at end of file
+KS @ IsWithin(ENVELOPE(-103.493164, -93.825195, 41.086914, 36.208984))
+WA @ IsWithin(ENVELOPE(-126.916016, -115.314453, 50.688965, 44.36084))
+MA CT RI @ IsWithin(ENVELOPE(-73.894043, -69.521484, 43.198242, 40.825195))
+AL GA @ IsWithin(ENVELOPE(-89.472656, -80.244141, 35.90332, 29.311523))
\ No newline at end of file
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/DistanceStrategyTest.java Fri Jan 24 19:40:14 2014
@@ -93,8 +93,8 @@ public class DistanceStrategyTest extend
adoc("103", (Shape)null);//test score for nothing
commit();
//FYI distances are in docid order
- checkDistValueSource("3,4", 2.8274937f, 5.0898066f, 180f);
- checkDistValueSource("4,0", 3.6043684f, 0.9975641f, 180f);
+ checkDistValueSource(ctx.makePoint(4, 3), 2.8274937f, 5.0898066f, 180f);
+ checkDistValueSource(ctx.makePoint(0, 4), 3.6043684f, 0.9975641f, 180f);
}
@Test
@@ -120,8 +120,7 @@ public class DistanceStrategyTest extend
return super.newDoc(id, shape);
}
- void checkDistValueSource(String ptStr, float... distances) throws IOException {
- Point pt = (Point) ctx.readShape(ptStr);
+ void checkDistValueSource(Point pt, float... distances) throws IOException {
float multiplier = random().nextFloat() * 100f;
float[] dists2 = Arrays.copyOf(distances, distances.length);
for (int i = 0; i < dists2.length; i++) {
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/PortedSolr3Test.java Fri Jan 24 19:40:14 2014
@@ -36,7 +36,6 @@ import org.apache.lucene.spatial.query.S
import org.apache.lucene.spatial.vector.PointVectorStrategy;
import org.junit.Test;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -91,21 +90,21 @@ public class PortedSolr3Test extends Str
this.strategy = strategy;
}
- private void setupDocs() throws IOException {
+ private void setupDocs() throws Exception {
super.deleteAll();
- adoc("1", "32.7693246, -79.9289094");
- adoc("2", "33.7693246, -80.9289094");
- adoc("3", "-32.7693246, 50.9289094");
- adoc("4", "-50.7693246, 60.9289094");
- adoc("5", "0,0");
- adoc("6", "0.1,0.1");
- adoc("7", "-0.1,-0.1");
- adoc("8", "0,179.9");
- adoc("9", "0,-179.9");
- adoc("10", "89.9,50");
- adoc("11", "89.9,-130");
- adoc("12", "-89.9,50");
- adoc("13", "-89.9,-130");
+ adoc("1", ctx.makePoint(-79.9289094, 32.7693246));
+ adoc("2", ctx.makePoint(-80.9289094, 33.7693246));
+ adoc("3", ctx.makePoint(50.9289094, -32.7693246));
+ adoc("4", ctx.makePoint(60.9289094, -50.7693246));
+ adoc("5", ctx.makePoint(0, 0));
+ adoc("6", ctx.makePoint(0.1, 0.1));
+ adoc("7", ctx.makePoint(-0.1, -0.1));
+ adoc("8", ctx.makePoint(179.9, 0));
+ adoc("9", ctx.makePoint(-179.9, 0));
+ adoc("10", ctx.makePoint(50, 89.9));
+ adoc("11", ctx.makePoint(-130, 89.9));
+ adoc("12", ctx.makePoint(50, -89.9));
+ adoc("13", ctx.makePoint(-130, -89.9));
commit();
}
@@ -115,53 +114,52 @@ public class PortedSolr3Test extends Str
setupDocs();
//Try some edge cases
//NOTE: 2nd arg is distance in kilometers
- checkHitsCircle("1,1", 175, 3, 5, 6, 7);
- checkHitsCircle("0,179.8", 200, 2, 8, 9);
- checkHitsCircle("89.8, 50", 200, 2, 10, 11);//this goes over the north pole
- checkHitsCircle("-89.8, 50", 200, 2, 12, 13);//this goes over the south pole
+ checkHitsCircle(ctx.makePoint(1, 1), 175, 3, 5, 6, 7);
+ checkHitsCircle(ctx.makePoint(179.8, 0), 200, 2, 8, 9);
+ checkHitsCircle(ctx.makePoint(50, 89.8), 200, 2, 10, 11);//this goes over the north pole
+ checkHitsCircle(ctx.makePoint(50, -89.8), 200, 2, 12, 13);//this goes over the south pole
//try some normal cases
- checkHitsCircle("33.0,-80.0", 300, 2);
+ checkHitsCircle(ctx.makePoint(-80.0, 33.0), 300, 2);
//large distance
- checkHitsCircle("1,1", 5000, 3, 5, 6, 7);
+ checkHitsCircle(ctx.makePoint(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.
- checkHitsBBox("0.1,0.1", 15, 2, 5, 6);
+ checkHitsBBox(ctx.makePoint(0.1, 0.1), 15, 2, 5, 6);
//try some more
deleteAll();
- adoc("14", "0,5");
- adoc("15", "0,15");
+ adoc("14", ctx.makePoint(5, 0));
+ adoc("15", ctx.makePoint(15, 0));
//3000KM from 0,0, see http://www.movable-type.co.uk/scripts/latlong.html
- adoc("16", "18.71111,19.79750");
- adoc("17", "44.043900,-95.436643");
+ adoc("16", ctx.makePoint(19.79750, 18.71111));
+ adoc("17", ctx.makePoint(-95.436643, 44.043900));
commit();
- checkHitsCircle("0,0", 1000, 1, 14);
- checkHitsCircle("0,0", 2000, 2, 14, 15);
- checkHitsBBox("0,0", 3000, 3, 14, 15, 16);
- checkHitsCircle("0,0", 3001, 3, 14, 15, 16);
- checkHitsCircle("0,0", 3000.1, 3, 14, 15, 16);
+ checkHitsCircle(ctx.makePoint(0, 0), 1000, 1, 14);
+ checkHitsCircle(ctx.makePoint(0, 0), 2000, 2, 14, 15);
+ checkHitsBBox(ctx.makePoint(0, 0), 3000, 3, 14, 15, 16);
+ checkHitsCircle(ctx.makePoint(0, 0), 3001, 3, 14, 15, 16);
+ checkHitsCircle(ctx.makePoint(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
- checkHitsCircle("43.517030,-96.789603", 109, 0);
+ checkHitsCircle(ctx.makePoint(-96.789603, 43.517030), 109, 0);
// falls outside of the real distance, but inside the bounding box
- checkHitsCircle("43.517030,-96.789603", 110, 0);
- checkHitsBBox("43.517030,-96.789603", 110, 1, 17);
+ checkHitsCircle(ctx.makePoint(-96.789603, 43.517030), 110, 0);
+ checkHitsBBox(ctx.makePoint(-96.789603, 43.517030), 110, 1, 17);
}
//---- these are similar to Solr test methods
- private void checkHitsCircle(String ptStr, double distKM, int assertNumFound, int... assertIds) {
- _checkHits(false, ptStr, distKM, assertNumFound, assertIds);
+ private void checkHitsCircle(Point pt, double distKM, int assertNumFound, int... assertIds) {
+ _checkHits(false, pt, distKM, assertNumFound, assertIds);
}
- private void checkHitsBBox(String ptStr, double distKM, int assertNumFound, int... assertIds) {
- _checkHits(true, ptStr, distKM, assertNumFound, assertIds);
+ private void checkHitsBBox(Point pt, double distKM, int assertNumFound, int... assertIds) {
+ _checkHits(true, pt, distKM, assertNumFound, assertIds);
}
- private void _checkHits(boolean bbox, String ptStr, double distKM, int assertNumFound, int... assertIds) {
+ private void _checkHits(boolean bbox, Point pt, double distKM, int assertNumFound, int... assertIds) {
SpatialOperation op = SpatialOperation.Intersects;
- Point pt = (Point) ctx.readShape(ptStr);
double distDEG = DistanceUtils.dist2Degrees(distKM, DistanceUtils.EARTH_MEAN_RADIUS_KM);
Shape shape = ctx.makeCircle(pt, distDEG);
if (bbox)
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialExample.java Fri Jan 24 19:40:14 2014
@@ -57,11 +57,11 @@ public class SpatialExample extends Luce
//Note: Test invoked via TestTestFramework.spatialExample()
- public static void main(String[] args) throws IOException {
+ public static void main(String[] args) throws Exception {
new SpatialExample().test();
}
- public void test() throws IOException {
+ public void test() throws Exception {
init();
indexPoints();
search();
@@ -102,7 +102,7 @@ public class SpatialExample extends Luce
this.directory = new RAMDirectory();
}
- private void indexPoints() throws IOException {
+ private void indexPoints() throws Exception {
IndexWriterConfig iwConfig = new IndexWriterConfig(TEST_VERSION_CURRENT,null);
IndexWriter indexWriter = new IndexWriter(directory, iwConfig);
@@ -110,10 +110,9 @@ public class SpatialExample extends Luce
indexWriter.addDocument(newSampleDocument(
2, ctx.makePoint(-80.93, 33.77)));
- //When parsing a string to a shape, the presence of a comma means it's y-x
- // order (lon, lat)
+ //Spatial4j has a WKT parser which is also "x y" order
indexWriter.addDocument(newSampleDocument(
- 4, ctx.readShape("-50.7693246, 60.9289094")));
+ 4, ctx.readShapeFromWkt("POINT(60.9289094 -50.7693246)")));
indexWriter.addDocument(newSampleDocument(
20, ctx.makePoint(0.1,0.1), ctx.makePoint(0, 0)));
@@ -131,13 +130,15 @@ public class SpatialExample extends Luce
doc.add(f);
}
//store it too; the format is up to you
- doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+ // (assume point in this example)
+ Point pt = (Point) shape;
+ doc.add(new StoredField(strategy.getFieldName(), pt.getX()+" "+pt.getY()));
}
return doc;
}
- private void search() throws IOException {
+ private void search() throws Exception {
IndexReader indexReader = DirectoryReader.open(directory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
Sort idSort = new Sort(new SortField("id", SortField.Type.INT));
@@ -155,15 +156,19 @@ public class SpatialExample extends Luce
// (this computation is usually not redundant)
StoredDocument doc1 = indexSearcher.doc(docs.scoreDocs[0].doc);
String doc1Str = doc1.getField(strategy.getFieldName()).stringValue();
- Point doc1Point = (Point) ctx.readShape(doc1Str);
- double doc1DistDEG = ctx.getDistCalc().distance(args.getShape().getCenter(), doc1Point);
+ //assume doc1Str is "x y" as written in newSampleDocument()
+ int spaceIdx = doc1Str.indexOf(' ');
+ double x = Double.parseDouble(doc1Str.substring(0, spaceIdx));
+ double y = Double.parseDouble(doc1Str.substring(spaceIdx+1));
+ double doc1DistDEG = ctx.calcDistance(args.getShape().getCenter(), x, y);
assertEquals(121.6d, DistanceUtils.degrees2Dist(doc1DistDEG, DistanceUtils.EARTH_MEAN_RADIUS_KM), 0.1);
+ //or more simply:
+ assertEquals(121.6d, doc1DistDEG * DistanceUtils.DEG_TO_KM, 0.1);
}
//--Match all, order by distance ascending
{
Point pt = ctx.makePoint(60, -50);
- double degToKm = DistanceUtils.degrees2Dist(1, DistanceUtils.EARTH_MEAN_RADIUS_KM);
- ValueSource valueSource = strategy.makeDistanceValueSource(pt, degToKm);//the distance (in km)
+ ValueSource valueSource = strategy.makeDistanceValueSource(pt, DistanceUtils.DEG_TO_KM);//the distance (in km)
Sort distSort = new Sort(valueSource.getSortField(false)).rewrite(indexSearcher);//false=asc dist
TopDocs docs = indexSearcher.search(new MatchAllDocsQuery(), 10, distSort);
assertDocMatchedIds(indexSearcher, docs, 4, 20, 2);
@@ -178,7 +183,7 @@ public class SpatialExample extends Luce
{
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects,
ctx.makeCircle(-80.0, 33.0, 1));
- SpatialArgs args2 = new SpatialArgsParser().parse("Intersects(Circle(33,-80 d=1))", ctx);
+ SpatialArgs args2 = new SpatialArgsParser().parse("Intersects(BUFFER(POINT(-80 33),1))", ctx);
assertEquals(args.toString(),args2.toString());
}
Added: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestData.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestData.java?rev=1561129&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestData.java (added)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestData.java Fri Jan 24 19:40:14 2014
@@ -0,0 +1,71 @@
+package org.apache.lucene.spatial;
+
+/*
+ * 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.
+ */
+
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.shape.Shape;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+// This class is modelled after SpatialTestQuery.
+// Before Lucene 4.7, this was a bit different in Spatial4j as SampleData & SampleDataReader.
+
+public class SpatialTestData {
+ public String id;
+ public String name;
+ public Shape shape;
+
+ /** Reads the stream, consuming a format that is a tab-separated values of 3 columns:
+ * an "id", a "name" and the "shape". Empty lines and lines starting with a '#' are skipped.
+ * The stream is closed.
+ */
+ public static Iterator<SpatialTestData> getTestData(InputStream in, SpatialContext ctx) throws IOException {
+ List<SpatialTestData> results = new ArrayList<SpatialTestData>();
+ BufferedReader bufInput = new BufferedReader(new InputStreamReader(in,"UTF-8"));
+ try {
+ String line;
+ while ((line = bufInput.readLine()) != null) {
+ if (line.length() == 0 || line.charAt(0) == '#')
+ continue;
+
+ SpatialTestData data = new SpatialTestData();
+ String[] vals = line.split("\t");
+ if (vals.length != 3)
+ throw new RuntimeException("bad format; expecting 3 tab-separated values for line: "+line);
+ data.id = vals[0];
+ data.name = vals[1];
+ try {
+ data.shape = ctx.readShapeFromWkt(vals[2]);
+ } catch (ParseException e) {
+ throw new RuntimeException(e);
+ }
+ results.add(data);
+ }
+ } finally {
+ bufInput.close();
+ }
+ return results.iterator();
+ }
+}
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/SpatialTestQuery.java Fri Jan 24 19:40:14 2014
@@ -18,10 +18,10 @@ package org.apache.lucene.spatial;
*/
import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.io.LineReader;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialArgsParser;
+import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -41,20 +41,23 @@ public class SpatialTestQuery {
public List<String> ids = new ArrayList<String>();
/**
- * Get Test Queries
+ * Get Test Queries. The InputStream is closed.
*/
public static Iterator<SpatialTestQuery> getTestQueries(
final SpatialArgsParser parser,
final SpatialContext ctx,
final String name,
final InputStream in ) throws IOException {
- return new LineReader<SpatialTestQuery>(new InputStreamReader(in,"UTF-8")) {
- @Override
- public SpatialTestQuery parseLine(String line) {
+ List<SpatialTestQuery> results = new ArrayList<SpatialTestQuery>();
+
+ BufferedReader bufInput = new BufferedReader(new InputStreamReader(in,"UTF-8"));
+ try {
+ String line;
+ for (int lineNumber = 1; (line = bufInput.readLine()) != null; lineNumber++) {
SpatialTestQuery test = new SpatialTestQuery();
test.line = line;
- test.lineNumber = getLineNumber();
+ test.lineNumber = lineNumber;
try {
// skip a comment
@@ -71,13 +74,16 @@ public class SpatialTestQuery {
test.ids.add(st.nextToken().trim());
}
test.args = parser.parse(line.substring(idx + 1).trim(), ctx);
- return test;
+ results.add(test);
}
catch( Exception ex ) {
throw new RuntimeException( "invalid query line: "+test.line, ex );
}
}
- };
+ } finally {
+ bufInput.close();
+ }
+ return results.iterator();
}
@Override
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/StrategyTestCase.java Fri Jan 24 19:40:14 2014
@@ -19,8 +19,6 @@ package org.apache.lucene.spatial;
*/
import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.io.sample.SampleData;
-import com.spatial4j.core.io.sample.SampleDataReader;
import com.spatial4j.core.shape.Shape;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
@@ -40,6 +38,7 @@ import org.apache.lucene.spatial.query.S
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -88,21 +87,21 @@ public abstract class StrategyTestCase e
return getDocuments(getSampleData(testDataFile));
}
- protected List<Document> getDocuments(Iterator<SampleData> sampleData) {
+ protected List<Document> getDocuments(Iterator<SpatialTestData> sampleData) {
List<Document> documents = new ArrayList<Document>();
while (sampleData.hasNext()) {
- SampleData data = sampleData.next();
+ SpatialTestData data = sampleData.next();
Document document = new Document();
document.add(new StringField("id", data.id, Field.Store.YES));
document.add(new StringField("name", data.name, Field.Store.YES));
- Shape shape = ctx.readShape(data.shape);
+ Shape shape = data.shape;
shape = convertShapeFromGetDocuments(shape);
if (shape != null) {
for (Field f : strategy.createIndexableFields(shape)) {
document.add(f);
}
- if (storeShape)
- document.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+ if (storeShape)//just for diagnostics
+ document.add(new StoredField(strategy.getFieldName(), shape.toString()));
}
documents.add(document);
@@ -115,18 +114,18 @@ public abstract class StrategyTestCase e
return shape;
}
- protected Iterator<SampleData> getSampleData(String testDataFile) throws IOException {
+ protected Iterator<SpatialTestData> getSampleData(String testDataFile) throws IOException {
String path = "data/" + testDataFile;
InputStream stream = getClass().getClassLoader().getResourceAsStream(path);
if (stream == null)
throw new FileNotFoundException("classpath resource not found: "+path);
- return new SampleDataReader(stream);
+ return SpatialTestData.getTestData(stream, ctx);//closes the InputStream
}
protected Iterator<SpatialTestQuery> getTestQueries(String testQueryFile, SpatialContext ctx) throws IOException {
InputStream in = getClass().getClassLoader().getResourceAsStream(testQueryFile);
return SpatialTestQuery.getTestQueries(
- argsParser, ctx, testQueryFile, in );
+ argsParser, ctx, testQueryFile, in );//closes the InputStream
}
public void runTestQueries(
@@ -142,8 +141,8 @@ public abstract class StrategyTestCase e
String msg = q.toString(); //"Query: " + q.args.toString(ctx);
SearchResults got = executeQuery(strategy.makeQuery(q.args), Math.max(100, q.ids.size()+1));
if (storeShape && got.numFound > 0) {
- //check stored value is there & parses
- assertNotNull(ctx.readShape(got.results.get(0).document.get(strategy.getFieldName())));
+ //check stored value is there
+ assertNotNull(got.results.get(0).document.get(strategy.getFieldName()));
}
if (concern.orderIsImportant) {
Iterator<String> ids = q.ids.iterator();
@@ -184,8 +183,8 @@ public abstract class StrategyTestCase e
}
}
- protected void adoc(String id, String shapeStr) throws IOException {
- Shape shape = shapeStr==null ? null : ctx.readShape(shapeStr);
+ protected void adoc(String id, String shapeStr) throws IOException, ParseException {
+ Shape shape = shapeStr==null ? null : ctx.readShapeFromWkt(shapeStr);
addDocument(newDoc(id, shape));
}
protected void adoc(String id, Shape shape) throws IOException {
@@ -200,7 +199,7 @@ public abstract class StrategyTestCase e
doc.add(f);
}
if (storeShape)
- doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+ doc.add(new StoredField(strategy.getFieldName(), shape.toString()));//not to be parsed; just for debug
}
return doc;
}
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/TestTestFramework.java Fri Jan 24 19:40:14 2014
@@ -44,7 +44,7 @@ public class TestTestFramework extends L
InputStream in = getClass().getClassLoader().getResourceAsStream(name);
SpatialContext ctx = SpatialContext.GEO;
Iterator<SpatialTestQuery> iter = SpatialTestQuery.getTestQueries(
- new SpatialArgsParser(), ctx, name, in );
+ new SpatialArgsParser(), ctx, name, in );//closes the InputStream
List<SpatialTestQuery> tests = new ArrayList<SpatialTestQuery>();
while( iter.hasNext() ) {
tests.add( iter.next() );
@@ -52,15 +52,15 @@ public class TestTestFramework extends L
Assert.assertEquals( 3, tests.size() );
SpatialTestQuery sf = tests.get(0);
- // assert
+ // assert
Assert.assertEquals( 1, sf.ids.size() );
Assert.assertTrue( sf.ids.get(0).equals( "G5391959" ) );
Assert.assertTrue( sf.args.getShape() instanceof Rectangle);
- Assert.assertEquals( SpatialOperation.Intersects, sf.args.getOperation() );
+ Assert.assertEquals(SpatialOperation.Intersects, sf.args.getOperation());
}
@Test
- public void spatialExample() throws IOException {
+ public void spatialExample() throws Exception {
//kind of a hack so that SpatialExample is tested despite
// it not starting or ending with "Test".
SpatialExample.main(null);
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/JtsPolygonTest.java Fri Jan 24 19:40:14 2014
@@ -35,7 +35,7 @@ import org.apache.lucene.spatial.query.S
import org.apache.lucene.spatial.query.SpatialOperation;
import org.junit.Test;
-import java.io.IOException;
+import java.text.ParseException;
import java.util.HashMap;
public class JtsPolygonTest extends StrategyTestCase {
@@ -59,7 +59,7 @@ public class JtsPolygonTest extends Stra
@Test
/** LUCENE-4464 */
- public void testCloseButNoMatch() throws IOException {
+ public void testCloseButNoMatch() throws Exception {
getAddAndVerifyIndexedDocuments("LUCENE-4464.txt");
SpatialArgs args = q(
"POLYGON((-93.18100824442227 45.25676372469945," +
@@ -73,8 +73,8 @@ public class JtsPolygonTest extends Stra
//did not find poly 1 !
}
- private SpatialArgs q(String shapeStr, double distErrPct) {
- Shape shape = ctx.readShape(shapeStr);
+ private SpatialArgs q(String shapeStr, double distErrPct) throws ParseException {
+ Shape shape = ctx.readShapeFromWkt(shapeStr);
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, shape);
args.setDistErrPct(distErrPct);
return args;
@@ -87,7 +87,7 @@ public class JtsPolygonTest extends Stra
@Test
public void testBadPrefixTreePrune() throws Exception {
- Shape area = ctx.readShape("POLYGON((-122.83 48.57, -122.77 48.56, -122.79 48.53, -122.83 48.57))");
+ Shape area = ctx.readShapeFromWkt("POLYGON((-122.83 48.57, -122.77 48.56, -122.79 48.53, -122.83 48.57))");
SpatialPrefixTree trie = new QuadPrefixTree(ctx, 12);
TermQueryPrefixTreeStrategy strategy = new TermQueryPrefixTreeStrategy(trie, "geo");
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/SpatialOpRecursivePrefixTreeTest.java Fri Jan 24 19:40:14 2014
@@ -19,6 +19,7 @@ package org.apache.lucene.spatial.prefix
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.context.SpatialContextFactory;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Rectangle;
import com.spatial4j.core.shape.Shape;
@@ -71,7 +72,10 @@ public class SpatialOpRecursivePrefixTre
public void mySetup(int maxLevels) throws IOException {
//non-geospatial makes this test a little easier (in gridSnap), and using boundary values 2^X raises
// the prospect of edge conditions we want to test, plus makes for simpler numbers (no decimals).
- this.ctx = new SpatialContext(false, null, new RectangleImpl(0, 256, -128, 128, null));
+ SpatialContextFactory factory = new SpatialContextFactory();
+ factory.geo = false;
+ factory.worldBounds = new RectangleImpl(0, 256, -128, 128, null);
+ this.ctx = factory.newSpatialContext();
//A fairly shallow grid, and default 2.5% distErrPct
if (maxLevels == -1)
maxLevels = randomIntBetween(1, 8);
@@ -179,8 +183,8 @@ public class SpatialOpRecursivePrefixTre
doc.add(f);
}
}
- if (storeShape)
- doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
+ if (storeShape)//just for diagnostics
+ doc.add(new StoredField(strategy.getFieldName(), shape.toString()));
}
return doc;
}
@@ -412,6 +416,16 @@ public class SpatialOpRecursivePrefixTre
}
@Override
+ public Shape getBuffered(double distance, SpatialContext ctx) {
+ throw new UnsupportedOperationException("TODO unimplemented");//TODO
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
public String toString() {
return "ShapePair(" + shape1 + " , " + shape2 + ")";
}
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/prefix/TestTermQueryPrefixGridStrategy.java Fri Jan 24 19:40:14 2014
@@ -46,7 +46,7 @@ public class TestTermQueryPrefixGridStra
for (Field field : prefixGridStrategy.createIndexableFields(point)) {
losAngeles.add(field);
}
- losAngeles.add(new StoredField(prefixGridStrategy.getFieldName(), ctx.toString(point)));
+ losAngeles.add(new StoredField(prefixGridStrategy.getFieldName(), point.toString()));//just for diagnostics
addDocumentsAndCommit(Arrays.asList(losAngeles));
Modified: lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java (original)
+++ lucene/dev/trunk/lucene/spatial/src/test/org/apache/lucene/spatial/query/SpatialArgsParserTest.java Fri Jan 24 19:40:14 2014
@@ -34,7 +34,7 @@ public class SpatialArgsParserTest exten
public void testArgsParser() throws Exception {
SpatialArgsParser parser = new SpatialArgsParser();
- String arg = SpatialOperation.IsWithin + "(-10 -20 10 20)";
+ String arg = SpatialOperation.IsWithin + "(Envelope(-10, 10, 20, -20))";
SpatialArgs out = parser.parse(arg, ctx);
assertEquals(SpatialOperation.IsWithin, out.getOperation());
Rectangle bounds = (Rectangle) out.getShape();
@@ -42,7 +42,7 @@ public class SpatialArgsParserTest exten
assertEquals(10.0, bounds.getMaxX(), 0D);
// Disjoint should not be scored
- arg = SpatialOperation.IsDisjointTo + " (-10 10 -20 20)";
+ arg = SpatialOperation.IsDisjointTo + " (Envelope(-10,-20,20,10))";
out = parser.parse(arg, ctx);
assertEquals(SpatialOperation.IsDisjointTo, out.getOperation());
@@ -54,7 +54,7 @@ public class SpatialArgsParserTest exten
}
try {
- parser.parse("XXXX(-10 10 -20 20)", ctx);
+ parser.parse("XXXX(Envelope(-10, 10, 20, -20))", ctx);
fail("unknown operation!");
}
catch (Exception ex) {//expected
Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Fri Jan 24 19:40:14 2014
@@ -115,8 +115,8 @@ New Features
* SOLR-5506: Support docValues in CollationField and ICUCollationField.
(Robert Muir)
- * SOLR-5518: Added EditFileRequestHandler to deal with security issues around modifying
- solr configuration files.
+* SOLR-5518: Added EditFileRequestHandler to deal with security issues around modifying
+ solr configuration files.
* SOLR-5023: Add support for deleteInstanceDir to be passed from SolrJ for Core
Unload action. (Lyubov Romanchuk, shalin)
@@ -154,6 +154,10 @@ New Features
* SOLR-5594: Allow FieldTypes to specify custom PrefixQuery behavior
(Anshum Gupta via hossman)
+* LUCENE-5395: Upgrade to Spatial4j 0.4. Various new options are now exposed
+ automatically for an RPT field type. See Spatial4j CHANGES & javadocs.
+ https://github.com/spatial4j/spatial4j/blob/master/CHANGES.md (David Smiley)
+
Bug Fixes
----------------------
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/AbstractSpatialFieldType.java Fri Jan 24 19:40:14 2014
@@ -23,8 +23,7 @@ import com.google.common.cache.CacheBuil
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.context.SpatialContextFactory;
import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
-import com.spatial4j.core.io.ParseUtils;
+import com.spatial4j.core.io.LegacyShapeReadWriterFormat;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Rectangle;
import com.spatial4j.core.shape.Shape;
@@ -47,10 +46,12 @@ import org.apache.solr.response.TextResp
import org.apache.solr.search.QParser;
import org.apache.solr.search.SpatialOptions;
import org.apache.solr.util.MapListener;
+import org.apache.solr.util.SpatialUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
+import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -89,12 +90,32 @@ public abstract class AbstractSpatialFie
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Must specify units=\"degrees\" on field types with class "+getClass().getSimpleName());
+ //replace legacy rect format with ENVELOPE
+ String wbStr = args.get("worldBounds");
+ if (wbStr != null && !wbStr.toUpperCase().startsWith("ENVELOPE")) {
+ log.warn("Using old worldBounds format? Should use ENVELOPE(xMin, xMax, yMax, yMin).");
+ String[] parts = wbStr.split(" ");//"xMin yMin xMax yMax"
+ if (parts.length == 4) {
+ args.put("worldBounds",
+ "ENVELOPE(" + parts[0] + ", " + parts[2] + ", " + parts[3] + ", " + parts[1] + ")");
+ } //else likely eventual exception
+ }
+
//Solr expects us to remove the parameters we've used.
MapListener<String, String> argsWrap = new MapListener<String, String>(args);
ctx = SpatialContextFactory.makeSpatialContext(argsWrap, schema.getResourceLoader().getClassLoader());
args.keySet().removeAll(argsWrap.getSeenKeys());
- argsParser = new SpatialArgsParser();//might make pluggable some day?
+ argsParser = newSpatialArgsParser();
+ }
+
+ protected SpatialArgsParser newSpatialArgsParser() {
+ return new SpatialArgsParser() {
+ @Override
+ protected Shape parseShape(String str, SpatialContext ctx) throws ParseException {
+ return AbstractSpatialFieldType.this.parseShape(str);
+ }
+ };
}
//--------------------------------------------------------------
@@ -136,16 +157,39 @@ public abstract class AbstractSpatialFie
return result;
}
- protected Shape parseShape(String shapeStr) {
+ protected Shape parseShape(String str) {
+ if (str.length() == 0)
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "empty string shape");
+ //In Solr trunk we only support "lat, lon" (or x y) as an additional format; in v4.0 we do the
+ // weird Circle & Rect formats too (Spatial4j LegacyShapeReadWriterFormat).
try {
- return ctx.readShape(shapeStr);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
+ Shape shape = LegacyShapeReadWriterFormat.readShapeOrNull(str, ctx);
+ if (shape != null)
+ return shape;
+ return ctx.readShapeFromWkt(str);
+ } catch (Exception e) {
+ String message = e.getMessage();
+ if (!message.contains(str))
+ message = "Couldn't parse shape '" + str + "' because: " + message;
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message, e);
}
}
+ /**
+ * Returns a String version of a shape to be used for the stored value. This method in Solr is only called if for some
+ * reason a Shape object is passed to the field type (perhaps via a custom UpdateRequestProcessor),
+ * *and* the field is marked as stored. <em>The default implementation throws an exception.</em>
+ * <p/>
+ * Spatial4j 0.4 is probably the last release to support SpatialContext.toString(shape) but it's deprecated with no
+ * planned replacement. Shapes do have a toString() method but they are generally internal/diagnostic and not
+ * standard WKT.
+ * The solution is subclassing and calling ctx.toString(shape) or directly using LegacyShapeReadWriterFormat or
+ * passing in some sort of custom wrapped shape that holds a reference to a String or can generate it.
+ */
protected String shapeToString(Shape shape) {
- return ctx.toString(shape);
+// return ctx.toString(shape);
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+ "Getting a String from a Shape is no longer possible. See javadocs for commentary.");
}
/** Called from {@link #getStrategy(String)} upon first use by fieldName. } */
@@ -161,27 +205,16 @@ public abstract class AbstractSpatialFie
//--------------------------------------------------------------
/**
- * Implemented for compatibility with Solr 3 spatial geofilt & bbox query parsers:
+ * Implemented for compatibility with geofilt & bbox query parsers:
* {@link SpatialQueryable}.
*/
@Override
public Query createSpatialQuery(QParser parser, SpatialOptions options) {
- //--WARNING: the code from here to the next marker is identical to LatLonType's impl.
- double[] point = null;
- try {
- point = ParseUtils.parseLatitudeLongitude(options.pointStr);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
-
- // lat & lon in degrees
- double latCenter = point[0];
- double lonCenter = point[1];
+ Point pt = SpatialUtils.parsePointSolrException(options.pointStr, ctx);
double distDeg = DistanceUtils.dist2Degrees(options.distance, options.radius);
- //--END-WARNING
- Shape shape = ctx.makeCircle(lonCenter, latCenter, distDeg);
+ Shape shape = ctx.makeCircle(pt, distDeg);
if (options.bbox)
shape = shape.getBoundingBox();
@@ -193,12 +226,9 @@ public abstract class AbstractSpatialFie
public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
if (!minInclusive || !maxInclusive)
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Both sides of spatial range query must be inclusive: " + field.getName());
- Shape shape1 = parseShape(part1);
- Shape shape2 = parseShape(part2);
- if (!(shape1 instanceof Point) || !(shape2 instanceof Point))
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Both sides of spatial range query must be points: " + field.getName());
- Point p1 = (Point) shape1;
- Point p2 = (Point) shape2;
+ Point p1 = SpatialUtils.parsePointSolrException(part1, ctx);
+ Point p2 = SpatialUtils.parsePointSolrException(part2, ctx);
+
Rectangle bbox = ctx.makeRectangle(p1, p2);
SpatialArgs spatialArgs = new SpatialArgs(SpatialOperation.Intersects, bbox);
return getQueryFromSpatialArgs(parser, field, spatialArgs);//won't score by default
@@ -220,6 +250,8 @@ public abstract class AbstractSpatialFie
protected SpatialArgs parseSpatialArgs(String externalVal) {
try {
return argsParser.parse(externalVal, ctx);
+ } catch (SolrException e) {
+ throw e;
} catch (Exception e) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/GeoHashField.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/GeoHashField.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/GeoHashField.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/GeoHashField.java Fri Jan 24 19:40:14 2014
@@ -22,18 +22,16 @@ import org.apache.lucene.queries.functio
import org.apache.lucene.index.StorableField;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
-import com.spatial4j.core.io.ParseUtils;
import com.spatial4j.core.context.SpatialContext;
-import com.spatial4j.core.exception.InvalidShapeException;
import com.spatial4j.core.io.GeohashUtils;
import com.spatial4j.core.shape.Point;
-import org.apache.solr.common.SolrException;
import org.apache.solr.response.TextResponseWriter;
import org.apache.solr.search.QParser;
import org.apache.solr.search.SolrConstantScoreQuery;
import org.apache.solr.search.SpatialOptions;
import org.apache.solr.search.function.ValueSourceRangeFilter;
import org.apache.solr.search.function.distance.GeohashHaversineFunction;
+import org.apache.solr.util.SpatialUtils;
import java.io.IOException;
@@ -42,14 +40,9 @@ import java.io.IOException;
* This is a class that represents a <a
* href="http://en.wikipedia.org/wiki/Geohash">Geohash</a> field. The field is
* provided as a lat/lon pair and is internally represented as a string.
- *
- * @see com.spatial4j.core.io.ParseUtils#parseLatitudeLongitude(double[], String)
*/
public class GeoHashField extends FieldType implements SpatialQueryable {
-
- private final SpatialContext ctx = SpatialContext.GEO;
-
@Override
public SortField getSortField(SchemaField field, boolean top) {
return getStringSort(field, top);
@@ -60,13 +53,7 @@ public class GeoHashField extends FieldT
//encoding. Plus there are issues around the Equator/Prime Meridian
@Override
public Query createSpatialQuery(QParser parser, SpatialOptions options) {
- double [] point = new double[0];
- try {
- point = ParseUtils.parsePointDouble(null, options.pointStr, 2);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
- String geohash = GeohashUtils.encodeLatLon(point[0], point[1]);
+ String geohash = toInternal(options.pointStr);
//TODO: optimize this
return new SolrConstantScoreQuery(new ValueSourceRangeFilter(new GeohashHaversineFunction(getValueSource(options.field, parser),
new LiteralValueSource(geohash), options.radius), "0", String.valueOf(options.distance), true, true));
@@ -78,33 +65,22 @@ public class GeoHashField extends FieldT
writer.writeStr(name, toExternal(f), false);
}
-
@Override
public String toExternal(StorableField f) {
- Point p = GeohashUtils.decode(f.stringValue(),ctx);
+ Point p = GeohashUtils.decode(f.stringValue(), SpatialContext.GEO);
return p.getY() + "," + p.getX();
}
-
@Override
public String toInternal(String val) {
- // validate that the string is of the form
- // latitude, longitude
- double[] latLon = new double[0];
- try {
- latLon = ParseUtils.parseLatitudeLongitude(null, val);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
- return GeohashUtils.encodeLatLon(latLon[0], latLon[1]);
+ Point point = SpatialUtils.parsePointSolrException(val, SpatialContext.GEO);
+ return GeohashUtils.encodeLatLon(point.getY(), point.getX());
}
-
@Override
public ValueSource getValueSource(SchemaField field, QParser parser) {
field.checkFieldCacheSource(parser);
return new StrFieldSource(field.name);
}
-
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/LatLonType.java Fri Jan 24 19:40:14 2014
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import com.spatial4j.core.shape.Point;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.IndexReader;
@@ -49,9 +50,8 @@ import org.apache.solr.search.SpatialOpt
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
-import com.spatial4j.core.io.ParseUtils;
import com.spatial4j.core.shape.Rectangle;
+import org.apache.solr.util.SpatialUtils;
/**
@@ -71,24 +71,16 @@ public class LatLonType extends Abstract
@Override
public List<StorableField> createFields(SchemaField field, Object value, float boost) {
String externalVal = value.toString();
- //we could have tileDiff + 3 fields (two for the lat/lon, one for storage)
+ //we could have 3 fields (two for the lat & lon, one for storage)
List<StorableField> f = new ArrayList<StorableField>(3);
if (field.indexed()) {
- int i = 0;
- double[] latLon;
- try {
- latLon = ParseUtils.parseLatitudeLongitude(null, externalVal);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
+ Point point = SpatialUtils.parsePointSolrException(externalVal, SpatialContext.GEO);
//latitude
- SchemaField lat = subField(field, i, schema);
- f.add(lat.createField(String.valueOf(latLon[LAT]), lat.indexed() && !lat.omitNorms() ? boost : 1f));
- i++;
+ SchemaField subLatSF = subField(field, LAT, schema);
+ f.add(subLatSF.createField(String.valueOf(point.getY()), subLatSF.indexed() && !subLatSF.omitNorms() ? boost : 1f));
//longitude
- SchemaField lon = subField(field, i, schema);
- f.add(lon.createField(String.valueOf(latLon[LON]), lon.indexed() && !lon.omitNorms() ? boost : 1f));
-
+ SchemaField subLonSF = subField(field, LON, schema);
+ f.add(subLonSF.createField(String.valueOf(point.getX()), subLonSF.indexed() && !subLonSF.omitNorms() ? boost : 1f));
}
if (field.stored()) {
@@ -102,59 +94,43 @@ public class LatLonType extends Abstract
@Override
public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
- int dimension = 2;
+ Point p1 = SpatialUtils.parsePointSolrException(part1, SpatialContext.GEO);
+ Point p2 = SpatialUtils.parsePointSolrException(part2, SpatialContext.GEO);
- String[] p1;
- String[] p2;
- try {
- p1 = ParseUtils.parsePoint(null, part1, dimension);
- p2 = ParseUtils.parsePoint(null, part2, dimension);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
+ SchemaField latSF = subField(field, LAT, parser.getReq().getSchema());
+ SchemaField lonSF = subField(field, LON, parser.getReq().getSchema());
BooleanQuery result = new BooleanQuery(true);
- for (int i = 0; i < dimension; i++) {
- SchemaField subSF = subField(field, i, parser.getReq().getSchema());
- // points must currently be ordered... should we support specifying any two opposite corner points?
- result.add(subSF.getType().getRangeQuery(parser, subSF, p1[i], p2[i], minInclusive, maxInclusive), BooleanClause.Occur.MUST);
- }
+ // points must currently be ordered... should we support specifying any two opposite corner points?
+ result.add(latSF.getType().getRangeQuery(parser, latSF,
+ Double.toString(p1.getY()), Double.toString(p2.getY()), minInclusive, maxInclusive), BooleanClause.Occur.MUST);
+ result.add(lonSF.getType().getRangeQuery(parser, lonSF,
+ Double.toString(p1.getX()), Double.toString(p2.getX()), minInclusive, maxInclusive), BooleanClause.Occur.MUST);
return result;
-
}
@Override
public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
- int dimension = 2;
-
- String[] p1 = new String[0];
- try {
- p1 = ParseUtils.parsePoint(null, externalVal, dimension);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
- BooleanQuery bq = new BooleanQuery(true);
- for (int i = 0; i < dimension; i++) {
- SchemaField sf = subField(field, i, parser.getReq().getSchema());
- Query tq = sf.getType().getFieldQuery(parser, sf, p1[i]);
- bq.add(tq, BooleanClause.Occur.MUST);
- }
- return bq;
+ Point p1 = SpatialUtils.parsePointSolrException(externalVal, SpatialContext.GEO);
+
+ SchemaField latSF = subField(field, LAT, parser.getReq().getSchema());
+ SchemaField lonSF = subField(field, LON, parser.getReq().getSchema());
+ BooleanQuery result = new BooleanQuery(true);
+ result.add(latSF.getType().getFieldQuery(parser, latSF,
+ Double.toString(p1.getY())), BooleanClause.Occur.MUST);
+ result.add(lonSF.getType().getFieldQuery(parser, lonSF,
+ Double.toString(p1.getX())), BooleanClause.Occur.MUST);
+ return result;
}
@Override
public Query createSpatialQuery(QParser parser, SpatialOptions options) {
- double[] point = null;
- try {
- point = ParseUtils.parseLatitudeLongitude(options.pointStr);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
+ Point point = SpatialUtils.parsePointSolrException(options.pointStr, SpatialContext.GEO);
// lat & lon in degrees
- double latCenter = point[LAT];
- double lonCenter = point[LON];
+ double latCenter = point.getY();
+ double lonCenter = point.getX();
double distDeg = DistanceUtils.dist2Degrees(options.distance, options.radius);
Rectangle bbox = DistanceUtils.calcBoxByDistFromPtDEG(latCenter, lonCenter, distDeg, SpatialContext.GEO, null);
@@ -176,8 +152,8 @@ public class LatLonType extends Abstract
IndexSchema schema = parser.getReq().getSchema();
// Now that we've figured out the ranges, build them!
- SchemaField latField = subField(options.field, LAT, schema);
- SchemaField lonField = subField(options.field, LON, schema);
+ SchemaField latSF = subField(options.field, LAT, schema);
+ SchemaField lonSF = subField(options.field, LON, schema);
SpatialDistanceQuery spatial = new SpatialDistanceQuery();
@@ -185,14 +161,14 @@ public class LatLonType extends Abstract
if (options.bbox) {
BooleanQuery result = new BooleanQuery();
- Query latRange = latField.getType().getRangeQuery(parser, latField,
+ Query latRange = latSF.getType().getRangeQuery(parser, latSF,
String.valueOf(latMin),
String.valueOf(latMax),
true, true);
result.add(latRange, BooleanClause.Occur.MUST);
if (lonMin != -180 || lonMax != 180) {
- Query lonRange = lonField.getType().getRangeQuery(parser, lonField,
+ Query lonRange = lonSF.getType().getRangeQuery(parser, lonSF,
String.valueOf(lonMin),
String.valueOf(lonMax),
true, true);
@@ -201,7 +177,7 @@ public class LatLonType extends Abstract
BooleanQuery bothLons = new BooleanQuery();
bothLons.add(lonRange, BooleanClause.Occur.SHOULD);
- lonRange = lonField.getType().getRangeQuery(parser, lonField,
+ lonRange = lonSF.getType().getRangeQuery(parser, lonSF,
String.valueOf(lon2Min),
String.valueOf(lon2Max),
true, true);
@@ -218,8 +194,8 @@ public class LatLonType extends Abstract
spatial.origField = options.field.getName();
- spatial.latSource = latField.getType().getValueSource(latField, parser);
- spatial.lonSource = lonField.getType().getValueSource(lonField, parser);
+ spatial.latSource = latSF.getType().getValueSource(latSF, parser);
+ spatial.lonSource = lonSF.getType().getValueSource(lonSF, parser);
spatial.latMin = latMin;
spatial.latMax = latMax;
spatial.lonMin = lonMin;
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/PointType.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/PointType.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/PointType.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/schema/PointType.java Fri Jan 24 19:40:14 2014
@@ -25,9 +25,6 @@ import org.apache.lucene.search.BooleanC
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
-import com.spatial4j.core.io.ParseUtils;
-import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.SolrParams;
@@ -51,7 +48,7 @@ public class PointType extends Coordinat
SolrParams p = new MapSolrParams(args);
dimension = p.getInt(DIMENSION, DEFAULT_DIMENSION);
if (dimension < 1) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"The dimension must be > 0: " + dimension);
}
args.remove(DIMENSION);
@@ -70,12 +67,7 @@ public class PointType extends Coordinat
@Override
public List<StorableField> createFields(SchemaField field, Object value, float boost) {
String externalVal = value.toString();
- String[] point = new String[0];
- try {
- point = ParseUtils.parsePoint(null, externalVal, dimension);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
+ String[] point = parseCommaSeparatedList(externalVal, dimension);
// TODO: this doesn't currently support polyFields as sub-field types
List<StorableField> f = new ArrayList<StorableField>(dimension+1);
@@ -135,14 +127,9 @@ public class PointType extends Coordinat
public Query getRangeQuery(QParser parser, SchemaField field, String part1, String part2, boolean minInclusive, boolean maxInclusive) {
//Query could look like: [x1,y1 TO x2,y2] for 2 dimension, but could look like: [x1,y1,z1 TO x2,y2,z2], and can be extrapolated to n-dimensions
//thus, this query essentially creates a box, cube, etc.
- String[] p1;
- String[] p2;
- try {
- p1 = ParseUtils.parsePoint(null, part1, dimension);
- p2 = ParseUtils.parsePoint(null, part2, dimension);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
+ String[] p1 = parseCommaSeparatedList(part1, dimension);
+ String[] p2 = parseCommaSeparatedList(part2, dimension);
+
BooleanQuery result = new BooleanQuery(true);
for (int i = 0; i < dimension; i++) {
SchemaField subSF = subField(field, i, schema);
@@ -154,12 +141,7 @@ public class PointType extends Coordinat
@Override
public Query getFieldQuery(QParser parser, SchemaField field, String externalVal) {
- String[] p1 = new String[0];
- try {
- p1 = ParseUtils.parsePoint(null, externalVal, dimension);
- } catch (InvalidShapeException e) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
- }
+ String[] p1 = parseCommaSeparatedList(externalVal, dimension);
//TODO: should we assert that p1.length == dimension?
BooleanQuery bq = new BooleanQuery(true);
for (int i = 0; i < dimension; i++) {
@@ -171,18 +153,22 @@ public class PointType extends Coordinat
}
/**
- * Calculates the range and creates a RangeQuery (bounding box) wrapped in a BooleanQuery (unless the dimension is 1, one range for every dimension, AND'd together by a Boolean
- * @param parser The parser
+ * Calculates the range and creates a RangeQuery (bounding box) wrapped in a BooleanQuery (unless the dimension is
+ * 1, one range for every dimension, AND'd together by a Boolean
+ *
+ * @param parser The parser
* @param options The {@link org.apache.solr.search.SpatialOptions} for this filter.
* @return The Query representing the bounding box around the point.
*/
@Override
public Query createSpatialQuery(QParser parser, SpatialOptions options) {
- Query result = null;
- double [] point = new double[0];
+ String[] pointStrs = parseCommaSeparatedList(options.pointStr, dimension);
+ double[] point = new double[dimension];
try {
- point = ParseUtils.parsePointDouble(null, options.pointStr, dimension);
- } catch (InvalidShapeException e) {
+ for (int i = 0; i < pointStrs.length; i++) {
+ point[i] = Double.parseDouble(pointStrs[i]);
+ }
+ } catch (NumberFormatException e) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e);
}
IndexSchema schema = parser.getReq().getSchema();
@@ -192,22 +178,95 @@ public class PointType extends Coordinat
String upper = String.valueOf(point[0] + options.distance);
SchemaField subSF = subField(options.field, 0, schema);
// points must currently be ordered... should we support specifying any two opposite corner points?
- result = subSF.getType().getRangeQuery(parser, subSF, lower, upper, true, true);
+ return subSF.getType().getRangeQuery(parser, subSF, lower, upper, true, true);
} else {
BooleanQuery tmp = new BooleanQuery();
//TODO: Handle distance measures, as this assumes Euclidean
- double [] ur = DistanceUtils.vectorBoxCorner(point, null, options.distance, true);
- double [] ll = DistanceUtils.vectorBoxCorner(point, null, options.distance, false);
+ double[] ur = vectorBoxCorner(point, null, options.distance, true);
+ double[] ll = vectorBoxCorner(point, null, options.distance, false);
for (int i = 0; i < ur.length; i++) {
SchemaField subSF = subField(options.field, i, schema);
Query range = subSF.getType().getRangeQuery(parser, subSF, String.valueOf(ll[i]), String.valueOf(ur[i]), true, true);
tmp.add(range, BooleanClause.Occur.MUST);
-
}
- result = tmp;
+ return tmp;
+ }
+ }
+
+ private static final double SIN_PI_DIV_4 = Math.sin(Math.PI / 4);
+
+ /**
+ * Return the coordinates of a vector that is the corner of a box (upper right or lower left), assuming a Rectangular
+ * coordinate system. Note, this does not apply for points on a sphere or ellipse (although it could be used as an
+ * approximation).
+ *
+ * @param center The center point
+ * @param result Holds the result, potentially resizing if needed.
+ * @param distance The d from the center to the corner
+ * @param upperRight If true, return the coords for the upper right corner, else return the lower left.
+ * @return The point, either the upperLeft or the lower right
+ */
+ public static double[] vectorBoxCorner(double[] center, double[] result, double distance, boolean upperRight) {
+ if (result == null || result.length != center.length) {
+ result = new double[center.length];
+ }
+ if (upperRight == false) {
+ distance = -distance;
+ }
+ //We don't care about the power here,
+ // b/c we are always in a rectangular coordinate system, so any norm can be used by
+ //using the definition of sine
+ distance = SIN_PI_DIV_4 * distance; // sin(Pi/4) == (2^0.5)/2 == opp/hyp == opp/distance, solve for opp, similarly for cosine
+ for (int i = 0; i < center.length; i++) {
+ result[i] = center[i] + distance;
}
return result;
}
+
+ /**
+ * Given a string containing <i>dimension</i> values encoded in it, separated by commas,
+ * return a String array of length <i>dimension</i> containing the values.
+ *
+ * @param externalVal The value to parse
+ * @param dimension The expected number of values for the point
+ * @return An array of the values that make up the point (aka vector)
+ * @throws SolrException if the dimension specified does not match the number found
+ */
+ public static String[] parseCommaSeparatedList(String externalVal, int dimension) throws SolrException {
+ //TODO: Should we support sparse vectors?
+ String[] out = new String[dimension];
+ int idx = externalVal.indexOf(',');
+ int end = idx;
+ int start = 0;
+ int i = 0;
+ if (idx == -1 && dimension == 1 && externalVal.length() > 0) {//we have a single point, dimension better be 1
+ out[0] = externalVal.trim();
+ i = 1;
+ } else if (idx > 0) {//if it is zero, that is an error
+ //Parse out a comma separated list of values, as in: 73.5,89.2,7773.4
+ for (; i < dimension; i++) {
+ while (start < end && externalVal.charAt(start) == ' ') start++;
+ while (end > start && externalVal.charAt(end - 1) == ' ') end--;
+ if (start == end) {
+ break;
+ }
+ out[i] = externalVal.substring(start, end);
+ start = idx + 1;
+ end = externalVal.indexOf(',', start);
+ idx = end;
+ if (end == -1) {
+ end = externalVal.length();
+ }
+ }
+ }
+ if (i != dimension) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ "incompatible dimension (" + dimension +
+ ") and values (" + externalVal + "). Only " + i + " values specified");
+ }
+ return out;
+ }
+
}
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/GeoDistValueSourceParser.java Fri Jan 24 19:40:14 2014
@@ -17,9 +17,8 @@ package org.apache.solr.search.function.
* limitations under the License.
*/
+import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
-import com.spatial4j.core.exception.InvalidShapeException;
-import com.spatial4j.core.io.ParseUtils;
import com.spatial4j.core.shape.Point;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.valuesource.ConstNumberSource;
@@ -34,6 +33,7 @@ import org.apache.solr.schema.SchemaFiel
import org.apache.solr.search.FunctionQParser;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.ValueSourceParser;
+import org.apache.solr.util.SpatialUtils;
import java.util.Arrays;
import java.util.Collections;
@@ -134,9 +134,7 @@ public class GeoDistValueSourceParser ex
// note: uses Haversine by default but can be changed via distCalc=...
SpatialStrategy strategy = ((SpatialStrategyMultiValueSource) mv2).strategy;
Point queryPoint = strategy.getSpatialContext().makePoint(constants[1], constants[0]);
- //TODO Spatial4j 0.4 will have a direct constant
- double multiplier = DistanceUtils.degrees2Dist(1, DistanceUtils.EARTH_MEAN_RADIUS_KM);
- return strategy.makeDistanceValueSource(queryPoint, multiplier);
+ return strategy.makeDistanceValueSource(queryPoint, DistanceUtils.DEG_TO_KM);
}
if (constants != null && other instanceof VectorValueSource) {
@@ -158,15 +156,12 @@ public class GeoDistValueSourceParser ex
}
private MultiValueSource parsePoint(FunctionQParser fp) throws SyntaxError {
- String pt = fp.getParam(SpatialParams.POINT);
- if (pt == null) return null;
- double[] point = null;
- try {
- point = ParseUtils.parseLatitudeLongitude(pt);
- } catch (InvalidShapeException e) {
- throw new SyntaxError("Bad spatial pt:" + pt);
- }
- return new VectorValueSource(Arrays.<ValueSource>asList(new DoubleConstValueSource(point[0]), new DoubleConstValueSource(point[1])));
+ String ptStr = fp.getParam(SpatialParams.POINT);
+ if (ptStr == null) return null;
+ Point point = SpatialUtils.parsePointSolrException(ptStr, SpatialContext.GEO);
+ //assume Lat Lon order
+ return new VectorValueSource(
+ Arrays.<ValueSource>asList(new DoubleConstValueSource(point.getY()), new DoubleConstValueSource(point.getX())));
}
private double[] getConstants(MultiValueSource vs) {
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java Fri Jan 24 19:40:14 2014
@@ -18,7 +18,6 @@ package org.apache.solr.search.function.
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.valuesource.MultiValueSource;
-import com.spatial4j.core.distance.DistanceUtils;
/**
* While not strictly a distance, the Sq. Euclidean Distance is often all that is needed in many applications
@@ -49,7 +48,7 @@ public class SquaredEuclideanFunction ex
dv1.doubleVal(doc, vals1);
dv2.doubleVal(doc, vals2);
- return DistanceUtils.distSquaredCartesian(vals1, vals2);
+ return distSquaredCartesian(vals1, vals2);
}
@Override
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java Fri Jan 24 19:40:14 2014
@@ -22,7 +22,6 @@ import org.apache.lucene.queries.functio
import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import org.apache.lucene.queries.function.valuesource.MultiValueSource;
import org.apache.lucene.search.IndexSearcher;
-import com.spatial4j.core.distance.DistanceUtils;
import org.apache.solr.common.SolrException;
import java.io.IOException;
@@ -75,7 +74,79 @@ public class VectorDistanceFunction exte
double[] vals2 = new double[source1.dimension()];
dv1.doubleVal(doc, vals1);
dv2.doubleVal(doc, vals2);
- return DistanceUtils.vectorDistance(vals1, vals2, power, oneOverPower);
+ return vectorDistance(vals1, vals2, power, oneOverPower);
+ }
+
+ /**
+ * Calculate the p-norm (i.e. length) between two vectors.
+ * <p/>
+ * See <a href="http://en.wikipedia.org/wiki/Lp_space">Lp space</a>
+ *
+ * @param vec1 The first vector
+ * @param vec2 The second vector
+ * @param power The power (2 for cartesian distance, 1 for manhattan, etc.)
+ * @return The length.
+ *
+ * @see #vectorDistance(double[], double[], double, double)
+ *
+ */
+ public static double vectorDistance(double[] vec1, double[] vec2, double power) {
+ //only calc oneOverPower if it's needed
+ double oneOverPower = (power == 0 || power == 1.0 || power == 2.0) ? Double.NaN : 1.0 / power;
+ return vectorDistance(vec1, vec2, power, oneOverPower);
+ }
+
+ /**
+ * Calculate the p-norm (i.e. length) between two vectors.
+ *
+ * @param vec1 The first vector
+ * @param vec2 The second vector
+ * @param power The power (2 for cartesian distance, 1 for manhattan, etc.)
+ * @param oneOverPower If you've pre-calculated oneOverPower and cached it, use this method to save
+ * one division operation over {@link #vectorDistance(double[], double[], double)}.
+ * @return The length.
+ */
+ public static double vectorDistance(double[] vec1, double[] vec2, double power, double oneOverPower) {
+ double result = 0;
+
+ if (power == 0) {
+ for (int i = 0; i < vec1.length; i++) {
+ result += vec1[i] - vec2[i] == 0 ? 0 : 1;
+ }
+ } else if (power == 1.0) { // Manhattan
+ for (int i = 0; i < vec1.length; i++) {
+ result += Math.abs(vec1[i] - vec2[i]);
+ }
+ } else if (power == 2.0) { // Cartesian
+ result = Math.sqrt(distSquaredCartesian(vec1, vec2));
+ } else if (power == Integer.MAX_VALUE || Double.isInfinite(power)) {//infinite norm?
+ for (int i = 0; i < vec1.length; i++) {
+ result = Math.max(result, Math.max(vec1[i], vec2[i]));
+ }
+ } else {
+ for (int i = 0; i < vec1.length; i++) {
+ result += Math.pow(vec1[i] - vec2[i], power);
+ }
+ result = Math.pow(result, oneOverPower);
+ }
+ return result;
+ }
+
+ /**
+ * The square of the cartesian Distance. Not really a distance, but useful if all that matters is
+ * comparing the result to another one.
+ *
+ * @param vec1 The first point
+ * @param vec2 The second point
+ * @return The squared cartesian distance
+ */
+ public static double distSquaredCartesian(double[] vec1, double[] vec2) {
+ double result = 0;
+ for (int i = 0; i < vec1.length; i++) {
+ double v = vec1[i] - vec2[i];
+ result += v * v;
+ }
+ return result;
}
@Override
Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SpatialUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SpatialUtils.java?rev=1561129&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SpatialUtils.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SpatialUtils.java Fri Jan 24 19:40:14 2014
@@ -0,0 +1,92 @@
+package org.apache.solr.util;
+
+/*
+ * 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.
+ */
+
+import com.spatial4j.core.context.SpatialContext;
+import com.spatial4j.core.exception.InvalidShapeException;
+import com.spatial4j.core.shape.Point;
+import org.apache.solr.common.SolrException;
+
+/** Utility methods pertaining to spatial. */
+public class SpatialUtils {
+
+ private SpatialUtils() {}
+
+ /** Parses either "lat, lon" (spaces optional on either comma side) or "x y" style formats. Spaces can be basically
+ * anywhere. And not any whitespace, just the space char.
+ *
+ * @param str Non-null; may have leading or trailing spaces
+ * @param ctx Non-null
+ * @return Non-null
+ * @throws InvalidShapeException If for any reason there was a problem parsing the string or creating the point.
+ */
+ public static Point parsePoint(String str, SpatialContext ctx) throws InvalidShapeException {
+ //note we don't do generic whitespace, just a literal space char detection
+ //TODO: decide on if we should pick one format decided by ctx.isGeo()
+ // Perhaps 5x use isGeo; 4x use either?
+ try {
+ double x, y;
+ str = str.trim();//TODO use findIndexNotSpace instead?
+ int commaIdx = str.indexOf(',');
+ if (commaIdx == -1) {
+ // "x y" format
+ int spaceIdx = str.indexOf(' ');
+ if (spaceIdx == -1)
+ throw new InvalidShapeException("Point must be in 'lat, lon' or 'x y' format: " + str);
+ int middleEndIdx = findIndexNotSpace(str, spaceIdx + 1, +1);
+ x = Double.parseDouble(str.substring(0, spaceIdx));
+ y = Double.parseDouble(str.substring(middleEndIdx));
+ } else {
+ // "lat, lon" format
+ int middleStartIdx = findIndexNotSpace(str, commaIdx - 1, -1);
+ int middleEndIdx = findIndexNotSpace(str, commaIdx + 1, +1);
+ y = Double.parseDouble(str.substring(0, middleStartIdx + 1));
+ x = Double.parseDouble(str.substring(middleEndIdx));
+ }
+
+ x = ctx.normX(x);//by default norm* methods do nothing but perhaps it's been customized
+ y = ctx.normY(y);
+ return ctx.makePoint(x, y);//will verify x & y fit in boundary
+ } catch (InvalidShapeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new InvalidShapeException(e.toString(), e);
+ }
+ }
+
+ private static int findIndexNotSpace(String str, int startIdx, int inc) {
+ assert inc == +1 || inc == -1;
+ int idx = startIdx;
+ while (idx >= 0 && idx < str.length() && str.charAt(idx) == ' ')
+ idx += inc;
+ return idx;
+ }
+
+ /** Calls {@link #parsePoint(String, com.spatial4j.core.context.SpatialContext)} and wraps
+ * the exception with {@link org.apache.solr.common.SolrException} with a helpful message. */
+ public static Point parsePointSolrException(String externalVal, SpatialContext ctx) throws SolrException {
+ try {
+ return parsePoint(externalVal, ctx);
+ } catch (InvalidShapeException e) {
+ String message = e.getMessage();
+ if (!message.contains(externalVal))
+ message = "Can't parse point '" + externalVal + "' because: " + message;
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, message, e);
+ }
+ }
+}
Modified: lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml?rev=1561129&r1=1561128&r2=1561129&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml (original)
+++ lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/schema-spatial.xml Fri Jan 24 19:40:14 2014
@@ -39,11 +39,13 @@
prefixTree="geohash" units="degrees" />
<fieldType name="stqpt_u" class="solr.SpatialTermQueryPrefixTreeFieldType"
- geo="false" distCalculator="cartesian^2" worldBounds="0 0 1000 1000" units="degrees"/>
+ geo="false" distCalculator="cartesian^2" worldBounds="ENVELOPE(0, 1000, 1000, 0)" units="degrees"/>
<fieldType name="pointvector" class="solr.SpatialPointVectorFieldType"
numberType="tdouble" units="degrees"/>
+ <fieldType name="stqpt_u_oldworldbounds" class="solr.SpatialTermQueryPrefixTreeFieldType"
+ geo="false" distCalculator="cartesian^2" worldBounds="0 0 1000 1000" units="degrees"/>
</types>