| Index: contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java (revision 833867) |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java Wed Jan 20 14:35:46 CET 2010 |
| @@ -31,8 +31,10 @@ |
| /** <p><font color="red"><b>NOTE:</b> This API is still in |
| * flux and might change in incompatible ways in the next |
| * release.</font> |
| + * |
| + * @deprecated This class has been replaced by DistanceFilter and GeoHashPointDecoder. It will be removed. |
| */ |
| - |
| +@Deprecated |
| public class GeoHashDistanceFilter extends DistanceFilter { |
| |
| /** |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/GeoHashPointDecoder.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/GeoHashPointDecoder.java Wed Jan 20 15:06:23 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/GeoHashPointDecoder.java Wed Jan 20 15:06:23 CET 2010 |
| @@ -0,0 +1,65 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.search.FieldCache; |
| +import org.apache.lucene.spatial.geohash.GeoHashUtils; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * PointDecoder which uses {@link org.apache.lucene.spatial.geohash.GeoHashUtils#decode(String)} to decode the point |
| + * data for a document. |
| + */ |
| +public class GeoHashPointDecoder implements PointDecoder { |
| + |
| + private final String geoHashField; |
| + |
| + /** |
| + * Creates a new GeoHashPointDecoder that decodes the data taken from the given field |
| + * |
| + * @param geoHashField Name of the field in documents where the encoded geohash data is |
| + */ |
| + public GeoHashPointDecoder(String geoHashField) { |
| + this.geoHashField = geoHashField; |
| + } |
| + |
| + /** |
| + * {@inheritDoc} |
| + */ |
| + public Point getPoint(int docId, IndexReader reader) throws IOException { |
| + double[] coords = GeoHashUtils.decode(getGeoHash(docId, reader)); |
| + return new Point(coords[0], coords[1]); |
| + } |
| + |
| + // ================================================= Helper Methods ================================================ |
| + |
| + /** |
| + * Retrieves the geohash for the document through the IndexReader |
| + * |
| + * @param docId ID of the document whose geohash is to be retrieved |
| + * @param reader IndexReader through which the hash can be retrieved |
| + * @return Geohash for the document |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + String getGeoHash(int docId, IndexReader reader) throws IOException { |
| + FieldCache.StringIndex stringIndex = FieldCache.DEFAULT.getStringIndex(reader, geoHashField); |
| + return stringIndex.lookup[stringIndex.order[docId]]; |
| + } |
| +} |
| Index: contrib/spatial/src/test/org/apache/lucene/spatial/distance/GeoHashPointDecoderTest.java |
| =================================================================== |
| --- contrib/spatial/src/test/org/apache/lucene/spatial/distance/GeoHashPointDecoderTest.java Wed Jan 20 15:08:50 CET 2010 |
| +++ contrib/spatial/src/test/org/apache/lucene/spatial/distance/GeoHashPointDecoderTest.java Wed Jan 20 15:08:50 CET 2010 |
| @@ -0,0 +1,49 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import junit.framework.TestCase; |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Tests for {@link org.apache.lucene.spatial.distance.GeoHashPointDecoder} |
| + */ |
| +public class GeoHashPointDecoderTest extends TestCase { |
| + |
| + /** |
| + * Pass condition: The geohash for the document is retrieved and decoded into a Point |
| + * |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + public void testGetPoint() throws IOException { |
| + GeoHashPointDecoder pointDecoder = new GeoHashPointDecoder("geohash") { |
| + |
| + @Override |
| + String getGeoHash(int docId, IndexReader reader) throws IOException { |
| + return "ezs42e44yx96"; |
| + } |
| + }; |
| + |
| + Point point = pointDecoder.getPoint(0, null); |
| + |
| + assertEquals(42.6, point.getX(), 0.00001D); |
| + assertEquals(-5.6, point.getY(), 0.00001D); |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/SimpleDocumentDistanceSource.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/SimpleDocumentDistanceSource.java Wed Jan 20 15:08:44 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/SimpleDocumentDistanceSource.java Wed Jan 20 15:08:44 CET 2010 |
| @@ -0,0 +1,53 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.DistanceUnits; |
| +import org.apache.lucene.spatial.geometry.GeoDistanceCalculator; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Simple implementation of {@link DocumentDistanceSource} which calculates the distance eachtime without any caching. |
| + */ |
| +public class SimpleDocumentDistanceSource implements DocumentDistanceSource { |
| + |
| + private final PointDecoder pointDecoder; |
| + private final GeoDistanceCalculator distanceCalculator; |
| + |
| + /** |
| + * Creates a new SimpleDocumentDistanceSource which uses the given PointDecoder to retrieve the Points for documents, |
| + * and the given GeoDistanceCalculator to calculate the distance |
| + * |
| + * @param pointDecoder PointDecoder to use to retrieve Points for documents |
| + * @param distanceCalculator GeoDistanceCalculator to use to calculate the actual distances |
| + */ |
| + public SimpleDocumentDistanceSource(PointDecoder pointDecoder, GeoDistanceCalculator distanceCalculator) { |
| + this.pointDecoder = pointDecoder; |
| + this.distanceCalculator = distanceCalculator; |
| + } |
| + |
| + /** |
| + * {@inheritDoc} |
| + */ |
| + public double getDocumentDistance(int docId, Point src, IndexReader indexReader, DistanceUnits units) throws IOException { |
| + Point docPoint = pointDecoder.getPoint(docId, indexReader); |
| + return distanceCalculator.calculate(src.getX(), src.getY(), docPoint.getX(), docPoint.getY(), units); |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/NoOpDistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/NoOpDistanceFilter.java Sun Jan 17 15:37:16 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/NoOpDistanceFilter.java Sun Jan 17 15:37:16 CET 2010 |
| @@ -0,0 +1,44 @@ |
| +/** |
| + * 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| + |
| +import java.io.IOException; |
| +import java.util.BitSet; |
| +import java.util.Collections; |
| +import java.util.Map; |
| + |
| +/** |
| + * Implementation of {@link DistanceFilter} that does no actual filtering. This means that there can always be a DistanceFilter |
| + * instantiated, but that the actual process of filtering documents by their distance, which is a computationally expensive |
| + * process, doesn't always have to occur. |
| + * |
| + * <p><font color="red"><b>NOTE:</b> This API is still in flux and might change in incompatible ways in the next release.</font> |
| + */ |
| +public class NoOpDistanceFilter implements DistanceFilter { |
| + |
| + /** |
| + * Executes no filtering. Simply returns the given BitSet |
| + * <p/> |
| + * {@inheritDoc} |
| + */ |
| + public BitSet bits(IndexReader reader, BitSet bits) throws IOException { |
| + return bits; |
| + } |
| +} |
| Index: contrib/spatial/src/test/org/apache/lucene/spatial/distance/TestThreadedDistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/test/org/apache/lucene/spatial/distance/TestThreadedDistanceFilter.java Wed Jan 20 15:05:00 CET 2010 |
| +++ contrib/spatial/src/test/org/apache/lucene/spatial/distance/TestThreadedDistanceFilter.java Wed Jan 20 15:05:00 CET 2010 |
| @@ -0,0 +1,264 @@ |
| +/** |
| + * 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.lucene.spatial.distance; |
| + |
| +import junit.framework.TestCase; |
| +import org.apache.lucene.analysis.standard.StandardAnalyzer; |
| +import org.apache.lucene.document.Document; |
| +import org.apache.lucene.document.Field; |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.index.IndexWriter; |
| +import org.apache.lucene.spatial.geometry.ArcGeoDistanceCalculator; |
| +import org.apache.lucene.spatial.geometry.DistanceUnits; |
| +import org.apache.lucene.spatial.geometry.GeoDistanceCalculator; |
| +import org.apache.lucene.spatial.geometry.Point; |
| +import org.apache.lucene.store.Directory; |
| +import org.apache.lucene.store.RAMDirectory; |
| +import org.apache.lucene.util.Version; |
| + |
| +import java.io.IOException; |
| +import java.util.*; |
| +import java.util.concurrent.*; |
| + |
| +/** |
| + * Tests for {@link TestThreadedDistanceFilter} |
| + */ |
| +public class TestThreadedDistanceFilter extends TestCase { |
| + |
| + private final List<Point> testPoints = Arrays.asList(new Point(4.53, 30.61), new Point(4.51, 31.01), new Point(5.69, 40.89)); |
| + |
| + private final PointDecoder pointDecoder = new PointDecoder() { |
| + |
| + public Point getPoint(int docId, IndexReader reader) throws IOException { |
| + return testPoints.get(docId); |
| + } |
| + }; |
| + |
| + private Directory directory; |
| + |
| + /** |
| + * Creates a new in-memory Directory containing an index with a document for each point in {@link #testPoints} |
| + * |
| + * @throws IOException Can be thrown creating the index |
| + */ |
| + public void setUp() throws IOException { |
| + directory = new RAMDirectory(); |
| + IndexWriter indexWriter = new IndexWriter(directory, new StandardAnalyzer(Version.LUCENE_CURRENT), IndexWriter.MaxFieldLength.UNLIMITED); |
| + for (int i = 0; i < testPoints.size(); i++) { |
| + addDocument(indexWriter, i); |
| + } |
| + indexWriter.commit(); |
| + indexWriter.close(); |
| + } |
| + |
| + /** |
| + * Closes the Directory |
| + * |
| + * @throws IOException Can be thrown closing the Directory |
| + */ |
| + public void tearDown() throws IOException { |
| + directory.close(); |
| + } |
| + |
| + /** |
| + * Adds a Document with a single field "id" with the given id as its value |
| + * |
| + * @param indexWriter IndexWriter to write the document too |
| + * @param id ID that the document will have |
| + * @throws IOException Can be thrown while writing document to the index |
| + */ |
| + private void addDocument(IndexWriter indexWriter, int id) throws IOException { |
| + Document document = new Document(); |
| + document.add(new Field("id", String.valueOf(id), Field.Store.YES, Field.Index.ANALYZED)); |
| + indexWriter.addDocument(document); |
| + } |
| + |
| + /** |
| + * Pass condition: The latitude/longitude values have to be passed to the GeoDistanceCalculator in the correct order |
| + * |
| + * @throws IOException Can be thrown reading from the index |
| + */ |
| + public void testGeoCalculation_correctArgumentPassing() throws IOException { |
| + StubGeoDistanceCalculator distanceCalculator = new StubGeoDistanceCalculator(); |
| + ExecutorService executorService = Executors.newFixedThreadPool(1); |
| + |
| + DocumentDistanceSource distanceSource = new SimpleDocumentDistanceSource(pointDecoder, distanceCalculator); |
| + |
| + ThreadedDistanceFilter filter = |
| + new ThreadedDistanceFilter(new Point(4.51, 31.01), 10, DistanceUnits.KILOMETERS, distanceSource, executorService, 1); |
| + |
| + IndexReader indexReader = IndexReader.open(directory); |
| + BitSet bitSet = new BitSet(1); |
| + bitSet.set(0); |
| + filter.bits(indexReader, bitSet); |
| + |
| + assertEquals(4.51, distanceCalculator.getSourceLatitude(), 0); |
| + assertEquals(31.01, distanceCalculator.getSourceLongitude(), 0); |
| + assertEquals(4.53, distanceCalculator.getTargetLatitude(), 0); |
| + assertEquals(30.61, distanceCalculator.getTargetLongitude(), 0); |
| + |
| + indexReader.close(); |
| + } |
| + |
| + /** |
| + * Pass condition: 2 threads with the correct start and end indexes are created based on the BitSet given in the method |
| + * call, and the number of threads that were requested. |
| + * |
| + * @throws java.io.IOException Can be thrown while reading from the index |
| + */ |
| + public void testBits() throws IOException { |
| + ExecutorService executorService = new ThreadPoolExecutor(2, 6, 8, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); |
| + DocumentDistanceSource distanceSource = new SimpleDocumentDistanceSource(pointDecoder, new ArcGeoDistanceCalculator()); |
| + |
| + BitSet bitSet = new BitSet(13); |
| + bitSet.set(2, 6); |
| + bitSet.set(8, 9); |
| + bitSet.set(11); |
| + |
| + final List<IterateCallInfo> infoList = Collections.synchronizedList(new ArrayList<IterateCallInfo>()); |
| + ThreadedDistanceFilter distanceFilter = new ThreadedDistanceFilter(new Point(4.52, 30.81), 30, DistanceUnits.MILES, distanceSource, executorService, 2) { |
| + |
| + @Override |
| + protected IterationResult iterate(BitSet originalBitSet, int start, int end, int size, IndexReader reader) { |
| + infoList.add(new IterateCallInfo(start, end, size)); |
| + return new IterationResult(new BitSet()); |
| + } |
| + }; |
| + |
| + IndexReader indexReader = IndexReader.open(directory); |
| + |
| + distanceFilter.bits(indexReader, bitSet); |
| + |
| + assertEquals(2, infoList.size()); |
| + |
| + Collections.sort(infoList, new Comparator<IterateCallInfo>() { |
| + public int compare(IterateCallInfo info1, IterateCallInfo info2) { |
| + return info1.getStart() - info2.getStart(); |
| + } |
| + }); |
| + |
| + IterateCallInfo callInfo = infoList.get(0); |
| + assertEquals(0, callInfo.getStart()); |
| + assertEquals(6, callInfo.getEnd()); |
| + assertEquals(6, callInfo.getSize()); |
| + |
| + callInfo = infoList.get(1); |
| + assertEquals(6, callInfo.getStart()); |
| + assertEquals(12, callInfo.getEnd()); |
| + assertEquals(6, callInfo.getSize()); |
| + |
| + indexReader.close(); |
| + } |
| + |
| + /** |
| + * Pass condition: Of the 3 documents with points, 1 is outside of the radius and should be filtered out, 1 has been |
| + * deleted so it should also be filtered out, leaving just 1 that passes the filter. Its distance should be recorded |
| + * in the calculated distances of the filter |
| + * |
| + * @throws IOException Can be thrown when interactin with the index |
| + */ |
| + public void testIterate() throws IOException { |
| + IndexReader indexReader = IndexReader.open(directory, false); |
| + indexReader.deleteDocument(1); |
| + |
| + BitSet bitSet = new BitSet(2); |
| + bitSet.set(0); |
| + bitSet.set(1); |
| + bitSet.set(2); |
| + |
| + MapCachingDocumentDistanceSource distanceSource = new MapCachingDocumentDistanceSource(new SimpleDocumentDistanceSource(pointDecoder, new ArcGeoDistanceCalculator())); |
| + |
| + ThreadedDistanceFilter distanceFilter = new ThreadedDistanceFilter(new Point(4.52, 30.81), 30, DistanceUnits.MILES, distanceSource, null, 0); |
| + |
| + ThreadedDistanceFilter.IterationResult result = distanceFilter.iterate(bitSet, 0, 3, 3, indexReader); |
| + |
| + assertNotNull(result); |
| + |
| + BitSet resultingBitSet = result.getBitSet(); |
| + assertNotNull(resultingBitSet); |
| + assertTrue(resultingBitSet.get(0)); |
| + assertFalse(resultingBitSet.get(1)); |
| + assertFalse(resultingBitSet.get(2)); |
| + |
| + assertEquals(2, distanceSource.getCachedDistances().size()); |
| + |
| + indexReader.close(); |
| + } |
| + |
| + // ================================================= Inner Classes ================================================= |
| + |
| + private static class IterateCallInfo { |
| + |
| + private final int start; |
| + private final int end; |
| + private final int size; |
| + |
| + private IterateCallInfo(int start, int end, int size) { |
| + this.start = start; |
| + this.end = end; |
| + this.size = size; |
| + } |
| + |
| + public int getStart() { |
| + return start; |
| + } |
| + |
| + public int getEnd() { |
| + return end; |
| + } |
| + |
| + public int getSize() { |
| + return size; |
| + } |
| + } |
| + |
| + /** |
| + * Dummy implementation. Used for unit test to assure that the given arguments to a distance calculator are given correctly . |
| + */ |
| + class StubGeoDistanceCalculator implements GeoDistanceCalculator { |
| + |
| + private double sourceLatitude; |
| + private double sourceLongitude; |
| + private double targetLatitude; |
| + private double targetLongitude; |
| + |
| + public double calculate(double sourceLatitude, double sourceLongitude, double targetLatitude, double targetLongitude, DistanceUnits unit) { |
| + this.sourceLatitude = sourceLatitude; |
| + this.sourceLongitude = sourceLongitude; |
| + this.targetLatitude = targetLatitude; |
| + this.targetLongitude = targetLongitude; |
| + return 0.0; |
| + } |
| + |
| + public double getSourceLatitude() { |
| + return sourceLatitude; |
| + } |
| + |
| + public double getSourceLongitude() { |
| + return sourceLongitude; |
| + } |
| + |
| + public double getTargetLatitude() { |
| + return targetLatitude; |
| + } |
| + |
| + public double getTargetLongitude() { |
| + return targetLongitude; |
| + } |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/LatLngPointDecoder.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/LatLngPointDecoder.java Wed Jan 20 15:08:24 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/LatLngPointDecoder.java Wed Jan 20 15:08:24 CET 2010 |
| @@ -0,0 +1,66 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.search.FieldCache; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * PointDecoder that uses latitude and longitude data that is stored in two separate fields. |
| + */ |
| +public class LatLngPointDecoder implements PointDecoder { |
| + |
| + private final String latField; |
| + private final String lngField; |
| + |
| + /** |
| + * Creates a new LatLngPointDecoder that uses the data found in the given latitude and longitude fields |
| + * |
| + * @param latField Name of the field in documents containing laitutde data |
| + * @param lngField Name of the field in documents containing longitude data |
| + */ |
| + public LatLngPointDecoder(String latField, String lngField) { |
| + this.latField = latField; |
| + this.lngField = lngField; |
| + } |
| + |
| + /** |
| + * {@inheritDoc} |
| + */ |
| + public Point getPoint(int docId, IndexReader reader) throws IOException { |
| + double[] latValues = getFieldValues(latField, reader); |
| + double[] lngValues = getFieldValues(lngField, reader); |
| + return new Point(latValues[docId], lngValues[docId]); |
| + } |
| + |
| + // ================================================= Helper Methods ================================================ |
| + |
| + /** |
| + * Gets the values for the given field from the IndexReader |
| + * |
| + * @param field Field whose values are to be retrieved |
| + * @param indexReader IndexReader from where the values are to be retrieved |
| + * @return Values for the field |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + double[] getFieldValues(String field, IndexReader indexReader) throws IOException { |
| + return FieldCache.DEFAULT.getDoubles(indexReader, field, FieldCache.NUMERIC_UTILS_DOUBLE_PARSER); |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/PointDecoder.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/PointDecoder.java Wed Jan 20 15:08:44 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/PointDecoder.java Wed Jan 20 15:08:44 CET 2010 |
| @@ -0,0 +1,38 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * PointDecoders decode the representation of a point for a document into instances of {@link org.apache.lucene.spatial.geometry.Point} |
| + */ |
| +public interface PointDecoder { |
| + |
| + /** |
| + * Retrieves the Point for the document with the given ID |
| + * |
| + * @param docId ID of the document whose point is to be retrieved |
| + * @param reader IndexReader for communicating with the index |
| + * @return Point representation of the decoded data |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + Point getPoint(int docId, IndexReader reader) throws IOException; |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/DistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/DistanceFilter.java Sun Jan 17 15:33:25 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/DistanceFilter.java Sun Jan 17 15:33:25 CET 2010 |
| @@ -0,0 +1,44 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| + |
| +import java.io.IOException; |
| +import java.util.BitSet; |
| +import java.util.Map; |
| + |
| +/** |
| + * DistanceFilter is responsible for filtering out documents from an existing BitSet, based on their calculated distance |
| + * from the central point. Because the costing of calculating distances for documents is relatively high, this filter |
| + * uses an existing BitSet, which will have been created another filter previously. As such, this is technically not |
| + * a Lucene Filter. |
| + * |
| + * <p><font color="red"><b>NOTE:</b> This API is still in flux and might change in incompatible ways in the next release.</font> |
| + */ |
| +public interface DistanceFilter { |
| + |
| + /** |
| + * Filters the documents from the given IndexReader who have bits set in the given BitSet. |
| + * |
| + * @param reader IndexReader from where the documents will be read from |
| + * @param bits BitSet containing bits indicating which documents should be considered to be filtered out |
| + * @return BitSet with bits set representing those documents that passed the filter |
| + * @throws java.io.IOException Can be thrown while reading from the IndexReader |
| + */ |
| + BitSet bits(IndexReader reader, BitSet bits) throws IOException; |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/MapCachingDocumentDistanceSource.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/MapCachingDocumentDistanceSource.java Wed Jan 20 15:08:29 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/MapCachingDocumentDistanceSource.java Wed Jan 20 15:08:29 CET 2010 |
| @@ -0,0 +1,69 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.DistanceUnits; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| +import java.util.HashMap; |
| +import java.util.Map; |
| + |
| +/** |
| + * Implementation of {@link DocumentDistanceSource} which caches calculated distances in a Map. Note, the caching does |
| + * not take into account the IndexReader, nor does it apply any multi-thread synchronisation. |
| + */ |
| +public class MapCachingDocumentDistanceSource implements DocumentDistanceSource { |
| + |
| + private final DocumentDistanceSource source; |
| + private final Map<Integer, Double> cachedDistances = new HashMap<Integer, Double>(); |
| + |
| + /** |
| + * Creates a new MapCachingDocumentDistanceSource that caches distances from the given DocumentDistanceSource |
| + * |
| + * @param source DocumentDistanceSource whose calculated distances will be cached |
| + */ |
| + public MapCachingDocumentDistanceSource(DocumentDistanceSource source) { |
| + this.source = source; |
| + } |
| + |
| + /** |
| + * {@inheritDoc} |
| + */ |
| + public double getDocumentDistance(int docId, Point src, IndexReader indexReader, DistanceUnits units) throws IOException { |
| + Double cachedDistance = cachedDistances.get(docId); |
| + if (cachedDistance != null) { |
| + return cachedDistance; |
| + } |
| + |
| + double calculatedDistance = source.getDocumentDistance(docId, src, indexReader, units); |
| + cachedDistances.put(docId, calculatedDistance); |
| + return calculatedDistance; |
| + } |
| + |
| + // ================================================= Getters / Setters ============================================= |
| + |
| + /** |
| + * Returns the cached distances |
| + * |
| + * @return Cached distances |
| + */ |
| + public Map<Integer, Double> getCachedDistances() { |
| + return cachedDistances; |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/ThreadedDistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/ThreadedDistanceFilter.java Sun Jan 17 15:35:42 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/ThreadedDistanceFilter.java Sun Jan 17 15:35:42 CET 2010 |
| @@ -0,0 +1,175 @@ |
| +/** |
| + * 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.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.DistanceUnits; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| +import java.util.*; |
| +import java.util.concurrent.Callable; |
| +import java.util.concurrent.ExecutionException; |
| +import java.util.concurrent.ExecutorService; |
| +import java.util.concurrent.Future; |
| + |
| +/** |
| + * Implementation of {@link DistanceFilter} that uses multiple threads to iterate in parallel, over the BitSet to be filtered. |
| + * <p/> |
| + * To manage the threads, an ExecutorService is used, which allows users of this class to have fine grained control over |
| + * how many threads should be created, and what to do when there isn't any threads left in the pool. |
| + * |
| + * <p><font color="red"><b>NOTE:</b> This API is still in flux and might change in incompatible ways in the next release.</font> |
| + */ |
| +public class ThreadedDistanceFilter implements DistanceFilter { |
| + |
| + private final Point centralPoint; |
| + private final double radius; |
| + private final DistanceUnits unit; |
| + private final DocumentDistanceSource documentDistanceSource; |
| + |
| + private final ExecutorService executorService; |
| + private final int threadCount; |
| + |
| + /** |
| + * Creates a new ThreadedDistanceFilter that will filter out documents that are outside of the given radius of the |
| + * central point defined by the given latitude and longitude |
| + * |
| + * @param centralPoint Point at the centre of the search |
| + * @param radius Radius that documents must be within from the central point to pass the filter |
| + * @param unit Unit of distance the radius is in |
| + * @param distanceSource DocumentDistanceSource from where the distances for documents from the central point, will be |
| + * retrieved from |
| + * @param executorService ExecutorService which will manage the execution of the threads |
| + * @param threadCount Number of threads that the filter should try to split its work across |
| + */ |
| + public ThreadedDistanceFilter( |
| + Point centralPoint, |
| + double radius, |
| + DistanceUnits unit, |
| + DocumentDistanceSource distanceSource, |
| + ExecutorService executorService, |
| + int threadCount) { |
| + this.centralPoint = centralPoint; |
| + this.radius = radius; |
| + this.unit = unit; |
| + this.documentDistanceSource = distanceSource; |
| + this.executorService = executorService; |
| + this.threadCount = threadCount; |
| + } |
| + |
| + /** |
| + * {@inheritDoc} |
| + */ |
| + public BitSet bits(final IndexReader reader, final BitSet bits) throws IOException { |
| + int maxLength = bits.length(); |
| + int threadSize = maxLength / threadCount; |
| + List<Callable<IterationResult>> tasks = new ArrayList<Callable<IterationResult>>(); |
| + |
| + for (int i = 0; i < threadCount; i++) { |
| + final int start = i * threadSize; |
| + // if the last batch of documents has been reached, then maxLength should be end |
| + final int end = (i == threadCount - 1) ? maxLength : Math.min((i + 1) * threadSize, maxLength); |
| + tasks.add(new Callable<IterationResult>() { |
| + public IterationResult call() throws Exception { |
| + return iterate(bits, start, end, end - start, reader); |
| + } |
| + }); |
| + } |
| + |
| + BitSet result = new BitSet(bits.cardinality()); |
| + |
| + try { |
| + List<Future<IterationResult>> results = executorService.invokeAll(tasks); |
| + for (Future<IterationResult> resultFuture : results) { |
| + IterationResult iterationResult = resultFuture.get(); |
| + result.or(iterationResult.getBitSet()); |
| + } |
| + } catch (InterruptedException ie) { |
| + throw new RuntimeException("InterruptedException thrown while executing tasks", ie); |
| + } catch (ExecutionException ee) { |
| + throw new RuntimeException("ExecutionException thrown while retrieving results of tasks", ee); |
| + } |
| + |
| + return result; |
| + } |
| + |
| + // ================================================ Helper Methods ================================================= |
| + |
| + /** |
| + * Iterates over the set bits in the given BitSet from the given start to end range, calculating the distance of the |
| + * documents and determining which are within the distance radius of the central point. |
| + * |
| + * @param originalBitSet BitSet which has bits set identifying which documents should be checked to see if their |
| + * distance falls within the radius |
| + * @param start Index in the BitSet that the method will start at |
| + * @param end Index in the BitSet that the method will stop at |
| + * @param size Size the the resulting BitSet should be created at (most likely end - start) |
| + * @param reader IndexReader for checking if the document has been deleted |
| + * @return IterationResult containing all the results of the method. |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + protected IterationResult iterate(BitSet originalBitSet, int start, int end, int size, IndexReader reader) throws IOException { |
| + BitSet bitSet = new BitSet(size); |
| + |
| + int docId = originalBitSet.nextSetBit(start); |
| + while (docId != -1 && docId < end) { |
| + if (reader.isDeleted(docId)) { |
| + docId = originalBitSet.nextSetBit(docId + 1); |
| + continue; |
| + } |
| + |
| + double distance = documentDistanceSource.getDocumentDistance(docId, centralPoint, reader, unit); |
| + if (distance < radius) { |
| + bitSet.set(docId); |
| + } |
| + |
| + docId = originalBitSet.nextSetBit(docId + 1); |
| + } |
| + return new IterationResult(bitSet); |
| + } |
| + |
| + // ================================================= Inner Classes ================================================= |
| + |
| + /** |
| + * Wrapper of the results from {@link ThreadedDistanceFilter#iterate(BitSet, int, int, int, IndexReader)}. |
| + * This allows the method to operate in almost total isolation in separate threads. |
| + */ |
| + protected class IterationResult { |
| + |
| + private BitSet bitSet; |
| + |
| + /** |
| + * Creates a new IterationResult that wraps the given BitSet |
| + * |
| + * @param bitSet BitSet to wrap |
| + */ |
| + public IterationResult(BitSet bitSet) { |
| + this.bitSet = bitSet; |
| + } |
| + |
| + /** |
| + * Returns the wrapped BitSet |
| + * |
| + * @return Wrapped BitSet |
| + */ |
| + public BitSet getBitSet() { |
| + return bitSet; |
| + } |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java (revision 833867) |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java Fri Dec 18 14:53:45 CET 2009 |
| @@ -29,7 +29,10 @@ |
| * <p><font color="red"><b>NOTE:</b> This API is still in |
| * flux and might change in incompatible ways in the next |
| * release.</font> |
| + * |
| + * @deprecated This class has been made replaced by DistanceFilter and LatLngLocationDataSetFactory. It will be removed. |
| */ |
| +@Deprecated |
| public class LatLongDistanceFilter extends DistanceFilter { |
| |
| /** |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java (revision 833867) |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java Fri Dec 18 14:53:40 CET 2009 |
| @@ -29,7 +29,10 @@ |
| * <p><font color="red"><b>NOTE:</b> This API is still in |
| * flux and might change in incompatible ways in the next |
| * release.</font> |
| + * |
| + * @deprecated This class has been replaced by DistanceFilter and its implementations. It will be removed. |
| */ |
| +@Deprecated |
| public abstract class DistanceFilter extends Filter { |
| |
| final protected Filter startingFilter; |
| Index: contrib/spatial/src/test/org/apache/lucene/spatial/distance/LatLngPointDecoderTest.java |
| =================================================================== |
| --- contrib/spatial/src/test/org/apache/lucene/spatial/distance/LatLngPointDecoderTest.java Wed Jan 20 15:08:54 CET 2010 |
| +++ contrib/spatial/src/test/org/apache/lucene/spatial/distance/LatLngPointDecoderTest.java Wed Jan 20 15:08:54 CET 2010 |
| @@ -0,0 +1,55 @@ |
| +/** 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.lucene.spatial.distance; |
| + |
| +import junit.framework.TestCase; |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Tests for {@link org.apache.lucene.spatial.distance.LatLngPointDecoder} |
| + */ |
| +public class LatLngPointDecoderTest extends TestCase { |
| + |
| + /** |
| + * Pass condition: The latitude and longitude for document 0 is correctly decoded from the lat and lng fields |
| + * |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + public void testGetPoint() throws IOException { |
| + LatLngPointDecoder pointDecoder = new LatLngPointDecoder("lat", "lng") { |
| + |
| + @Override |
| + double[] getFieldValues(String field, IndexReader indexReader) { |
| + if ("lat".equals(field)) { |
| + return new double[]{40.3, 54.2}; |
| + } else if ("lng".equals(field)) { |
| + return new double[]{3.21, 9.65}; |
| + } else { |
| + throw new IllegalArgumentException("Unexpected field name: " + field); |
| + } |
| + } |
| + }; |
| + |
| + Point point = pointDecoder.getPoint(0, null); |
| + |
| + assertEquals(40.3, point.getX(), 0D); |
| + assertEquals(3.21, point.getY(), 0D); |
| + } |
| +} |
| Index: contrib/spatial/src/java/org/apache/lucene/spatial/distance/DocumentDistanceSource.java |
| =================================================================== |
| --- contrib/spatial/src/java/org/apache/lucene/spatial/distance/DocumentDistanceSource.java Wed Jan 20 15:05:37 CET 2010 |
| +++ contrib/spatial/src/java/org/apache/lucene/spatial/distance/DocumentDistanceSource.java Wed Jan 20 15:05:37 CET 2010 |
| @@ -0,0 +1,25 @@ |
| +package org.apache.lucene.spatial.distance; |
| + |
| +import org.apache.lucene.index.IndexReader; |
| +import org.apache.lucene.spatial.geometry.DistanceUnits; |
| +import org.apache.lucene.spatial.geometry.Point; |
| + |
| +import java.io.IOException; |
| + |
| +/** |
| + * Single access point for anything wishing to retrieve the distance a document is from a point. |
| + */ |
| +public interface DocumentDistanceSource { |
| + |
| + /** |
| + * Retrieves the distance the document with the given id is from the given Point. |
| + * |
| + * @param docId ID of the document whose distance is to be retrieved |
| + * @param src Point from where the distance to the document is to be calculated |
| + * @param indexReader IndexReader for interacting with the index |
| + * @param units DistanceUnits that the distance should be returned in |
| + * @return Distance the document is from the point in the defined units |
| + * @throws IOException Can be thrown while interacting with the index |
| + */ |
| + double getDocumentDistance(int docId, Point src, IndexReader indexReader, DistanceUnits units) throws IOException; |
| +} |