diff --git a/contrib/spatial/build.xml b/contrib/spatial/build.xml index 261e47954f8..060ea02aac9 100644 --- a/contrib/spatial/build.xml +++ b/contrib/spatial/build.xml @@ -25,8 +25,23 @@ - + + + + + + + + + + + + + Misc building dependency ${misc.jar} + + + diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/ISerialChainFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/ISerialChainFilter.java deleted file mode 100644 index eb3c3b88a9d..00000000000 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/ISerialChainFilter.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * 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; - -import java.io.IOException; -import java.util.BitSet; - -import org.apache.lucene.index.CorruptIndexException; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.search.Filter; - -/** - * Provide an optimized filter, by allowing the bitset from - * previous filters in the bitset to be used in the next part of the chain. - * - */ -public abstract class ISerialChainFilter extends Filter { - public abstract BitSet bits(IndexReader reader, BitSet bits) throws CorruptIndexException, IOException, Exception; -} diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/SerialChainFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/SerialChainFilter.java deleted file mode 100644 index 3be3f188852..00000000000 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/SerialChainFilter.java +++ /dev/null @@ -1,214 +0,0 @@ -/** - * 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; - -import java.io.IOException; -import java.util.BitSet; - -import org.apache.lucene.index.CorruptIndexException; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.search.DocIdSet; -import org.apache.lucene.search.Filter; -import org.apache.lucene.util.DocIdBitSet; - -/** - * - * Provide a serial chain filter, passing the bitset in with the - * index reader to each of the filters in an ordered fashion. - * - * Based off chain filter, but with some improvements to allow a narrowed down - * filtering. Traditional filter required iteration through an IndexReader. - * - * By implementing the ISerialChainFilter class, you can create a bits(IndexReader reader, BitSet bits) - * @see org.apache.lucene.search.ISerialChainFilter - * - */ -public class SerialChainFilter extends Filter { - - /** - * $Id: SerialChainFilter.java 136 2008-12-17 16:16:38Z ryantxu $ - */ - private static final long serialVersionUID = 1L; - private Filter chain[]; - public static final int SERIALAND = 1; - public static final int SERIALOR = 2; - public static final int AND = 3; // regular filters may be used first - public static final int OR = 4; // regular filters may be used first - public static final int DEFAULT = SERIALOR; - - private int actionType[]; - - public SerialChainFilter(Filter chain[]){ - this.chain = chain; - this.actionType = new int[] {DEFAULT}; - } - - public SerialChainFilter(Filter chain[], int actionType[]){ - this.chain= chain; - this.actionType = actionType; - } - - /* (non-Javadoc) - * @see org.apache.lucene.search.Filter#bits(org.apache.lucene.index.IndexReader) - */ - @Override - public BitSet bits(IndexReader reader) throws IOException { - return ((DocIdBitSet)getDocIdSet(reader)).getBitSet(); - } - - - /* (non-Javadoc) - * @see org.apache.lucene.search.Filter#getDocIdSet(org.apache.lucene.index.IndexReader) - */ - @Override - public DocIdSet getDocIdSet(IndexReader reader) throws CorruptIndexException, IOException { - - BitSet bits = new BitSet(reader.maxDoc()); - int chainSize = chain.length; - int actionSize = actionType.length; - int i = 0; - - /** - * taken from ChainedFilter, first and on an empty bitset results in 0 - */ - if (actionType[i] == AND){ - try { - //System.out.println(chain[i] ); - bits = (BitSet) ((DocIdBitSet)chain[i].getDocIdSet(reader)).getBitSet().clone(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - ++i; - } - - for( ; i < chainSize; i++) { - - int action = (i < actionSize)? actionType[i]: DEFAULT; - //System.out.println(chain[i] + ": "+ action); - switch (action){ - - case (SERIALAND): - try { - bits.and(((ISerialChainFilter) chain[i]).bits(reader, bits)); - } catch (CorruptIndexException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - case (SERIALOR): - try { - bits.or(((ISerialChainFilter) chain[i]).bits(reader,bits)); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - break; - case (AND): - bits.and(chain[i].bits(reader)); - break; - case (OR): - bits.or(((DocIdBitSet)chain[i].getDocIdSet(reader)).getBitSet()); - break; - } - } - -// System.out.println("++++++===================="); -// new Exception().printStackTrace(); - - return new DocIdBitSet(bits); - } - - /** - * @return the chain - */ - Filter[] getChain() { - return chain; - } - - /** - * @return the actionType - */ - int[] getActionType() { - return actionType; - } - - /** - * Returns true if o is equal to this. - * - * @see org.apache.lucene.search.RangeFilter#equals - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SerialChainFilter)) return false; - SerialChainFilter other = (SerialChainFilter) o; - - if (this.chain.length != other.getChain().length || - this.actionType.length != other.getActionType().length) - return false; - - for (int i = 0; i < this.chain.length; i++) { - if (this.actionType[i] != other.getActionType()[i] || - (!this.chain[i].equals(other.getChain()[i]))) - return false; - } - return true; - } - - /** - * Returns a hash code value for this object. - * - * @see org.apache.lucene.search.RangeFilter#hashCode - */ - @Override - public int hashCode() { - if (chain.length == 0) - return 0; - - int h = chain[0].hashCode() ^ new Integer(actionType[0]).hashCode(); - for (int i = 1; i < this.chain.length; i++) { - h ^= chain[i].hashCode(); - h ^= new Integer(actionType[i]).hashCode(); - } - return h; - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append("SerialChainFilter("); - for (int i = 0; i < chain.length; i++) { - switch(actionType[i]) { - case (SERIALAND): buf.append("SERIALAND"); break; - case (SERIALOR): buf.append("SERIALOR"); break; - case (AND): buf.append("AND"); break; - case (OR): buf.append("OR"); break; - default: buf.append(actionType[i]); - } - buf.append(" " + chain[i].toString() + " "); - } - return buf.toString().trim() + ")"; - } -} diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java index bb22ba8e57d..73244858123 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java @@ -18,17 +18,14 @@ package org.apache.lucene.spatial.geohash; import java.io.IOException; -import java.util.BitSet; -import java.util.HashMap; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.logging.Logger; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.FieldCache; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.DocIdSet; +import org.apache.lucene.search.FilteredDocIdSet; import org.apache.lucene.spatial.tier.DistanceFilter; import org.apache.lucene.spatial.tier.DistanceUtils; -import org.apache.lucene.spatial.tier.DistanceHandler.Precision; @@ -39,167 +36,62 @@ public class GeoHashDistanceFilter extends DistanceFilter { */ private static final long serialVersionUID = 1L; - private double distance; private double lat; private double lng; private String geoHashField; - private Logger log = Logger.getLogger(getClass().getName()); - - private Map distances = null; - private Precision precise = null; - int offset = 0; - int nextOffset; - /** * Provide a distance filter based from a center point with a radius * in miles + * @param startingFilter * @param lat * @param lng * @param miles - * @param latField - * @param lngField */ - public GeoHashDistanceFilter(double lat, double lng, double miles, String geoHashField){ - distance = miles; + public GeoHashDistanceFilter(Filter startingFilter, double lat, double lng, double miles, String geoHashField) { + super(startingFilter, miles); this.lat = lat; this.lng = lng; this.geoHashField = geoHashField; - } - - - public Map getDistances(){ - return distances; - } - - public Double getDistance(int docid){ - return distances.get(docid); - } - + @Override - public BitSet bits(IndexReader reader) throws IOException { + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { - /* Create a BitSet to store the result */ - int maxdocs = reader.numDocs(); - BitSet bits = new BitSet(maxdocs); - - setPrecision(maxdocs); - // create an intermediate cache to avoid recomputing - // distances for the same point - // TODO: Why is this a WeakHashMap? - WeakHashMap cdistance = new WeakHashMap(maxdocs); - - String[] geoHashCache = FieldCache.DEFAULT.getStrings(reader, geoHashField); - + final String[] geoHashValues = FieldCache.DEFAULT.getStrings(reader, geoHashField); - /* store calculated distances for reuse by other components */ - distances = new HashMap(maxdocs); - for (int i = 0 ; i < maxdocs; i++) { - - String geoHash = geoHashCache[i]; - double[] coords = GeoHashUtils.decode(geoHash); - double x = coords[0]; - double y = coords[1]; - - // round off lat / longs if necessary -// x = DistanceHandler.getPrecision(x, precise); -// y = DistanceHandler.getPrecision(y, precise); - - - Double cachedDistance = cdistance.get(geoHash); - - - double d; - - if(cachedDistance != null){ - d = cachedDistance.doubleValue(); - } else { - d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); - cdistance.put(geoHash, d); - } - distances.put(i, d); - - if (d < distance){ - bits.set(i); - } - - } - - return bits; - } + final int docBase = nextDocBase; + nextDocBase += reader.maxDoc(); - - @Override - public BitSet bits(IndexReader reader, BitSet bits) throws Exception { - - - /* Create a BitSet to store the result */ - int size = bits.cardinality(); - BitSet result = new BitSet(size); - - - /* create an intermediate cache to avoid recomputing - distances for the same point */ - HashMap cdistance = new HashMap(size); - - - /* store calculated distances for reuse by other components */ - offset += reader.maxDoc(); - if (distances == null) - distances = new HashMap(size); - - long start = System.currentTimeMillis(); - String[] geoHashCache = FieldCache.DEFAULT.getStrings(reader, geoHashField); - - /* loop over all set bits (hits from the boundary box filters) */ - int i = bits.nextSetBit(0); - while (i >= 0){ - - // if we have a completed - // filter chain, lat / lngs can be retrived from - // memory rather than document base. - - String geoHash = geoHashCache[i]; - double[] coords = GeoHashUtils.decode(geoHash); - double x = coords[0]; - double y = coords[1]; - - // round off lat / longs if necessary -// x = DistanceHandler.getPrecision(x, precise); -// y = DistanceHandler.getPrecision(y, precise); - - - Double cachedDistance = cdistance.get(geoHash); - double d; - - if(cachedDistance != null){ - d = cachedDistance.doubleValue(); + return new FilteredDocIdSet(startingFilter.getDocIdSet(reader)) { + public boolean match(int doc) { - } else { - d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); - //d = DistanceUtils.getLLMDistance(lat, lng, x, y); - cdistance.put(geoHash, d); - } + String geoHash = geoHashValues[doc]; + double[] coords = GeoHashUtils.decode(geoHash); + double x = coords[0]; + double y = coords[1]; - distances.put(i, d); - - if (d < distance){ - result.set(i); - } - i = bits.nextSetBit(i+1); - } - - long end = System.currentTimeMillis(); - log.fine("Time taken : "+ (end - start) + - ", results : "+ distances.size() + - ", cached : "+ cdistance.size() + - ", incoming size: "+ size); - + // round off lat / longs if necessary + // x = DistanceHandler.getPrecision(x, precise); + // y = DistanceHandler.getPrecision(y, precise); + Double cachedDistance = distanceLookupCache.get(geoHash); + double d; + + if (cachedDistance != null) { + d = cachedDistance.doubleValue(); + } else { + d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); + distanceLookupCache.put(geoHash, d); + } - cdistance = null; - nextOffset += offset; - return result; + if (d < distance){ + distances.put(doc+docBase, d); + return true; + } else { + return false; + } + } + }; } /** Returns true if o is equal to this. */ @@ -209,7 +101,8 @@ public class GeoHashDistanceFilter extends DistanceFilter { if (!(o instanceof GeoHashDistanceFilter)) return false; GeoHashDistanceFilter other = (GeoHashDistanceFilter) o; - if (this.distance != other.distance || + if (!this.startingFilter.equals(other.startingFilter) || + this.distance != other.distance || this.lat != other.lat || this.lng != other.lng || !this.geoHashField.equals(other.geoHashField) ) { @@ -222,26 +115,11 @@ public class GeoHashDistanceFilter extends DistanceFilter { @Override public int hashCode() { int h = new Double(distance).hashCode(); + h ^= startingFilter.hashCode(); h ^= new Double(lat).hashCode(); h ^= new Double(lng).hashCode(); h ^= geoHashField.hashCode(); return h; } - - private void setPrecision(int maxDocs) { - precise = Precision.EXACT; - - if (maxDocs > 1000 && distance > 10) { - precise = Precision.TWENTYFEET; - } - - if (maxDocs > 10000 && distance > 10){ - precise = Precision.TWOHUNDREDFEET; - } - } - - public void setDistances(Map distances) { - this.distances = distances; - } } diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java index 44449c50a73..ec44f91f95f 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java @@ -46,9 +46,6 @@ public class CartesianPoint { /** * Return a new point translated in the x and y dimensions - * @param i - * @param translation - * @return */ public CartesianPoint translate(int deltaX, int deltaY) { return new CartesianPoint(this.x+deltaX, this.y+deltaY); diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java index 5e8efc5a569..259fa89853a 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java @@ -22,7 +22,6 @@ package org.apache.lucene.spatial.geometry; * Abstract base lat-lng class which can manipulate fixed point or floating * point based coordinates. Instances are immutable. * - * @see FixedLatLngTest * @see FloatLatLng * */ @@ -62,8 +61,6 @@ public abstract class LatLng { * The x dimension corresponds to latitude and y corresponds to longitude. * The translation starts with the normalized latlng and adds 180 to the latitude and * 90 to the longitude (subject to fixed point scaling). - * - * @return */ public CartesianPoint toCartesian() { LatLng ll=normalize(); @@ -80,7 +77,6 @@ public abstract class LatLng { /** * The inverse of toCartesian(). Always returns a FixedLatLng. * @param pt - * @return */ public static LatLng fromCartesian(CartesianPoint pt) { int lat=pt.getY() - 90 * FixedLatLng.SCALE_FACTOR_INT; @@ -158,7 +154,6 @@ public abstract class LatLng { /** * Calculate the midpoint between this point an another. Respects fixed vs floating point * @param other - * @return */ public abstract LatLng calculateMidpoint(LatLng other); } diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java index 1f9b916cb6a..767b3bf9a33 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java @@ -56,9 +56,6 @@ public class Ellipse implements Geometry2D { /** * Constructor given bounding rectangle and a rotation. - * - * @param - * @param */ public Ellipse(Point2D p1, Point2D p2, double angle) { center = new Point2D(); diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java index f7354ef6ebb..978507b1227 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java @@ -31,26 +31,22 @@ public interface Geometry2D { /** * Does the shape contain the given point * @param p - * @return */ public boolean contains(Point2D p); /** * Return the area - * @return */ public double area(); /** * Return the centroid - * @return */ public Point2D centroid(); /** * Returns information about how this shape intersects the given rectangle * @param r - * @return */ public IntersectCase intersect(Rectangle r); diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java index 0a3e001b519..ab6f2349ce9 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java @@ -41,7 +41,6 @@ public class LLRect { /** * Return the area in units of lat-lng squared. This is a contrived unit * that only has value when comparing to something else. - * @return */ public double area() { return Math.abs((ll.getLat()-ur.getLat()) * (ll.getLng()-ur.getLng())); @@ -79,7 +78,6 @@ public class LLRect { * @param center * @param widthMi * @param heightMi - * @return */ public static LLRect createBox(LatLng center, double widthMi, double heightMi) { double miplatdeg=DistanceApproximation.getMilesPerLngDeg(center.getLat()); @@ -97,7 +95,6 @@ public class LLRect { /** * Returns a rectangle shape for the bounding box - * @return */ public Rectangle toRectangle() { return new Rectangle(ll.getLng(), ll.getLat(), ur.getLng(), ur.getLat()); diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/BoundaryBoxFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/BoundaryBoxFilter.java index 08c3efe9074..6431e83258d 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/BoundaryBoxFilter.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/BoundaryBoxFilter.java @@ -18,7 +18,6 @@ package org.apache.lucene.spatial.tier; import java.io.IOException; -import java.util.BitSet; import java.util.logging.Logger; import org.apache.lucene.index.IndexReader; @@ -26,7 +25,9 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; import org.apache.lucene.index.TermEnum; import org.apache.lucene.search.Filter; +import org.apache.lucene.search.DocIdSet; import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.util.OpenBitSet; @@ -84,15 +85,15 @@ public class BoundaryBoxFilter extends Filter { /** - * Returns a BitSet with true for documents which should be + * Returns a DocIdSet with true for documents which should be * permitted in search results, and false for those that should * not. */ @Override - public BitSet bits(IndexReader reader) throws IOException { + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { long start = System.currentTimeMillis(); - BitSet bits = new BitSet(reader.maxDoc()); + OpenBitSet bits = new OpenBitSet(reader.maxDoc()); TermEnum enumerator = (null != lowerTerm ? reader.terms(new Term(fieldName, lowerTerm)) @@ -128,7 +129,7 @@ public class BoundaryBoxFilter extends Filter { // we have a good term, find the docs termDocs.seek(enumerator.term()); while (termDocs.next()) { - bits.set(termDocs.doc()); + bits.fastSet(termDocs.doc()); } } } diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java index 212dc518253..f6e0b12a3e8 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java @@ -33,6 +33,12 @@ import org.apache.lucene.spatial.tier.projections.SinusoidalProjector; */ public class CartesianPolyFilterBuilder { + // Finer granularity than 1 mile isn't accurate with + // standard java math. Also, there's already a 2nd + // precise filter, if needed, in DistanceQueryBuilder, + // that will make the filtering exact. + public static final double MILES_FLOOR = 1.0; + private IProjector projector = new SinusoidalProjector(); private Logger log = Logger.getLogger(getClass().getName()); @@ -42,10 +48,12 @@ public class CartesianPolyFilterBuilder { this.tierPrefix = tierPrefix; } - public Shape getBoxShape(double latitude, double longitude, int miles) + public Shape getBoxShape(double latitude, double longitude, double miles) { + if (miles < MILES_FLOOR) { + miles = MILES_FLOOR; + } Rectangle box = DistanceUtils.getInstance().getBoundary(latitude, longitude, miles); - double latY = box.getMaxPoint().getY();//box.getY(); double latX = box.getMinPoint().getY() ; //box.getMaxY(); @@ -104,7 +112,7 @@ public class CartesianPolyFilterBuilder { return shape; } - public Filter getBoundingArea(double latitude, double longitude, int miles) + public Filter getBoundingArea(double latitude, double longitude, double miles) { Shape shape = getBoxShape(latitude, longitude, miles); return new CartesianShapeFilter(shape, shape.getTierId()); diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianShapeFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianShapeFilter.java index 1cc3c43ffd8..5b4b18a60ea 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianShapeFilter.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianShapeFilter.java @@ -17,7 +17,6 @@ package org.apache.lucene.spatial.tier; import java.io.IOException; -import java.util.BitSet; import java.util.List; import java.util.logging.Logger; @@ -25,7 +24,9 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.index.TermDocs; import org.apache.lucene.search.Filter; +import org.apache.lucene.search.DocIdSet; import org.apache.lucene.util.NumericUtils; +import org.apache.lucene.util.OpenBitSet; public class CartesianShapeFilter extends Filter { @@ -43,16 +44,16 @@ public class CartesianShapeFilter extends Filter { } @Override - public BitSet bits(IndexReader reader) throws IOException { + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { long start = System.currentTimeMillis(); - BitSet bits = new BitSet(reader.maxDoc()); + OpenBitSet bits = new OpenBitSet(reader.maxDoc()); TermDocs termDocs = reader.termDocs(); List area = shape.getArea(); int sz = area.size(); log.fine("Area size "+ sz); - + // iterate through each boxid for (int i =0; i< sz; i++) { double boxId = area.get(i).doubleValue(); @@ -62,7 +63,7 @@ public class CartesianShapeFilter extends Filter { // iterate through all documents // which have this boxId while (termDocs.next()) { - bits.set(termDocs.doc()); + bits.fastSet(termDocs.doc()); } } @@ -70,5 +71,4 @@ public class CartesianShapeFilter extends Filter { log.fine("BoundaryBox Time Taken: "+ (end - start) + " found: "+bits.cardinality()+" candidates"); return bits; } - } diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java index 0dcb3d10d6d..b83bef101d5 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java @@ -16,38 +16,81 @@ package org.apache.lucene.spatial.tier; -import java.io.IOException; -import java.util.BitSet; import java.util.Map; +import java.util.WeakHashMap; +import java.util.HashMap; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.spatial.ISerialChainFilter; +import org.apache.lucene.search.Filter; +import org.apache.lucene.spatial.tier.DistanceHandler.Precision; +public abstract class DistanceFilter extends Filter { -public abstract class DistanceFilter extends ISerialChainFilter { + final protected Filter startingFilter; + protected Precision precise; + protected Map distances; + protected double distance; - public DistanceFilter() { - super(); - } + protected int nextDocBase; + protected final WeakHashMap distanceLookupCache; - public abstract Map getDistances(); + /** Filters the startingFilter by precise distance + * checking filter */ + public DistanceFilter(Filter startingFilter, double distance) { + if (startingFilter == null) { + throw new IllegalArgumentException("please provide a non-null startingFilter; you can use QueryWrapperFilter(MatchAllDocsQuery) as a no-op filter"); + } + this.startingFilter = startingFilter; + this.distance = distance; - public abstract Double getDistance(int docid); + // NOTE: neither of the distance filters use precision + // now - if we turn that on, we'll need to pass top + // reader into here + // setPrecision(reader.maxDoc()); - @Override - public abstract BitSet bits(IndexReader reader) throws IOException; + /* store calculated distances for reuse by other components */ + distances = new HashMap(); - @Override - public abstract BitSet bits(IndexReader reader, BitSet bits) throws Exception; + // create an intermediate cache to avoid recomputing + // distances for the same point + // TODO: Why is this a WeakHashMap? + distanceLookupCache = new WeakHashMap(); + } - /** Returns true if o is equal to this. */ - @Override - public abstract boolean equals(Object o); + public Map getDistances(){ + return distances; + } + + public Double getDistance(int docid){ + return distances.get(docid); + } + + public void setDistances(Map distances) { + this.distances = distances; + } - /** Returns a hash code value for this object.*/ - @Override - public abstract int hashCode(); + /** You must call this before re-using this DistanceFilter + * across searches */ + public void reset() { + nextDocBase = 0; + } - public abstract void setDistances(Map distances); + /** Returns true if o is equal to this. */ + public abstract boolean equals(Object o); -} \ No newline at end of file + /** Returns a hash code value for this object.*/ + public abstract int hashCode(); + + /* + private void setPrecision(int maxDocs) { + precise = Precision.EXACT; + + if (maxDocs > 1000 && distance > 10) { + precise = Precision.TWENTYFEET; + } + + if (maxDocs > 10000 && distance > 10){ + precise = Precision.TWOHUNDREDFEET; + } + } + */ +} diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java index bbc7ba33a1a..9003729e37f 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java @@ -21,8 +21,8 @@ import org.apache.lucene.search.ConstantScoreQuery; import org.apache.lucene.search.Filter; import org.apache.lucene.search.Query; import org.apache.lucene.search.QueryWrapperFilter; -import org.apache.lucene.spatial.SerialChainFilter; import org.apache.lucene.spatial.geohash.GeoHashDistanceFilter; +import org.apache.lucene.misc.ChainedFilter; public class DistanceQueryBuilder { @@ -31,39 +31,39 @@ public class DistanceQueryBuilder { public BoundaryBoxFilter latFilter; public BoundaryBoxFilter lngFilter; - public DistanceFilter distanceFilter; private final double lat; private final double lng; private final double miles; - private Filter cartesianFilter; - private boolean needPrecision = true; + private final Filter filter; + final DistanceFilter distanceFilter; + /** * Create a distance query using * a boundary box wrapper around a more precise * DistanceFilter. * - * @see SerialChainFilter * @param lat * @param lng * @param miles */ public DistanceQueryBuilder (double lat, double lng, double miles, - String latField, String lngField, String tierFieldPrefix,boolean needPrecise){ + String latField, String lngField, String tierFieldPrefix, boolean needPrecise) { this.lat = lat; this.lng = lng; this.miles = miles; - this.needPrecision = needPrecise; - CartesianPolyFilterBuilder cpf = new CartesianPolyFilterBuilder(tierFieldPrefix); - cartesianFilter = cpf.getBoundingArea(lat, lng, (int)miles); + Filter cartesianFilter = cpf.getBoundingArea(lat, lng, miles); /* create precise distance filter */ - if( needPrecise) - distanceFilter = new LatLongDistanceFilter(lat, lng, miles, latField, lngField); - + if (needPrecise) { + filter = distanceFilter = new LatLongDistanceFilter(cartesianFilter, lat, lng, miles, latField, lngField); + } else { + filter = cartesianFilter; + distanceFilter = null; + } } /** @@ -71,80 +71,54 @@ public class DistanceQueryBuilder { * a boundary box wrapper around a more precise * DistanceFilter. * - * @see SerialChainFilter * @param lat * @param lng * @param miles */ public DistanceQueryBuilder (double lat, double lng, double miles, - String geoHashFieldPrefix, String tierFieldPrefix,boolean needPrecise){ + String geoHashFieldPrefix, String tierFieldPrefix, boolean needPrecise){ this.lat = lat; this.lng = lng; this.miles = miles; - this.needPrecision = needPrecise; CartesianPolyFilterBuilder cpf = new CartesianPolyFilterBuilder(tierFieldPrefix); - cartesianFilter = cpf.getBoundingArea(lat, lng, (int)miles); + Filter cartesianFilter = cpf.getBoundingArea(lat, lng, miles); /* create precise distance filter */ - if( needPrecise) - distanceFilter = new GeoHashDistanceFilter(lat, lng, miles, geoHashFieldPrefix); - + if (needPrecise) { + filter = distanceFilter = new GeoHashDistanceFilter(cartesianFilter, lat, lng, miles, geoHashFieldPrefix); + } else { + filter = cartesianFilter; + distanceFilter = null; + } } - /** + /** * Create a distance query using * a boundary box wrapper around a more precise * DistanceFilter. - * - * @see SerialChainFilter - * @param lat - * @param lng - * @param miles */ public Filter getFilter() { - Filter [] f; - int [] chain; - - if (needPrecision){ - f = new Filter[]{cartesianFilter, distanceFilter}; - chain = new int[] {SerialChainFilter.AND, - SerialChainFilter.SERIALAND}; - }else{ - f= new Filter[]{cartesianFilter}; - chain = new int[] {SerialChainFilter.AND}; - } - return new SerialChainFilter( f, chain ); + if (distanceFilter != null) { + distanceFilter.reset(); + } + return filter; } public Filter getFilter(Query query) { + // Chain the Query (as filter) with our distance filter + if (distanceFilter != null) { + distanceFilter.reset(); + } QueryWrapperFilter qf = new QueryWrapperFilter(query); - - Filter [] f; - int [] chain; - - if (needPrecision){ - f = new Filter[]{cartesianFilter, qf, distanceFilter}; - chain = new int[] {SerialChainFilter.AND, - SerialChainFilter.AND, - SerialChainFilter.SERIALAND}; - }else{ - f= new Filter[]{cartesianFilter, qf}; - chain = new int[] {SerialChainFilter.AND, - SerialChainFilter.AND}; - } - return new SerialChainFilter(f,chain); + return new ChainedFilter(new Filter[] {qf, filter}, + ChainedFilter.AND); } -// public Query getQuery() { -// return new ConstantScoreQuery(getFilter()); -// } - - public Query getQuery(Query query){ - return new ConstantScoreQuery(getFilter(query)); + return new ConstantScoreQuery(getFilter(query)); } public double getLat() { diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceSortSource.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceSortSource.java index ccf05643f84..26805081cf0 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceSortSource.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceSortSource.java @@ -71,19 +71,10 @@ public class DistanceSortSource implements SortComparatorSource { public int compare(ScoreDoc aDoc, ScoreDoc bDoc) { - -// if (this.distances == null) { -// distances = distanceFilter.getDistances(); -// } - //System.out.println("comparing : "+ aDoc.doc+ " - "+ bDoc.doc); - try { - double a = distanceFilter.getDistance(aDoc.doc); - double b = distanceFilter.getDistance(bDoc.doc); - if (a > b) return 1; - if (a < b )return -1; - } catch (Exception e){ - System.out.println(" Failed with sort with "+ aDoc.doc +" - "+bDoc.doc); - } + double a = distanceFilter.getDistance(aDoc.doc); + double b = distanceFilter.getDistance(bDoc.doc); + if (a > b) return 1; + if (a < b) return -1; return 0; } diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java index fedd8d32ffa..bdf6183c38e 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java @@ -18,19 +18,11 @@ package org.apache.lucene.spatial.tier; import java.io.IOException; -import java.util.BitSet; -import java.util.HashMap; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.logging.Logger; - import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.TermDocs; +import org.apache.lucene.search.FilteredDocIdSet; import org.apache.lucene.search.FieldCache; -import org.apache.lucene.util.NumericUtils; -import org.apache.lucene.spatial.tier.DistanceHandler.Precision; - - +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.DocIdSet; public class LatLongDistanceFilter extends DistanceFilter { @@ -40,192 +32,70 @@ public class LatLongDistanceFilter extends DistanceFilter { */ private static final long serialVersionUID = 1L; - double distance; double lat; double lng; String latField; String lngField; - Logger log = Logger.getLogger(getClass().getName()); int nextOffset = 0; - Map distances = null; - private Precision precise = null; - /** * Provide a distance filter based from a center point with a radius - * in miles + * in miles. + * @param startingFilter Filter to start from * @param lat * @param lng * @param miles * @param latField * @param lngField */ - public LatLongDistanceFilter(double lat, double lng, double miles, String latField, String lngField){ - distance = miles; + public LatLongDistanceFilter(Filter startingFilter, double lat, double lng, double miles, String latField, String lngField) { + super(startingFilter, miles); this.lat = lat; this.lng = lng; this.latField = latField; this.lngField = lngField; } - - public Map getDistances(){ - return distances; - } - - public Double getDistance(int docid){ - return distances.get(docid); - } - @Override - public BitSet bits(IndexReader reader) throws IOException { + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { - /* Create a BitSet to store the result */ - int maxdocs = reader.maxDoc(); - BitSet bits = new BitSet(maxdocs); - - setPrecision(maxdocs); - // create an intermediate cache to avoid recomputing - // distances for the same point - // TODO: Why is this a WeakHashMap? - WeakHashMap cdistance = new WeakHashMap(maxdocs); - long start = System.currentTimeMillis(); - double[] latIndex = FieldCache.DEFAULT.getDoubles(reader, latField); - double[] lngIndex = FieldCache.DEFAULT.getDoubles(reader, lngField); + final double[] latIndex = FieldCache.DEFAULT.getDoubles(reader, latField); + final double[] lngIndex = FieldCache.DEFAULT.getDoubles(reader, lngField); - /* store calculated distances for reuse by other components */ - distances = new HashMap(maxdocs); - - if (distances == null){ - distances = new HashMap(); - } + final int docBase = nextDocBase; + nextDocBase += reader.maxDoc(); - TermDocs td = reader.termDocs(null); - while(td.next()) { - int doc = td.doc(); + return new FilteredDocIdSet(startingFilter.getDocIdSet(reader)) { + protected boolean match(int doc) { + double x = latIndex[doc]; + double y = lngIndex[doc]; - double x = latIndex[doc]; - double y = lngIndex[doc]; + // round off lat / longs if necessary + // x = DistanceHandler.getPrecision(x, precise); + // y = DistanceHandler.getPrecision(y, precise); - // round off lat / longs if necessary -// x = DistanceHandler.getPrecision(x, precise); -// y = DistanceHandler.getPrecision(y, precise); - - String ck = new Double(x).toString()+","+new Double(y).toString(); - Double cachedDistance = cdistance.get(ck); - - - double d; - - if(cachedDistance != null){ - d = cachedDistance.doubleValue(); - } else { - d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); - cdistance.put(ck, d); + String ck = Double.toString(x)+","+Double.toString(y); + Double cachedDistance = distanceLookupCache.get(ck); + + double d; + if (cachedDistance != null){ + d = cachedDistance.doubleValue(); + } else { + d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); + distanceLookupCache.put(ck, d); + } + + if (d < distance) { + // Save distances, so they can be pulled for + // sorting after filtering is done: + distances.put(doc+docBase, d); + return true; + } else { + return false; + } } - - // why was i storing all distances again? - if (d < distance){ - bits.set(doc); - distances.put(doc+ nextOffset, d); // include nextOffset for multi segment reader - } - } - int size = bits.cardinality(); - nextOffset += reader.maxDoc(); // this should be something that's part of indexReader - long end = System.currentTimeMillis(); - log.fine("Bits 1: Time taken : "+ (end - start) + - ", results : "+ distances.size() + - ", cached : "+ cdistance.size() + - ", incoming size: "+ size+ - ", nextOffset: "+ nextOffset); - - return bits; - } - - - @Override - public BitSet bits(IndexReader reader, BitSet bits) throws Exception { - - - /* Create a BitSet to store the result */ - - int size = bits.cardinality(); - BitSet result = new BitSet(size); - - - /* create an intermediate cache to avoid recomputing - distances for the same point */ - HashMap cdistance = new HashMap(size); - - - - if (distances == null){ - distances = new HashMap(); - } - - long start = System.currentTimeMillis(); - double[] latIndex = FieldCache.DEFAULT.getDoubles(reader, latField); - double[] lngIndex = FieldCache.DEFAULT.getDoubles(reader, lngField); - - /* loop over all set bits (hits from the boundary box filters) */ - int i = bits.nextSetBit(0); - while (i >= 0){ - - if (reader.isDeleted(i)) { - i = bits.nextSetBit(i+1); - continue; - } - - double x,y; - - // if we have a completed - // filter chain, lat / lngs can be retrived from - // memory rather than document base. - - x = latIndex[i]; - y = lngIndex[i]; - - // round off lat / longs if necessary -// x = DistanceHandler.getPrecision(x, precise); -// y = DistanceHandler.getPrecision(y, precise); - - String ck = new Double(x).toString()+","+new Double(y).toString(); - Double cachedDistance = cdistance.get(ck); - double d; - - if(cachedDistance != null){ - d = cachedDistance.doubleValue(); - - } else { - d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); - //d = DistanceUtils.getLLMDistance(lat, lng, x, y); - cdistance.put(ck, d); - } - - // why was i storing all distances again? - if (d < distance){ - result.set(i); - int did = i + nextOffset; - distances.put(did, d); // include nextOffset for multi segment reader - - } - i = bits.nextSetBit(i+1); - } - - long end = System.currentTimeMillis(); - nextOffset += reader.maxDoc(); // this should be something that's part of indexReader - log.fine("Time taken : "+ (end - start) + - ", results : "+ distances.size() + - ", cached : "+ cdistance.size() + - ", incoming size: "+ size+ - ", nextOffset: "+ nextOffset); - - - cdistance = null; - - - return result; + }; } /** Returns true if o is equal to this. */ @@ -235,7 +105,8 @@ public class LatLongDistanceFilter extends DistanceFilter { if (!(o instanceof LatLongDistanceFilter)) return false; LatLongDistanceFilter other = (LatLongDistanceFilter) o; - if (this.distance != other.distance || + if (!this.startingFilter.equals(other.startingFilter) || + this.distance != other.distance || this.lat != other.lat || this.lng != other.lng || !this.latField.equals(other.latField) || @@ -249,28 +120,11 @@ public class LatLongDistanceFilter extends DistanceFilter { @Override public int hashCode() { int h = new Double(distance).hashCode(); + h ^= startingFilter.hashCode(); h ^= new Double(lat).hashCode(); h ^= new Double(lng).hashCode(); h ^= latField.hashCode(); h ^= lngField.hashCode(); return h; } - - - - public void setDistances(Map distances) { - this.distances = distances; - } - - void setPrecision(int maxDocs) { - precise = Precision.EXACT; - - if (maxDocs > 1000 && distance > 10) { - precise = Precision.TWENTYFEET; - } - - if (maxDocs > 10000 && distance > 10){ - precise = Precision.TWOHUNDREDFEET; - } - } } diff --git a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java index 17dd6708e50..bcd82b4c79b 100644 --- a/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java +++ b/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java @@ -82,7 +82,6 @@ public class CartesianTierPlotter { * * @param latitude * @param longitude - * @return */ public double getTierBoxId (double latitude, double longitude) { @@ -106,7 +105,6 @@ public class CartesianTierPlotter { /** * get the string name representing current tier * _localTier<tiedId> - * @return */ public String getTierFieldName (){ @@ -117,7 +115,6 @@ public class CartesianTierPlotter { * get the string name representing tierId * _localTier<tierId> * @param tierId - * @return */ public String getTierFieldName (int tierId){ @@ -133,12 +130,8 @@ public class CartesianTierPlotter { * * Distances less than a mile return 15, finer granularity is * in accurate - * - * @param latitude - * @param longitude - * @return */ - public int bestFit(int miles){ + public int bestFit(double miles){ //28,892 a rough circumference of the earth int circ = 28892; @@ -146,7 +139,6 @@ public class CartesianTierPlotter { double r = miles / 2.0; double corner = r - Math.sqrt(Math.pow(r, 2) / 2.0d); - System.out.println("corner "+ corner); double times = circ / corner; int bestFit = (int)Math.ceil(log2(times)) + 1; @@ -162,7 +154,6 @@ public class CartesianTierPlotter { * a log to the base 2 formula * Math.log(value) / Math.log(2) * @param value - * @return */ public double log2(double value) { diff --git a/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java b/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java index 5d43a06ba38..a6ce027e829 100644 --- a/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java +++ b/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java @@ -145,168 +145,178 @@ public class TestCartesian extends TestCase{ public void testRange() throws IOException, InvalidGeoException { searcher = new IndexSearcher(directory); + + final double[] milesToTest = new double[] {6.0, 0.5, 0.001, 0.0}; + final int[] expected = new int[] {7, 1, 0, 0}; + + for(int x=0;x distances = dq.distanceFilter.getDistances(); + + // distances calculated from filter first pass must be less than total + // docs, from the above test of 20 items, 12 will come from the boundary box + // filter, but only 5 are actually in the radius of the results. + + // Note Boundary Box filtering, is not accurate enough for most systems. + + + System.out.println("Distance Filter filtered: " + distances.size()); + System.out.println("Results: " + results); + System.out.println("============================="); + System.out.println("Distances should be 7 "+ distances.size()); + System.out.println("Results should be 7 "+ results); + + assertEquals(expected[x], distances.size()); // fixed a store of only needed distances + assertEquals(expected[x], results); + double lastDistance = 0; + for(int i =0 ; i < results; i++){ + Document d = hits.doc(i); + + String name = d.get("name"); + double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField)); + double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField)); + Double geo_distance = distances.get(hits.id(i)); + + double distance = DistanceUtils.getInstance().getDistanceMi(lat, lng, rsLat, rsLng); + double llm = DistanceUtils.getInstance().getLLMDistance(lat, lng, rsLat, rsLng); + System.out.println("Name: "+ name +", Distance "+ distance); //(res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i)); + assertTrue(Math.abs((distance - llm)) < 1); + assertTrue((distance < miles )); + assertTrue(geo_distance > lastDistance); + lastDistance = geo_distance; } - }; - // Create a distance sort - // As the radius filter has performed the distance calculations - // already, pass in the filter to reuse the results. - // - DistanceFieldComparatorSource dsort = new DistanceFieldComparatorSource(dq.distanceFilter); - Sort sort = new Sort(new SortField("foo", dsort,false)); - - // Perform the search, using the term query, the serial chain filter, and the - // distance sort - Hits hits = searcher.search(customScore,null,sort); - - int results = hits.length(); - - // Get a list of distances - Map distances = dq.distanceFilter.getDistances(); - - // distances calculated from filter first pass must be less than total - // docs, from the above test of 20 items, 12 will come from the boundary box - // filter, but only 5 are actually in the radius of the results. - - // Note Boundary Box filtering, is not accurate enough for most systems. - - - System.out.println("Distance Filter filtered: " + distances.size()); - System.out.println("Results: " + results); - System.out.println("============================="); - System.out.println("Distances should be 7 "+ distances.size()); - System.out.println("Results should be 7 "+ results); - - assertEquals(7, distances.size()); // fixed a store of only needed distances - assertEquals(7, results); - double lastDistance = 0; - for(int i =0 ; i < results; i++){ - Document d = hits.doc(i); - - String name = d.get("name"); - double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField)); - double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField)); - Double geo_distance = distances.get(hits.id(i)); - - double distance = DistanceUtils.getInstance().getDistanceMi(lat, lng, rsLat, rsLng); - double llm = DistanceUtils.getInstance().getLLMDistance(lat, lng, rsLat, rsLng); - System.out.println("Name: "+ name +", Distance "+ distance); //(res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i)); - assertTrue(Math.abs((distance - llm)) < 1); - assertTrue((distance < miles )); - assertTrue(geo_distance > lastDistance); - lastDistance = geo_distance; } } public void testGeoHashRange() throws IOException, InvalidGeoException { - searcher = new IndexSearcher(directory); + searcher = new IndexSearcher(directory); - final double miles = 6.0; + final double[] milesToTest = new double[] {6.0, 0.5, 0.001, 0.0}; + final int[] expected = new int[] {7, 1, 0, 0}; + + for(int x=0;x distances = dq.distanceFilter.getDistances(); + // Get a list of distances + Map distances = dq.distanceFilter.getDistances(); - // distances calculated from filter first pass must be less than total - // docs, from the above test of 20 items, 12 will come from the boundary box - // filter, but only 5 are actually in the radius of the results. + // distances calculated from filter first pass must be less than total + // docs, from the above test of 20 items, 12 will come from the boundary box + // filter, but only 5 are actually in the radius of the results. - // Note Boundary Box filtering, is not accurate enough for most systems. + // Note Boundary Box filtering, is not accurate enough for most systems. - System.out.println("Distance Filter filtered: " + distances.size()); - System.out.println("Results: " + results); - System.out.println("============================="); - System.out.println("Distances should be 14 "+ distances.size()); - System.out.println("Results should be 7 "+ results); + System.out.println("Distance Filter filtered: " + distances.size()); + System.out.println("Results: " + results); + System.out.println("============================="); + System.out.println("Distances should be 14 "+ distances.size()); + System.out.println("Results should be 7 "+ results); - assertEquals(14, distances.size()); - assertEquals(7, results); + assertEquals(expected[x], distances.size()); + assertEquals(expected[x], results); - for(int i =0 ; i < results; i++){ - Document d = hits.doc(i); + for(int i =0 ; i < results; i++){ + Document d = hits.doc(i); - String name = d.get("name"); - double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField)); - double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField)); - Double geo_distance = distances.get(hits.id(i)); + String name = d.get("name"); + double rsLat = NumericUtils.prefixCodedToDouble(d.get(latField)); + double rsLng = NumericUtils.prefixCodedToDouble(d.get(lngField)); + Double geo_distance = distances.get(hits.id(i)); - double distance = DistanceUtils.getInstance().getDistanceMi(lat, lng, rsLat, rsLng); - double llm = DistanceUtils.getInstance().getLLMDistance(lat, lng, rsLat, rsLng); - System.out.println("Name: "+ name +", Distance (res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i)); - assertTrue(Math.abs((distance - llm)) < 1); - assertTrue((distance < miles )); + double distance = DistanceUtils.getInstance().getDistanceMi(lat, lng, rsLat, rsLng); + double llm = DistanceUtils.getInstance().getLLMDistance(lat, lng, rsLat, rsLng); + System.out.println("Name: "+ name +", Distance (res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i)); + assertTrue(Math.abs((distance - llm)) < 1); + assertTrue((distance < miles )); - } - } - + } + } + } } diff --git a/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java b/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java index 9d0a135d9c3..a1b919b21c7 100644 --- a/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java +++ b/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java @@ -17,7 +17,6 @@ package org.apache.lucene.spatial.tier; import java.io.IOException; -import java.util.BitSet; import junit.framework.TestCase; @@ -27,10 +26,9 @@ import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.index.IndexReader; -import org.apache.lucene.search.Filter; -import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.QueryWrapperFilter; +import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.util.NumericUtils; -import org.apache.lucene.spatial.tier.LatLongDistanceFilter; import org.apache.lucene.store.RAMDirectory; @@ -41,7 +39,6 @@ public class TestDistance extends TestCase{ private RAMDirectory directory; - private IndexSearcher searcher; // reston va private double lat = 38.969398; private double lng= -77.386398; @@ -103,13 +100,13 @@ public class TestDistance extends TestCase{ public void testLatLongFilterOnDeletedDocs() throws Exception { writer.deleteDocuments(new Term("name", "Potomac")); IndexReader r = writer.getReader(); - LatLongDistanceFilter f = new LatLongDistanceFilter(lat, lng, 1.0, latField, lngField); - f.bits(r); + LatLongDistanceFilter f = new LatLongDistanceFilter(new QueryWrapperFilter(new MatchAllDocsQuery()), + lat, lng, 1.0, latField, lngField); - BitSet allSet = new BitSet(r.maxDoc()); - allSet.set(0, r.maxDoc()); - f.bits(r, allSet); - r.close(); + IndexReader[] readers = r.getSequentialSubReaders(); + for(int i=0;i