Index: src/java/org/apache/lucene/search/FilteredDocIdSetIterator.java =================================================================== --- src/java/org/apache/lucene/search/FilteredDocIdSetIterator.java (revision 799636) +++ src/java/org/apache/lucene/search/FilteredDocIdSetIterator.java (working copy) @@ -47,7 +47,7 @@ * @return true if input docid should be in the result set, false otherwise. * @see #FilteredDocIdSetIterator(DocIdSetIterator). */ - abstract protected boolean match(int doc); + abstract protected boolean match(int doc) throws IOException; /** @deprecated use {@link #docID()} instead. */ public final int doc() { Index: src/java/org/apache/lucene/search/FilteredDocIdSet.java =================================================================== --- src/java/org/apache/lucene/search/FilteredDocIdSet.java (revision 799636) +++ src/java/org/apache/lucene/search/FilteredDocIdSet.java (working copy) @@ -54,7 +54,7 @@ * @param docid docid to be tested * @return true if input docid should be in the result set, false otherwise. */ - protected abstract boolean match(int docid); + protected abstract boolean match(int docid) throws IOException; /** * Implementation of the contract to build a DocIdSetIterator. @@ -64,7 +64,7 @@ // @Override public DocIdSetIterator iterator() throws IOException { return new FilteredDocIdSetIterator(_innerSet.iterator()) { - protected boolean match(int docid) { + protected boolean match(int docid) throws IOException { return FilteredDocIdSet.this.match(docid); } }; Index: contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java =================================================================== --- contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java (revision 799641) +++ contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java (working copy) @@ -289,7 +289,7 @@ System.out.println("Distances should be 14 "+ distances.size()); System.out.println("Results should be 7 "+ results); - assertEquals(14, distances.size()); + assertEquals(7, distances.size()); assertEquals(7, results); for(int i =0 ; i < results; i++){ Index: contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java =================================================================== --- contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java (revision 799636) +++ contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestDistance.java (working copy) @@ -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.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 @@ private RAMDirectory directory; - private IndexSearcher searcher; // reston va private double lat = 38.969398; private double lng= -77.386398; @@ -103,13 +100,13 @@ 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;iMath.log(value) / Math.log(2) * @param value - * @return */ public double log2(double value) { Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFilter.java (working copy) @@ -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; + } + } + */ +} Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/LatLongDistanceFilter.java (working copy) @@ -18,21 +18,13 @@ 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 @@ */ 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); - } - - // 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; - } + String ck = Double.toString(x)+","+Double.toString(y); + Double cachedDistance = distanceLookupCache.get(ck); - - @Override - public BitSet bits(IndexReader reader, BitSet bits) throws Exception { + double d; + if (cachedDistance != null){ + d = cachedDistance.doubleValue(); + } else { + d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); + distanceLookupCache.put(ck, d); + } - - /* 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; + 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; + } } - - 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 @@ 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 @@ @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; - } - } } Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceQueryBuilder.java (working copy) @@ -21,8 +21,8 @@ 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 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, (int)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 @@ * 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, (int) 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() { Index: contrib/spatial/src/java/org/apache/lucene/spatial/SerialChainFilter.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/SerialChainFilter.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/SerialChainFilter.java (working copy) @@ -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() + ")"; - } -} Index: contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Geometry2D.java (working copy) @@ -31,26 +31,22 @@ /** * 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); Index: contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java (working copy) @@ -41,7 +41,6 @@ /** * 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 @@ * @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 @@ /** * Returns a rectangle shape for the bounding box - * @return */ public Rectangle toRectangle() { return new Rectangle(ll.getLng(), ll.getLat(), ur.getLng(), ur.getLat()); Index: contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/Ellipse.java (working copy) @@ -56,9 +56,6 @@ /** * Constructor given bounding rectangle and a rotation. - * - * @param - * @param */ public Ellipse(Point2D p1, Point2D p2, double angle) { center = new Point2D(); Index: contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java (working copy) @@ -22,7 +22,6 @@ * 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 @@ * 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 @@ /** * 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 @@ /** * Calculate the midpoint between this point an another. Respects fixed vs floating point * @param other - * @return */ public abstract LatLng calculateMidpoint(LatLng other); } Index: contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geometry/CartesianPoint.java (working copy) @@ -46,9 +46,6 @@ /** * 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); Index: contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java (revision 799636) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geohash/GeoHashDistanceFilter.java (working copy) @@ -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 @@ */ 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 { - /* 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); - - - /* 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; - } - - @Override - public BitSet bits(IndexReader reader, BitSet bits) throws Exception { + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { - - /* Create a BitSet to store the result */ - int size = bits.cardinality(); - BitSet result = new BitSet(size); - + final String[] geoHashValues = FieldCache.DEFAULT.getStrings(reader, geoHashField); - /* create an intermediate cache to avoid recomputing - distances for the same point */ - HashMap cdistance = new HashMap(size); - + final int docBase = nextDocBase; + nextDocBase += reader.maxDoc(); - /* 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){ + return new FilteredDocIdSet(startingFilter.getDocIdSet(reader)) { + public boolean match(int doc) { + + String geoHash = geoHashValues[doc]; + double[] coords = GeoHashUtils.decode(geoHash); + double x = coords[0]; + double y = coords[1]; - // 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 = distanceLookupCache.get(geoHash); + double d; - // round off lat / longs if necessary -// x = DistanceHandler.getPrecision(x, precise); -// y = DistanceHandler.getPrecision(y, precise); + if (cachedDistance != null) { + d = cachedDistance.doubleValue(); + } else { + d = DistanceUtils.getInstance().getDistanceMi(lat, lng, x, y); + distanceLookupCache.put(geoHash, d); + } - - Double cachedDistance = cdistance.get(geoHash); - 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(geoHash, d); + if (d < distance){ + distances.put(doc+docBase, d); + return true; + } else { + return false; + } } - - 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); - - - cdistance = null; - nextOffset += offset; - return result; + }; } /** Returns true if o is equal to this. */ @@ -209,7 +101,8 @@ 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 @@ @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; - } } Index: contrib/spatial/build.xml =================================================================== --- contrib/spatial/build.xml (revision 799636) +++ contrib/spatial/build.xml (working copy) @@ -25,8 +25,23 @@ - + + + + + + + + + + + + + Misc building dependency ${misc.jar} + + +