LUCENE-1504: switch to DocIdSet API and FilteredDocIdSet for contrib/spatial

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@800892 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2009-08-04 18:01:57 +00:00
parent a4c2eae1d4
commit d79a369414
21 changed files with 376 additions and 880 deletions

View File

@ -25,8 +25,23 @@
<property name="javac.source" value="1.5" />
<property name="javac.target" value="1.5" />
<import file="../contrib-build.xml"/>
<property name="misc.jar" location="${common.dir}/build/contrib/misc/lucene-misc-${version}.jar"/>
<available property="memory.jar.present" type="file" file="${memory.jar}"/>
<path id="classpath">
<pathelement path="${lucene.jar}"/>
<pathelement path="${misc.jar}"/>
<pathelement path="${project.classpath}"/>
</path>
<target name="compile-core" depends="build-misc, common.compile-core" />
<target name="build-misc" unless="memory.jar.present">
<echo>Misc building dependency ${misc.jar}</echo>
<ant antfile="../miscellaneous/build.xml" target="default" inheritall="false" dir="../miscellaneous" />
</target>
</project>

View File

@ -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;
}

View File

@ -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 <code>o</code> 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() + ")";
}
}

View File

@ -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<Integer,Double> 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<Integer,Double> 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<String,Double> cdistance = new WeakHashMap<String,Double>(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<Integer,Double>(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<String,Double> cdistance = new HashMap<String,Double>(size);
/* store calculated distances for reuse by other components */
offset += reader.maxDoc();
if (distances == null)
distances = new HashMap<Integer,Double>(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 <code>o</code> 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<Integer, Double> distances) {
this.distances = distances;
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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();

View File

@ -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);

View File

@ -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());

View File

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

View File

@ -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());

View File

@ -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<Double> 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;
}
}

View File

@ -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<Integer,Double> distances;
protected double distance;
public DistanceFilter() {
super();
}
protected int nextDocBase;
protected final WeakHashMap<String,Double> distanceLookupCache;
public abstract Map<Integer,Double> 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<Integer,Double>();
@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<String,Double>();
}
/** Returns true if <code>o</code> is equal to this. */
@Override
public abstract boolean equals(Object o);
public Map<Integer,Double> getDistances(){
return distances;
}
public Double getDistance(int docid){
return distances.get(docid);
}
public void setDistances(Map<Integer, Double> 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<Integer, Double> distances);
/** Returns true if <code>o</code> is equal to this. */
public abstract boolean equals(Object o);
}
/** 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;
}
}
*/
}

View File

@ -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() {

View File

@ -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;
}

View File

@ -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<Integer,Double> 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<Integer,Double> 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<String,Double> cdistance = new WeakHashMap<String,Double>(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<Integer,Double>(maxdocs);
if (distances == null){
distances = new HashMap<Integer,Double>();
}
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<String,Double> cdistance = new HashMap<String,Double>(size);
if (distances == null){
distances = new HashMap<Integer,Double>();
}
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 <code>o</code> 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<Integer, Double> 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;
}
}
}

View File

@ -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&lt;tiedId&gt;
* @return
*/
public String getTierFieldName (){
@ -117,7 +115,6 @@ public class CartesianTierPlotter {
* get the string name representing tierId
* _localTier&lt;tierId&gt;
* @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
* <code>Math.log(value) / Math.log(2)</code>
* @param value
* @return
*/
public double log2(double value) {

View File

@ -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<expected.length;x++) {
final double miles = 6.0;
final double miles = milesToTest[x];
// create a distance query
final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
latField, lngField, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true);
// create a distance query
final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
latField, lngField, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true);
System.out.println(dq);
//create a term query to search against all documents
Query tq = new TermQuery(new Term("metafile", "doc"));
System.out.println(dq);
//create a term query to search against all documents
Query tq = new TermQuery(new Term("metafile", "doc"));
FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
CustomScoreQuery customScore = new CustomScoreQuery(dq.getQuery(tq),fsQuery){
CustomScoreQuery customScore = new CustomScoreQuery(dq.getQuery(tq),fsQuery){
@Override
public float customScore(int doc, float subQueryScore, float valSrcScore){
//System.out.println(doc);
if (dq.distanceFilter.getDistance(doc) == null)
return 0;
@Override
public float customScore(int doc, float subQueryScore, float valSrcScore){
//System.out.println(doc);
if (dq.distanceFilter.getDistance(doc) == null)
return 0;
double distance = dq.distanceFilter.getDistance(doc);
// boost score shouldn't exceed 1
if (distance < 1.0d)
distance = 1.0d;
//boost by distance is invertly proportional to
// to distance from center point to location
float score = new Float((miles - distance) / miles ).floatValue();
return score * subQueryScore;
double distance = dq.distanceFilter.getDistance(doc);
// boost score shouldn't exceed 1
if (distance < 1.0d)
distance = 1.0d;
//boost by distance is invertly proportional to
// to distance from center point to location
float score = new Float((miles - distance) / miles ).floatValue();
return score * subQueryScore;
}
};
// 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<Integer,Double> 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<Integer,Double> 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<expected.length;x++) {
final double miles = milesToTest[x];
// create a distance query
final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
geoHashPrefix, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true);
// create a distance query
final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
geoHashPrefix, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true);
System.out.println(dq);
//create a term query to search against all documents
Query tq = new TermQuery(new Term("metafile", "doc"));
System.out.println(dq);
//create a term query to search against all documents
Query tq = new TermQuery(new Term("metafile", "doc"));
FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
CustomScoreQuery customScore = new CustomScoreQuery(tq,fsQuery){
FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
CustomScoreQuery customScore = new CustomScoreQuery(tq,fsQuery){
@Override
public float customScore(int doc, float subQueryScore, float valSrcScore){
//System.out.println(doc);
if (dq.distanceFilter.getDistance(doc) == null)
return 0;
@Override
public float customScore(int doc, float subQueryScore, float valSrcScore){
//System.out.println(doc);
if (dq.distanceFilter.getDistance(doc) == null)
return 0;
double distance = dq.distanceFilter.getDistance(doc);
// boost score shouldn't exceed 1
if (distance < 1.0d)
distance = 1.0d;
//boost by distance is invertly proportional to
// to distance from center point to location
float score = new Float((miles - distance) / miles ).floatValue();
return score * subQueryScore;
}
};
// Create a distance sort
// As the radius filter has performed the distance calculations
// already, pass in the filter to reuse the results.
//
DistanceSortSource dsort = new DistanceSortSource(dq.distanceFilter);
Sort sort = new Sort(new SortField("foo", dsort));
double distance = dq.distanceFilter.getDistance(doc);
// boost score shouldn't exceed 1
if (distance < 1.0d)
distance = 1.0d;
//boost by distance is invertly proportional to
// to distance from center point to location
float score = new Float((miles - distance) / miles ).floatValue();
return score * subQueryScore;
}
};
// Create a distance sort
// As the radius filter has performed the distance calculations
// already, pass in the filter to reuse the results.
//
DistanceSortSource dsort = new DistanceSortSource(dq.distanceFilter);
Sort sort = new Sort(new SortField("foo", dsort));
// Perform the search, using the term query, the serial chain filter, and the
// distance sort
Hits hits = searcher.search(customScore, dq.getFilter()); //,sort);
// Perform the search, using the term query, the serial chain filter, and the
// distance sort
Hits hits = searcher.search(customScore, dq.getFilter()); //,sort);
int results = hits.length();
int results = hits.length();
// Get a list of distances
Map<Integer,Double> distances = dq.distanceFilter.getDistances();
// Get a list of distances
Map<Integer,Double> 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 ));
}
}
}
}
}
}

View File

@ -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<readers.length;i++) {
f.getDocIdSet(readers[i]);
}
}

View File

@ -54,7 +54,7 @@ public abstract class FilteredDocIdSet extends DocIdSet {
* @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 @@ public abstract class FilteredDocIdSet extends DocIdSet {
// @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);
}
};

View File

@ -47,7 +47,7 @@ public abstract class FilteredDocIdSetIterator extends DocIdSetIterator {
* @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() {