LUCENE-5714: BBoxStrategy should convert shapes to bounding box on indexing (but not search)

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1609468 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
David Wayne Smiley 2014-07-10 14:27:49 +00:00
parent 8e7ad8727c
commit 8f7dc8d07b
2 changed files with 23 additions and 30 deletions

View File

@ -54,21 +54,22 @@ import org.apache.lucene.util.NumericUtils;
* *
* <h4>Characteristics:</h4> * <h4>Characteristics:</h4>
* <ul> * <ul>
* <li>Only indexes Rectangles; just one per field value.</li> * <li>Only indexes Rectangles; just one per field value. Other shapes can be provided
* <li>Can query only by a Rectangle.</li> * and the bounding box will be used.</li>
* <li>Supports most {@link SpatialOperation}s -- not Overlaps.</li> * <li>Can query only by a Rectangle. Providing other shapes is an error.</li>
* <li>Supports most {@link SpatialOperation}s but not Overlaps.</li>
* <li>Uses the DocValues API for any sorting / relevancy.</li> * <li>Uses the DocValues API for any sorting / relevancy.</li>
* </ul> * </ul>
* *
* <h4>Implementation:</h4> * <h4>Implementation:</h4>
* This uses 4 double fields for minX, maxX, minY, maxY * This uses 4 double fields for minX, maxX, minY, maxY
* and a boolean to mark a dateline cross. Depending on the particular {@link * and a boolean to mark a dateline cross. Depending on the particular {@link
* SpatialOperation}s, there is a variety of {@link NumericRangeQuery}s to be * SpatialOperation}s, there are a variety of {@link NumericRangeQuery}s to be
* done. * done.
* The {@link #makeOverlapRatioValueSource(com.spatial4j.core.shape.Rectangle, double)} * The {@link #makeOverlapRatioValueSource(com.spatial4j.core.shape.Rectangle, double)}
* works by calculating the query bbox overlap percentage against the indexed * works by calculating the query bbox overlap percentage against the indexed
* shape overlap percentage. The indexed shape's coordinates are retrieved from * shape overlap percentage. The indexed shape's coordinates are retrieved from
* {@link AtomicReader#getNumericDocValues} * {@link AtomicReader#getNumericDocValues}.
* *
* @lucene.experimental * @lucene.experimental
*/ */
@ -117,6 +118,9 @@ public class BBoxStrategy extends SpatialStrategy {
return fieldType; return fieldType;
} }
/** Used to customize the indexing options of the 4 number fields, and to a lesser degree the XDL field too. Search
* requires indexed=true, and relevancy requires docValues. If these features aren't needed then disable them.
* {@link FieldType#freeze()} is called on the argument. */
public void setFieldType(FieldType fieldType) { public void setFieldType(FieldType fieldType) {
fieldType.freeze(); fieldType.freeze();
this.fieldType = fieldType; this.fieldType = fieldType;
@ -136,17 +140,25 @@ public class BBoxStrategy extends SpatialStrategy {
@Override @Override
public Field[] createIndexableFields(Shape shape) { public Field[] createIndexableFields(Shape shape) {
if (shape instanceof Rectangle) return createIndexableFields(shape.getBoundingBox());
return createIndexableFields((Rectangle)shape);
throw new UnsupportedOperationException("Can only index a Rectangle, not " + shape);
} }
/** Field subclass circumventing Field limitations. This one instance can optionally index, store, public Field[] createIndexableFields(Rectangle bbox) {
* or have DocValues. Field[] fields = new Field[5];
fields[0] = new ComboField(field_minX, bbox.getMinX(), fieldType);
fields[1] = new ComboField(field_maxX, bbox.getMaxX(), fieldType);
fields[2] = new ComboField(field_minY, bbox.getMinY(), fieldType);
fields[3] = new ComboField(field_maxY, bbox.getMaxY(), fieldType);
fields[4] = new ComboField(field_xdl, bbox.getCrossesDateLine()?"T":"F", xdlFieldType);
return fields;
}
/** Field subclass circumventing Field limitations. This one instance can have any combination of indexed, stored,
* and docValues.
*/ */
private static class ComboField extends Field { private static class ComboField extends Field {
private ComboField(String name, Object value, FieldType type) { private ComboField(String name, Object value, FieldType type) {
super(name, type);//this expert constructor allows us to have a field that has docValues & indexed super(name, type);//this expert constructor allows us to have a field that has docValues & indexed/stored
super.fieldsData = value; super.fieldsData = value;
} }
@ -165,16 +177,6 @@ public class BBoxStrategy extends SpatialStrategy {
} }
} }
public Field[] createIndexableFields(Rectangle bbox) {
Field[] fields = new Field[5];
fields[0] = new ComboField(field_minX, bbox.getMinX(), fieldType);
fields[1] = new ComboField(field_maxX, bbox.getMaxX(), fieldType);
fields[2] = new ComboField(field_minY, bbox.getMinY(), fieldType);
fields[3] = new ComboField(field_maxY, bbox.getMaxY(), fieldType);
fields[4] = new ComboField(field_xdl, bbox.getCrossesDateLine()?"T":"F", xdlFieldType);
return fields;
}
//--------------------------------- //---------------------------------
// Value Source / Relevancy // Value Source / Relevancy
//--------------------------------- //---------------------------------

View File

@ -22,7 +22,6 @@ import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import com.spatial4j.core.context.SpatialContext; import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.shape.Point; import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Shape; import com.spatial4j.core.shape.Shape;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.FieldType; import org.apache.lucene.document.FieldType;
import org.apache.lucene.spatial.bbox.BBoxStrategy; import org.apache.lucene.spatial.bbox.BBoxStrategy;
import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy; import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
@ -139,14 +138,6 @@ public class DistanceStrategyTest extends StrategyTestCase {
new float[]{1.00f, 0.10f, 0f}, 0.09f); new float[]{1.00f, 0.10f, 0f}, 0.09f);
} }
@Override
protected Document newDoc(String id, Shape shape) {
//called by adoc(). Make compatible with BBoxStrategy.
if (shape != null && strategy instanceof BBoxStrategy)
shape = ctx.makeRectangle(shape.getCenter(), shape.getCenter());
return super.newDoc(id, shape);
}
void checkDistValueSource(Point pt, float... distances) throws IOException { void checkDistValueSource(Point pt, float... distances) throws IOException {
float multiplier = random().nextFloat() * 100f; float multiplier = random().nextFloat() * 100f;
float[] dists2 = Arrays.copyOf(distances, distances.length); float[] dists2 = Arrays.copyOf(distances, distances.length);