mirror of https://github.com/apache/lucene.git
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:
parent
a4c2eae1d4
commit
d79a369414
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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() + ")";
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* <code>Math.log(value) / Math.log(2)</code>
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public double log2(double value) {
|
||||
|
||||
|
|
|
@ -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 ));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue