LUCENE-4389 Support dateline and circles for TwoDoublesStrategy

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1385130 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
David Wayne Smiley 2012-09-15 17:06:10 +00:00
parent 11e072c590
commit 922c7316d8
4 changed files with 55 additions and 45 deletions

View File

@ -29,7 +29,7 @@ import java.io.IOException;
/**
* Filter that matches all documents where a valuesource is
* in between a range of <code>min</code> and <code>max</code>
* in between a range of <code>min</code> and <code>max</code> inclusive.
* @lucene.internal
*/
public class ValueSourceFilter extends Filter {
@ -57,7 +57,7 @@ public class ValueSourceFilter extends Filter {
@Override
public boolean match(int doc) {
double val = values.doubleVal( doc );
return val > min && val < max;
return val >= min && val <= max;
}
};
}

View File

@ -101,7 +101,13 @@ public class TwoDoublesStrategy extends SpatialStrategy {
@Override
public Filter makeFilter(SpatialArgs args) {
return new QueryWrapperFilter(makeQuery(args).getQuery());
//unwrap the CSQ from makeQuery
ConstantScoreQuery csq = makeQuery(args);
Filter filter = csq.getFilter();
if (filter != null)
return filter;
else
return new QueryWrapperFilter(csq.getQuery());
}
@Override
@ -111,15 +117,25 @@ public class TwoDoublesStrategy extends SpatialStrategy {
SpatialOperation.IsWithin ))
throw new UnsupportedSpatialOperation(args.getOperation());
Shape shape = args.getShape();
if (!(shape instanceof Rectangle))
throw new InvalidShapeException("Only Rectangle is currently supported, got "+shape.getClass());
if (shape instanceof Rectangle) {
Rectangle bbox = (Rectangle) shape;
if (bbox.getCrossesDateLine()) {
throw new UnsupportedOperationException( "Crossing dateline not yet supported" );
}
return new ConstantScoreQuery(makeWithin(bbox));
} else if (shape instanceof Circle) {
Circle circle = (Circle)shape;
Rectangle bbox = circle.getBoundingBox();
ValueSourceFilter vsf = new ValueSourceFilter(
new QueryWrapperFilter(makeWithin(bbox)),
makeDistanceValueSource(circle.getCenter()),
0,
circle.getRadius() );
return new ConstantScoreQuery(vsf);
} else {
throw new InvalidShapeException("Only Rectangles and Circles are currently supported, " +
"found [" + shape.getClass() + "]");//TODO
}
}
//TODO this is basically old code that hasn't been verified well and should probably be removed
public Query makeQueryDistanceScore(SpatialArgs args) {
// For starters, just limit the bbox
Shape shape = args.getShape();
@ -183,49 +199,40 @@ public class TwoDoublesStrategy extends SpatialStrategy {
/**
* Constructs a query to retrieve documents that fully contain the input envelope.
* @return the spatial query
*/
private Query makeWithin(Rectangle bbox) {
Query qX = NumericRangeQuery.newDoubleRange(
fieldNameX,
precisionStep,
bbox.getMinX(),
bbox.getMaxX(),
true,
true);
Query qY = NumericRangeQuery.newDoubleRange(
fieldNameY,
precisionStep,
bbox.getMinY(),
bbox.getMaxY(),
true,
true);
BooleanQuery bq = new BooleanQuery();
bq.add(qX,BooleanClause.Occur.MUST);
bq.add(qY,BooleanClause.Occur.MUST);
BooleanClause.Occur MUST = BooleanClause.Occur.MUST;
if (bbox.getCrossesDateLine()) {
//use null as performance trick since no data will be beyond the world bounds
bq.add(rangeQuery(fieldNameX, null/*-180*/, bbox.getMaxX()), BooleanClause.Occur.SHOULD );
bq.add(rangeQuery(fieldNameX, bbox.getMinX(), null/*+180*/), BooleanClause.Occur.SHOULD );
bq.setMinimumNumberShouldMatch(1);//must match at least one of the SHOULD
} else {
bq.add(rangeQuery(fieldNameX, bbox.getMinX(), bbox.getMaxX()), MUST);
}
bq.add(rangeQuery(fieldNameY, bbox.getMinY(), bbox.getMaxY()), MUST);
return bq;
}
private NumericRangeQuery<Double> rangeQuery(String fieldName, Double min, Double max) {
return NumericRangeQuery.newDoubleRange(
fieldName,
precisionStep,
min,
max,
true,
true);//inclusive
}
/**
* Constructs a query to retrieve documents that fully contain the input envelope.
* @return the spatial query
*/
Query makeDisjoint(Rectangle bbox) {
Query qX = NumericRangeQuery.newDoubleRange(
fieldNameX,
precisionStep,
bbox.getMinX(),
bbox.getMaxX(),
true,
true);
Query qY = NumericRangeQuery.newDoubleRange(
fieldNameY,
precisionStep,
bbox.getMinY(),
bbox.getMaxY(),
true,
true);
private Query makeDisjoint(Rectangle bbox) {
if (bbox.getCrossesDateLine())
throw new UnsupportedOperationException("makeDisjoint doesn't handle dateline cross");
Query qX = rangeQuery(fieldNameX, bbox.getMinX(), bbox.getMaxX());
Query qY = rangeQuery(fieldNameY, bbox.getMinY(), bbox.getMaxY());
BooleanQuery bq = new BooleanQuery();
bq.add(qX,BooleanClause.Occur.MUST_NOT);

View File

@ -34,6 +34,7 @@ import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.lucene.spatial.vector.TwoDoublesStrategy;
import org.junit.Test;
import java.io.IOException;
@ -67,6 +68,9 @@ public class PortedSolr3Test extends StrategyTestCase {
strategy = new TermQueryPrefixTreeStrategy(grid, "termquery_geohash");
ctorArgs.add(new Object[]{new Param(strategy, "termquery_geohash")});
strategy = new TwoDoublesStrategy(ctx, "twodoubles");
ctorArgs.add(new Object[]{new Param(strategy, "twodoubles")});
return ctorArgs;
}

View File

@ -27,7 +27,6 @@ import org.apache.lucene.spatial.StrategyTestCase;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import java.io.IOException;
@ -42,7 +41,7 @@ public class TestTwoDoublesStrategy extends StrategyTestCase {
this.strategy = new TwoDoublesStrategy(ctx, getClass().getSimpleName());
}
@Test @Ignore
@Test
public void testCircleShapeSupport() {
Circle circle = ctx.makeCircle(ctx.makePoint(0, 0), 10);
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle);