mirror of https://github.com/apache/lucene.git
LUCENE-4099 remove SpatialFieldInfo (and corresponding generics) and put fieldName into Strategy instead of methods. Thus an instance of SpatialStrategy is now a per-field object, not per-fieldType.
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1357451 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e58e456156
commit
c92eb67f6d
|
@ -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;
|
||||
|
||||
/**
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public class SimpleSpatialFieldInfo implements SpatialFieldInfo {
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
public SimpleSpatialFieldInfo(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
}
|
|
@ -1,26 +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;
|
||||
|
||||
/**
|
||||
* Information the strategy needs for the lucene fields
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public interface SpatialFieldInfo {
|
||||
}
|
|
@ -32,13 +32,22 @@ import org.apache.lucene.spatial.query.SpatialArgs;
|
|||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public abstract class SpatialStrategy<T extends SpatialFieldInfo> {
|
||||
public abstract class SpatialStrategy {
|
||||
|
||||
protected boolean ignoreIncompatibleGeometry = false;
|
||||
protected final SpatialContext ctx;
|
||||
private final String fieldName;
|
||||
|
||||
public SpatialStrategy(SpatialContext ctx) {
|
||||
/**
|
||||
* Constructs the spatial strategy with its mandatory arguments.
|
||||
*/
|
||||
public SpatialStrategy(SpatialContext ctx, String fieldName) {
|
||||
if (ctx == null)
|
||||
throw new IllegalArgumentException("ctx is required");
|
||||
this.ctx = ctx;
|
||||
if (fieldName == null || fieldName.length() == 0)
|
||||
throw new IllegalArgumentException("fieldName is required");
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public SpatialContext getSpatialContext() {
|
||||
|
@ -50,6 +59,15 @@ public abstract class SpatialStrategy<T extends SpatialFieldInfo> {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the field or the prefix of them if there are multiple
|
||||
* fields needed internally.
|
||||
* @return Not null.
|
||||
*/
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Corresponds with Solr's FieldType.createField().
|
||||
*
|
||||
|
@ -57,33 +75,33 @@ public abstract class SpatialStrategy<T extends SpatialFieldInfo> {
|
|||
* This is reasonable behavior if 'ignoreIncompatibleGeometry=true' and the
|
||||
* geometry is incompatible
|
||||
*/
|
||||
public abstract IndexableField createField(T fieldInfo, Shape shape, boolean index, boolean store);
|
||||
public abstract IndexableField createField(Shape shape, boolean index, boolean store);
|
||||
|
||||
/** Corresponds with Solr's FieldType.createFields(). */
|
||||
public IndexableField[] createFields(T fieldInfo, Shape shape, boolean index, boolean store) {
|
||||
return new IndexableField[] { createField(fieldInfo, shape, index, store) };
|
||||
public IndexableField[] createFields(Shape shape, boolean index, boolean store) {
|
||||
return new IndexableField[] { createField(shape, index, store) };
|
||||
}
|
||||
|
||||
/**
|
||||
* The value source yields a number that is proportional to the distance between the query shape and indexed data.
|
||||
*/
|
||||
public abstract ValueSource makeValueSource(SpatialArgs args, T fieldInfo);
|
||||
public abstract ValueSource makeValueSource(SpatialArgs args);
|
||||
|
||||
/**
|
||||
* Make a query which has a score based on the distance from the data to the query shape.
|
||||
* The default implementation constructs a {@link FilteredQuery} based on
|
||||
* {@link #makeFilter(org.apache.lucene.spatial.query.SpatialArgs, SpatialFieldInfo)} and
|
||||
* {@link #makeValueSource(org.apache.lucene.spatial.query.SpatialArgs, SpatialFieldInfo)}.
|
||||
* {@link #makeFilter(org.apache.lucene.spatial.query.SpatialArgs)} and
|
||||
* {@link #makeValueSource(org.apache.lucene.spatial.query.SpatialArgs)}.
|
||||
*/
|
||||
public Query makeQuery(SpatialArgs args, T fieldInfo) {
|
||||
Filter filter = makeFilter(args, fieldInfo);
|
||||
ValueSource vs = makeValueSource(args, fieldInfo);
|
||||
public Query makeQuery(SpatialArgs args) {
|
||||
Filter filter = makeFilter(args);
|
||||
ValueSource vs = makeValueSource(args);
|
||||
return new FilteredQuery(new FunctionQuery(vs), filter);
|
||||
}
|
||||
/**
|
||||
* Make a Filter
|
||||
*/
|
||||
public abstract Filter makeFilter(SpatialArgs args, T fieldInfo);
|
||||
public abstract Filter makeFilter(SpatialArgs args);
|
||||
|
||||
public boolean isIgnoreIncompatibleGeometry() {
|
||||
return ignoreIncompatibleGeometry;
|
||||
|
@ -92,4 +110,9 @@ public abstract class SpatialStrategy<T extends SpatialFieldInfo> {
|
|||
public void setIgnoreIncompatibleGeometry(boolean ignoreIncompatibleGeometry) {
|
||||
this.ignoreIncompatibleGeometry = ignoreIncompatibleGeometry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()+" field:"+fieldName+" ctx="+ctx;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +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.bbox;
|
||||
|
||||
import org.apache.lucene.spatial.SpatialFieldInfo;
|
||||
|
||||
|
||||
/**
|
||||
* The Bounding Box gets stored as four fields for x/y min/max and a flag
|
||||
* that says if the box crosses the dateline (xdl).
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public class BBoxFieldInfo implements SpatialFieldInfo {
|
||||
|
||||
public static final String SUFFIX_MINX = "__minX";
|
||||
public static final String SUFFIX_MAXX = "__maxX";
|
||||
public static final String SUFFIX_MINY = "__minY";
|
||||
public static final String SUFFIX_MAXY = "__maxY";
|
||||
public static final String SUFFIX_XDL = "__xdl";
|
||||
|
||||
public String bbox = "bbox";
|
||||
public String minX = "bbox.minx";
|
||||
public String minY = "bbox.miny";
|
||||
public String maxX = "bbox.maxx";
|
||||
public String maxY = "bbox.maxy";
|
||||
public String xdl = "bbox.xdl"; // crosses dateline
|
||||
|
||||
public BBoxFieldInfo() {
|
||||
|
||||
}
|
||||
|
||||
public BBoxFieldInfo( String p ) {
|
||||
this.setFieldsPrefix( p );
|
||||
}
|
||||
|
||||
public void setFieldsPrefix(String prefix) {
|
||||
bbox = prefix;
|
||||
minX = prefix + SUFFIX_MINX;
|
||||
maxX = prefix + SUFFIX_MAXX;
|
||||
minY = prefix + SUFFIX_MINY;
|
||||
maxY = prefix + SUFFIX_MAXY;
|
||||
xdl = prefix + SUFFIX_XDL;
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.lucene.spatial.bbox;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -14,11 +16,9 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.apache.lucene.spatial.bbox;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.spatial4j.core.shape.simple.RectangleImpl;
|
||||
import org.apache.lucene.index.AtomicReader;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.queries.function.FunctionValues;
|
||||
|
@ -27,8 +27,8 @@ import org.apache.lucene.search.Explanation;
|
|||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.util.Bits;
|
||||
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.spatial4j.core.shape.simple.RectangleImpl;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An implementation of the Lucene ValueSource model to support spatial relevance ranking.
|
||||
|
@ -37,12 +37,12 @@ import com.spatial4j.core.shape.simple.RectangleImpl;
|
|||
*/
|
||||
public class BBoxSimilarityValueSource extends ValueSource {
|
||||
|
||||
private final BBoxFieldInfo field;
|
||||
private final BBoxStrategy strategy;
|
||||
private final BBoxSimilarity similarity;
|
||||
|
||||
public BBoxSimilarityValueSource(BBoxSimilarity similarity, BBoxFieldInfo field) {
|
||||
public BBoxSimilarityValueSource(BBoxStrategy strategy, BBoxSimilarity similarity) {
|
||||
this.strategy = strategy;
|
||||
this.similarity = similarity;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,13 +65,13 @@ public class BBoxSimilarityValueSource extends ValueSource {
|
|||
@Override
|
||||
public FunctionValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
|
||||
AtomicReader reader = readerContext.reader();
|
||||
final double[] minX = FieldCache.DEFAULT.getDoubles(reader, field.minX, true);
|
||||
final double[] minY = FieldCache.DEFAULT.getDoubles(reader, field.minY, true);
|
||||
final double[] maxX = FieldCache.DEFAULT.getDoubles(reader, field.maxX, true);
|
||||
final double[] maxY = FieldCache.DEFAULT.getDoubles(reader, field.maxY, true);
|
||||
final double[] minX = FieldCache.DEFAULT.getDoubles(reader, strategy.field_minX, true);
|
||||
final double[] minY = FieldCache.DEFAULT.getDoubles(reader, strategy.field_minY, true);
|
||||
final double[] maxX = FieldCache.DEFAULT.getDoubles(reader, strategy.field_maxX, true);
|
||||
final double[] maxY = FieldCache.DEFAULT.getDoubles(reader, strategy.field_maxY, true);
|
||||
|
||||
final Bits validMinX = FieldCache.DEFAULT.getDocsWithField(reader, field.minX);
|
||||
final Bits validMaxX = FieldCache.DEFAULT.getDocsWithField(reader, field.maxX);
|
||||
final Bits validMinX = FieldCache.DEFAULT.getDocsWithField(reader, strategy.field_minX);
|
||||
final Bits validMaxX = FieldCache.DEFAULT.getDocsWithField(reader, strategy.field_maxX);
|
||||
|
||||
return new FunctionValues() {
|
||||
@Override
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.lucene.spatial.bbox;
|
|||
import com.spatial4j.core.context.SpatialContext;
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import org.apache.lucene.document.DoubleField;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.FieldType;
|
||||
import org.apache.lucene.index.FieldInfo.IndexOptions;
|
||||
|
@ -27,12 +28,18 @@ import org.apache.lucene.index.IndexableField;
|
|||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queries.function.FunctionQuery;
|
||||
import org.apache.lucene.queries.function.ValueSource;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.ConstantScoreQuery;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.search.NumericRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.QueryWrapperFilter;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.spatial.SpatialStrategy;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||
import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
|
||||
import org.apache.lucene.spatial.util.NumericFieldInfo;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
|
@ -44,14 +51,43 @@ import java.util.Locale;
|
|||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
||||
public class BBoxStrategy extends SpatialStrategy {
|
||||
|
||||
public static final String SUFFIX_MINX = "__minX";
|
||||
public static final String SUFFIX_MAXX = "__maxX";
|
||||
public static final String SUFFIX_MINY = "__minY";
|
||||
public static final String SUFFIX_MAXY = "__maxY";
|
||||
public static final String SUFFIX_XDL = "__xdl";
|
||||
|
||||
/*
|
||||
* The Bounding Box gets stored as four fields for x/y min/max and a flag
|
||||
* that says if the box crosses the dateline (xdl).
|
||||
*/
|
||||
public final String field_bbox;
|
||||
public final String field_minX;
|
||||
public final String field_minY;
|
||||
public final String field_maxX;
|
||||
public final String field_maxY;
|
||||
public final String field_xdl; // crosses dateline
|
||||
|
||||
public double queryPower = 1.0;
|
||||
public double targetPower = 1.0f;
|
||||
public int precisionStep = 8; // same as solr default
|
||||
|
||||
public NumericFieldInfo finfo = null;
|
||||
public BBoxStrategy(SpatialContext ctx, String fieldNamePrefix) {
|
||||
super(ctx, fieldNamePrefix);
|
||||
field_bbox = fieldNamePrefix;
|
||||
field_minX = fieldNamePrefix + SUFFIX_MINX;
|
||||
field_maxX = fieldNamePrefix + SUFFIX_MAXX;
|
||||
field_minY = fieldNamePrefix + SUFFIX_MINY;
|
||||
field_maxY = fieldNamePrefix + SUFFIX_MAXY;
|
||||
field_xdl = fieldNamePrefix + SUFFIX_XDL;
|
||||
}
|
||||
|
||||
public BBoxStrategy(SpatialContext ctx) {
|
||||
super(ctx);
|
||||
public void setPrecisionStep( int p ) {
|
||||
precisionStep = p;
|
||||
if (precisionStep<=0 || precisionStep>=64)
|
||||
precisionStep=Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
//---------------------------------
|
||||
|
@ -59,15 +95,14 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
//---------------------------------
|
||||
|
||||
@Override
|
||||
public IndexableField[] createFields(BBoxFieldInfo fieldInfo,
|
||||
Shape shape, boolean index, boolean store) {
|
||||
public IndexableField[] createFields(Shape shape, boolean index, boolean store) {
|
||||
|
||||
Rectangle bbox = shape.getBoundingBox();
|
||||
IndexableField[] fields = new IndexableField[store?6:5];
|
||||
fields[0] = finfo.createDouble(fieldInfo.minX, bbox.getMinX());
|
||||
fields[1] = finfo.createDouble(fieldInfo.maxX, bbox.getMaxX());
|
||||
fields[2] = finfo.createDouble(fieldInfo.minY, bbox.getMinY());
|
||||
fields[3] = finfo.createDouble(fieldInfo.maxY, bbox.getMaxY());
|
||||
fields[0] = createDouble(field_minX, bbox.getMinX(), index, store);
|
||||
fields[1] = createDouble(field_maxX, bbox.getMaxX(), index, store);
|
||||
fields[2] = createDouble(field_minY, bbox.getMinY(), index, store);
|
||||
fields[3] = createDouble(field_maxY, bbox.getMaxY(), index, store);
|
||||
|
||||
FieldType ft = new FieldType();
|
||||
ft.setIndexed(index);
|
||||
|
@ -77,7 +112,7 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
ft.setIndexOptions(IndexOptions.DOCS_ONLY);
|
||||
ft.freeze();
|
||||
|
||||
Field xdl = new Field( fieldInfo.xdl, bbox.getCrossesDateLine()?"T":"F", ft );
|
||||
Field xdl = new Field( field_xdl, bbox.getCrossesDateLine()?"T":"F", ft );
|
||||
fields[4] = xdl;
|
||||
if( store ) {
|
||||
FieldType ff = new FieldType();
|
||||
|
@ -96,14 +131,25 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
nf.format( bbox.getMinY() ) + ' ' +
|
||||
nf.format( bbox.getMaxX() ) + ' ' +
|
||||
nf.format( bbox.getMaxY() ) + ' ';
|
||||
fields[5] = new Field( fieldInfo.bbox, ext, ff );
|
||||
fields[5] = new Field( field_bbox, ext, ff );
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
private IndexableField createDouble(String name, double v, boolean index, boolean store) {
|
||||
if (!store && !index)
|
||||
throw new IllegalArgumentException("field must be indexed or stored");
|
||||
|
||||
FieldType fieldType = new FieldType(DoubleField.TYPE_NOT_STORED);
|
||||
fieldType.setStored(store);
|
||||
fieldType.setIndexed(index);
|
||||
fieldType.setNumericPrecisionStep(precisionStep);
|
||||
return new DoubleField(name,v,fieldType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexableField createField(BBoxFieldInfo fieldInfo, Shape shape,
|
||||
boolean index, boolean store) {
|
||||
public IndexableField createField(Shape shape,
|
||||
boolean index, boolean store) {
|
||||
throw new UnsupportedOperationException("BBOX is poly field");
|
||||
}
|
||||
|
||||
|
@ -117,46 +163,46 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
//---------------------------------
|
||||
|
||||
@Override
|
||||
public ValueSource makeValueSource(SpatialArgs args, BBoxFieldInfo fields) {
|
||||
public ValueSource makeValueSource(SpatialArgs args) {
|
||||
return new BBoxSimilarityValueSource(
|
||||
new AreaSimilarity(args.getShape().getBoundingBox(), queryPower, targetPower), fields );
|
||||
this, new AreaSimilarity(args.getShape().getBoundingBox(), queryPower, targetPower));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Filter makeFilter(SpatialArgs args, BBoxFieldInfo fieldInfo) {
|
||||
Query spatial = makeSpatialQuery(args, fieldInfo);
|
||||
public Filter makeFilter(SpatialArgs args) {
|
||||
Query spatial = makeSpatialQuery(args);
|
||||
return new QueryWrapperFilter( spatial );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query makeQuery(SpatialArgs args, BBoxFieldInfo fieldInfo) {
|
||||
public Query makeQuery(SpatialArgs args) {
|
||||
BooleanQuery bq = new BooleanQuery();
|
||||
Query spatial = makeSpatialQuery(args, fieldInfo);
|
||||
Query spatial = makeSpatialQuery(args);
|
||||
bq.add(new ConstantScoreQuery(spatial), BooleanClause.Occur.MUST);
|
||||
|
||||
// This part does the scoring
|
||||
Query spatialRankingQuery = new FunctionQuery(makeValueSource(args, fieldInfo));
|
||||
Query spatialRankingQuery = new FunctionQuery(makeValueSource(args));
|
||||
bq.add(spatialRankingQuery, BooleanClause.Occur.MUST);
|
||||
return bq;
|
||||
}
|
||||
|
||||
|
||||
private Query makeSpatialQuery(SpatialArgs args, BBoxFieldInfo fieldInfo) {
|
||||
private Query makeSpatialQuery(SpatialArgs args) {
|
||||
Rectangle bbox = args.getShape().getBoundingBox();
|
||||
Query spatial = null;
|
||||
|
||||
// Useful for understanding Relations:
|
||||
// http://edndoc.esri.com/arcsde/9.1/general_topics/understand_spatial_relations.htm
|
||||
SpatialOperation op = args.getOperation();
|
||||
if( op == SpatialOperation.BBoxIntersects ) spatial = makeIntersects(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.BBoxWithin ) spatial = makeWithin(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.Contains ) spatial = makeContains(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.Intersects ) spatial = makeIntersects(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.IsEqualTo ) spatial = makeEquals(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.IsDisjointTo ) spatial = makeDisjoint(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.IsWithin ) spatial = makeWithin(bbox, fieldInfo);
|
||||
else if( op == SpatialOperation.Overlaps ) spatial = makeIntersects(bbox, fieldInfo);
|
||||
if( op == SpatialOperation.BBoxIntersects ) spatial = makeIntersects(bbox);
|
||||
else if( op == SpatialOperation.BBoxWithin ) spatial = makeWithin(bbox);
|
||||
else if( op == SpatialOperation.Contains ) spatial = makeContains(bbox);
|
||||
else if( op == SpatialOperation.Intersects ) spatial = makeIntersects(bbox);
|
||||
else if( op == SpatialOperation.IsEqualTo ) spatial = makeEquals(bbox);
|
||||
else if( op == SpatialOperation.IsDisjointTo ) spatial = makeDisjoint(bbox);
|
||||
else if( op == SpatialOperation.IsWithin ) spatial = makeWithin(bbox);
|
||||
else if( op == SpatialOperation.Overlaps ) spatial = makeIntersects(bbox);
|
||||
else {
|
||||
throw new UnsupportedSpatialOperation(op);
|
||||
}
|
||||
|
@ -173,15 +219,15 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
*
|
||||
* @return the spatial query
|
||||
*/
|
||||
Query makeContains(Rectangle bbox, BBoxFieldInfo fieldInfo) {
|
||||
Query makeContains(Rectangle bbox) {
|
||||
|
||||
// general case
|
||||
// docMinX <= queryExtent.getMinX() AND docMinY <= queryExtent.getMinY() AND docMaxX >= queryExtent.getMaxX() AND docMaxY >= queryExtent.getMaxY()
|
||||
|
||||
// Y conditions
|
||||
// docMinY <= queryExtent.getMinY() AND docMaxY >= queryExtent.getMaxY()
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(fieldInfo.minY, finfo.precisionStep, null, bbox.getMinY(), false, true);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(fieldInfo.maxY, finfo.precisionStep, bbox.getMaxY(), null, true, false);
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(field_minY, precisionStep, null, bbox.getMinY(), false, true);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(field_maxY, precisionStep, bbox.getMaxY(), null, true, false);
|
||||
Query yConditions = this.makeQuery(new Query[]{qMinY, qMaxY}, BooleanClause.Occur.MUST);
|
||||
|
||||
// X conditions
|
||||
|
@ -193,19 +239,19 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
// X Conditions for documents that do not cross the date line,
|
||||
// documents that contain the min X and max X of the query envelope,
|
||||
// docMinX <= queryExtent.getMinX() AND docMaxX >= queryExtent.getMaxX()
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, null, bbox.getMinX(), false, true);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, bbox.getMaxX(), null, true, false);
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, null, bbox.getMinX(), false, true);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, bbox.getMaxX(), null, true, false);
|
||||
Query qMinMax = this.makeQuery(new Query[]{qMinX, qMaxX}, BooleanClause.Occur.MUST);
|
||||
Query qNonXDL = this.makeXDL(false, qMinMax, fieldInfo);
|
||||
Query qNonXDL = this.makeXDL(false, qMinMax);
|
||||
|
||||
// X Conditions for documents that cross the date line,
|
||||
// the left portion of the document contains the min X of the query
|
||||
// OR the right portion of the document contains the max X of the query,
|
||||
// docMinXLeft <= queryExtent.getMinX() OR docMaxXRight >= queryExtent.getMaxX()
|
||||
Query qXDLLeft = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, null, bbox.getMinX(), false, true);
|
||||
Query qXDLRight = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, bbox.getMaxX(), null, true, false);
|
||||
Query qXDLLeft = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, null, bbox.getMinX(), false, true);
|
||||
Query qXDLRight = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, bbox.getMaxX(), null, true, false);
|
||||
Query qXDLLeftRight = this.makeQuery(new Query[]{qXDLLeft, qXDLRight}, BooleanClause.Occur.SHOULD);
|
||||
Query qXDL = this.makeXDL(true, qXDLLeftRight, fieldInfo);
|
||||
Query qXDL = this.makeXDL(true, qXDLLeftRight);
|
||||
|
||||
// apply the non-XDL and XDL conditions
|
||||
xConditions = this.makeQuery(new Query[]{qNonXDL, qXDL}, BooleanClause.Occur.SHOULD);
|
||||
|
@ -219,11 +265,11 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
// the left portion of the document contains the min X of the query
|
||||
// AND the right portion of the document contains the max X of the query,
|
||||
// docMinXLeft <= queryExtent.getMinX() AND docMaxXRight >= queryExtent.getMaxX()
|
||||
Query qXDLLeft = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, null, bbox.getMinX(), false, true);
|
||||
Query qXDLRight = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, bbox.getMaxX(), null, true, false);
|
||||
Query qXDLLeft = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, null, bbox.getMinX(), false, true);
|
||||
Query qXDLRight = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, bbox.getMaxX(), null, true, false);
|
||||
Query qXDLLeftRight = this.makeQuery(new Query[]{qXDLLeft, qXDLRight}, BooleanClause.Occur.MUST);
|
||||
|
||||
xConditions = this.makeXDL(true, qXDLLeftRight, fieldInfo);
|
||||
xConditions = this.makeXDL(true, qXDLLeftRight);
|
||||
}
|
||||
|
||||
// both X and Y conditions must occur
|
||||
|
@ -235,15 +281,15 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
*
|
||||
* @return the spatial query
|
||||
*/
|
||||
Query makeDisjoint(Rectangle bbox, BBoxFieldInfo fieldInfo) {
|
||||
Query makeDisjoint(Rectangle bbox) {
|
||||
|
||||
// general case
|
||||
// docMinX > queryExtent.getMaxX() OR docMaxX < queryExtent.getMinX() OR docMinY > queryExtent.getMaxY() OR docMaxY < queryExtent.getMinY()
|
||||
|
||||
// Y conditions
|
||||
// docMinY > queryExtent.getMaxY() OR docMaxY < queryExtent.getMinY()
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(fieldInfo.minY, finfo.precisionStep, bbox.getMaxY(), null, false, false);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(fieldInfo.maxY, finfo.precisionStep, null, bbox.getMinY(), false, false);
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(field_minY, precisionStep, bbox.getMaxY(), null, false, false);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(field_maxY, precisionStep, null, bbox.getMinY(), false, false);
|
||||
Query yConditions = this.makeQuery(new Query[]{qMinY, qMaxY}, BooleanClause.Occur.SHOULD);
|
||||
|
||||
// X conditions
|
||||
|
@ -254,10 +300,10 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
|
||||
// X Conditions for documents that do not cross the date line,
|
||||
// docMinX > queryExtent.getMaxX() OR docMaxX < queryExtent.getMinX()
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMaxX(), null, false, false);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, bbox.getMinX(), false, false);
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMaxX(), null, false, false);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, bbox.getMinX(), false, false);
|
||||
Query qMinMax = this.makeQuery(new Query[]{qMinX, qMaxX}, BooleanClause.Occur.SHOULD);
|
||||
Query qNonXDL = this.makeXDL(false, qMinMax, fieldInfo);
|
||||
Query qNonXDL = this.makeXDL(false, qMinMax);
|
||||
|
||||
// X Conditions for documents that cross the date line,
|
||||
// both the left and right portions of the document must be disjoint to the query
|
||||
|
@ -266,10 +312,10 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
// where: docMaxXLeft = 180.0, docMinXRight = -180.0
|
||||
// (docMaxXLeft < queryExtent.getMinX()) equates to (180.0 < queryExtent.getMinX()) and is ignored
|
||||
// (docMinXRight > queryExtent.getMaxX()) equates to (-180.0 > queryExtent.getMaxX()) and is ignored
|
||||
Query qMinXLeft = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMaxX(), null, false, false);
|
||||
Query qMaxXRight = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, bbox.getMinX(), false, false);
|
||||
Query qMinXLeft = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMaxX(), null, false, false);
|
||||
Query qMaxXRight = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, bbox.getMinX(), false, false);
|
||||
Query qLeftRight = this.makeQuery(new Query[]{qMinXLeft, qMaxXRight}, BooleanClause.Occur.MUST);
|
||||
Query qXDL = this.makeXDL(true, qLeftRight, fieldInfo);
|
||||
Query qXDL = this.makeXDL(true, qLeftRight);
|
||||
|
||||
// apply the non-XDL and XDL conditions
|
||||
xConditions = this.makeQuery(new Query[]{qNonXDL, qXDL}, BooleanClause.Occur.SHOULD);
|
||||
|
@ -281,17 +327,17 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
// the document must be disjoint to both the left and right query portions
|
||||
// (docMinX > queryExtent.getMaxX()Left OR docMaxX < queryExtent.getMinX()) AND (docMinX > queryExtent.getMaxX() OR docMaxX < queryExtent.getMinX()Left)
|
||||
// where: queryExtent.getMaxX()Left = 180.0, queryExtent.getMinX()Left = -180.0
|
||||
Query qMinXLeft = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, 180.0, null, false, false);
|
||||
Query qMaxXLeft = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, bbox.getMinX(), false, false);
|
||||
Query qMinXRight = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMaxX(), null, false, false);
|
||||
Query qMaxXRight = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, -180.0, false, false);
|
||||
Query qMinXLeft = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, 180.0, null, false, false);
|
||||
Query qMaxXLeft = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, bbox.getMinX(), false, false);
|
||||
Query qMinXRight = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMaxX(), null, false, false);
|
||||
Query qMaxXRight = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, -180.0, false, false);
|
||||
Query qLeft = this.makeQuery(new Query[]{qMinXLeft, qMaxXLeft}, BooleanClause.Occur.SHOULD);
|
||||
Query qRight = this.makeQuery(new Query[]{qMinXRight, qMaxXRight}, BooleanClause.Occur.SHOULD);
|
||||
Query qLeftRight = this.makeQuery(new Query[]{qLeft, qRight}, BooleanClause.Occur.MUST);
|
||||
|
||||
// No need to search for documents that do not cross the date line
|
||||
|
||||
xConditions = this.makeXDL(false, qLeftRight, fieldInfo);
|
||||
xConditions = this.makeXDL(false, qLeftRight);
|
||||
}
|
||||
|
||||
// either X or Y conditions should occur
|
||||
|
@ -303,13 +349,13 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
*
|
||||
* @return the spatial query
|
||||
*/
|
||||
Query makeEquals(Rectangle bbox, BBoxFieldInfo fieldInfo) {
|
||||
Query makeEquals(Rectangle bbox) {
|
||||
|
||||
// docMinX = queryExtent.getMinX() AND docMinY = queryExtent.getMinY() AND docMaxX = queryExtent.getMaxX() AND docMaxY = queryExtent.getMaxY()
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMinX(), bbox.getMinX(), true, true);
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(fieldInfo.minY, finfo.precisionStep, bbox.getMinY(), bbox.getMinY(), true, true);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, bbox.getMaxX(), bbox.getMaxX(), true, true);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(fieldInfo.maxY, finfo.precisionStep, bbox.getMaxY(), bbox.getMaxY(), true, true);
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMinX(), bbox.getMinX(), true, true);
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(field_minY, precisionStep, bbox.getMinY(), bbox.getMinY(), true, true);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, bbox.getMaxX(), bbox.getMaxX(), true, true);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(field_maxY, precisionStep, bbox.getMaxY(), bbox.getMaxY(), true, true);
|
||||
BooleanQuery bq = new BooleanQuery();
|
||||
bq.add(qMinX, BooleanClause.Occur.MUST);
|
||||
bq.add(qMinY, BooleanClause.Occur.MUST);
|
||||
|
@ -323,7 +369,7 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
*
|
||||
* @return the spatial query
|
||||
*/
|
||||
Query makeIntersects(Rectangle bbox, BBoxFieldInfo fieldInfo) {
|
||||
Query makeIntersects(Rectangle bbox) {
|
||||
|
||||
// the original intersects query does not work for envelopes that cross the date line,
|
||||
// switch to a NOT Disjoint query
|
||||
|
@ -332,9 +378,9 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
// to get round it we add all documents as a SHOULD
|
||||
|
||||
// there must be an envelope, it must not be disjoint
|
||||
Query qDisjoint = makeDisjoint(bbox, fieldInfo);
|
||||
Query qIsNonXDL = this.makeXDL(false, fieldInfo);
|
||||
Query qIsXDL = this.makeXDL(true, fieldInfo);
|
||||
Query qDisjoint = makeDisjoint(bbox);
|
||||
Query qIsNonXDL = this.makeXDL(false);
|
||||
Query qIsXDL = this.makeXDL(true);
|
||||
Query qHasEnv = this.makeQuery(new Query[]{qIsNonXDL, qIsXDL}, BooleanClause.Occur.SHOULD);
|
||||
BooleanQuery qNotDisjoint = new BooleanQuery();
|
||||
qNotDisjoint.add(qHasEnv, BooleanClause.Occur.MUST);
|
||||
|
@ -367,15 +413,15 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
*
|
||||
* @return the spatial query
|
||||
*/
|
||||
Query makeWithin(Rectangle bbox, BBoxFieldInfo fieldInfo) {
|
||||
Query makeWithin(Rectangle bbox) {
|
||||
|
||||
// general case
|
||||
// docMinX >= queryExtent.getMinX() AND docMinY >= queryExtent.getMinY() AND docMaxX <= queryExtent.getMaxX() AND docMaxY <= queryExtent.getMaxY()
|
||||
|
||||
// Y conditions
|
||||
// docMinY >= queryExtent.getMinY() AND docMaxY <= queryExtent.getMaxY()
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(fieldInfo.minY, finfo.precisionStep, bbox.getMinY(), null, true, false);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(fieldInfo.maxY, finfo.precisionStep, null, bbox.getMaxY(), false, true);
|
||||
Query qMinY = NumericRangeQuery.newDoubleRange(field_minY, precisionStep, bbox.getMinY(), null, true, false);
|
||||
Query qMaxY = NumericRangeQuery.newDoubleRange(field_maxY, precisionStep, null, bbox.getMaxY(), false, true);
|
||||
Query yConditions = this.makeQuery(new Query[]{qMinY, qMaxY}, BooleanClause.Occur.MUST);
|
||||
|
||||
// X conditions
|
||||
|
@ -386,20 +432,20 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
// AND the right portion of the document must be within the right portion of the query
|
||||
// docMinXLeft >= queryExtent.getMinX() AND docMaxXLeft <= 180.0
|
||||
// AND docMinXRight >= -180.0 AND docMaxXRight <= queryExtent.getMaxX()
|
||||
Query qXDLLeft = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMinX(), null, true, false);
|
||||
Query qXDLRight = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, bbox.getMaxX(), false, true);
|
||||
Query qXDLLeft = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMinX(), null, true, false);
|
||||
Query qXDLRight = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, bbox.getMaxX(), false, true);
|
||||
Query qXDLLeftRight = this.makeQuery(new Query[]{qXDLLeft, qXDLRight}, BooleanClause.Occur.MUST);
|
||||
Query qXDL = this.makeXDL(true, qXDLLeftRight, fieldInfo);
|
||||
Query qXDL = this.makeXDL(true, qXDLLeftRight);
|
||||
|
||||
// queries that do not cross the date line
|
||||
if (!bbox.getCrossesDateLine()) {
|
||||
|
||||
// X Conditions for documents that do not cross the date line,
|
||||
// docMinX >= queryExtent.getMinX() AND docMaxX <= queryExtent.getMaxX()
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMinX(), null, true, false);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, bbox.getMaxX(), false, true);
|
||||
Query qMinX = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMinX(), null, true, false);
|
||||
Query qMaxX = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, bbox.getMaxX(), false, true);
|
||||
Query qMinMax = this.makeQuery(new Query[]{qMinX, qMaxX}, BooleanClause.Occur.MUST);
|
||||
Query qNonXDL = this.makeXDL(false, qMinMax, fieldInfo);
|
||||
Query qNonXDL = this.makeXDL(false, qMinMax);
|
||||
|
||||
// apply the non-XDL or XDL X conditions
|
||||
if ((bbox.getMinX() <= -180.0) && bbox.getMaxX() >= 180.0) {
|
||||
|
@ -415,20 +461,20 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
|
||||
// the document should be within the left portion of the query
|
||||
// docMinX >= queryExtent.getMinX() AND docMaxX <= 180.0
|
||||
Query qMinXLeft = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, bbox.getMinX(), null, true, false);
|
||||
Query qMaxXLeft = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, 180.0, false, true);
|
||||
Query qMinXLeft = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, bbox.getMinX(), null, true, false);
|
||||
Query qMaxXLeft = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, 180.0, false, true);
|
||||
Query qLeft = this.makeQuery(new Query[]{qMinXLeft, qMaxXLeft}, BooleanClause.Occur.MUST);
|
||||
|
||||
// the document should be within the right portion of the query
|
||||
// docMinX >= -180.0 AND docMaxX <= queryExtent.getMaxX()
|
||||
Query qMinXRight = NumericRangeQuery.newDoubleRange(fieldInfo.minX, finfo.precisionStep, -180.0, null, true, false);
|
||||
Query qMaxXRight = NumericRangeQuery.newDoubleRange(fieldInfo.maxX, finfo.precisionStep, null, bbox.getMaxX(), false, true);
|
||||
Query qMinXRight = NumericRangeQuery.newDoubleRange(field_minX, precisionStep, -180.0, null, true, false);
|
||||
Query qMaxXRight = NumericRangeQuery.newDoubleRange(field_maxX, precisionStep, null, bbox.getMaxX(), false, true);
|
||||
Query qRight = this.makeQuery(new Query[]{qMinXRight, qMaxXRight}, BooleanClause.Occur.MUST);
|
||||
|
||||
// either left or right conditions should occur,
|
||||
// apply the left and right conditions to documents that do not cross the date line
|
||||
Query qLeftRight = this.makeQuery(new Query[]{qLeft, qRight}, BooleanClause.Occur.SHOULD);
|
||||
Query qNonXDL = this.makeXDL(false, qLeftRight, fieldInfo);
|
||||
Query qNonXDL = this.makeXDL(false, qLeftRight);
|
||||
|
||||
// apply the non-XDL and XDL conditions
|
||||
xConditions = this.makeQuery(new Query[]{qNonXDL, qXDL}, BooleanClause.Occur.SHOULD);
|
||||
|
@ -441,12 +487,13 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
/**
|
||||
* Constructs a query to retrieve documents that do or do not cross the date line.
|
||||
*
|
||||
*
|
||||
* @param crossedDateLine <code>true</true> for documents that cross the date line
|
||||
* @return the query
|
||||
*/
|
||||
Query makeXDL(boolean crossedDateLine, BBoxFieldInfo fieldInfo) {
|
||||
Query makeXDL(boolean crossedDateLine) {
|
||||
// The 'T' and 'F' values match solr fields
|
||||
return new TermQuery(new Term(fieldInfo.xdl, crossedDateLine ? "T" : "F"));
|
||||
return new TermQuery(new Term(field_xdl, crossedDateLine ? "T" : "F"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,9 +504,9 @@ public class BBoxStrategy extends SpatialStrategy<BBoxFieldInfo> {
|
|||
* @param query the spatial query
|
||||
* @return the query
|
||||
*/
|
||||
Query makeXDL(boolean crossedDateLine, Query query, BBoxFieldInfo fieldInfo) {
|
||||
Query makeXDL(boolean crossedDateLine, Query query) {
|
||||
BooleanQuery bq = new BooleanQuery();
|
||||
bq.add(this.makeXDL(crossedDateLine, fieldInfo), BooleanClause.Occur.MUST);
|
||||
bq.add(this.makeXDL(crossedDateLine), BooleanClause.Occur.MUST);
|
||||
bq.add(query, BooleanClause.Occur.MUST);
|
||||
return bq;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.apache.lucene.document.FieldType;
|
|||
import org.apache.lucene.document.StoredField;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.apache.lucene.queries.function.ValueSource;
|
||||
import org.apache.lucene.spatial.SimpleSpatialFieldInfo;
|
||||
import org.apache.lucene.spatial.SpatialStrategy;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
|
@ -42,14 +41,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
/**
|
||||
* @lucene.internal
|
||||
*/
|
||||
public abstract class PrefixTreeStrategy extends SpatialStrategy<SimpleSpatialFieldInfo> {
|
||||
public abstract class PrefixTreeStrategy extends SpatialStrategy {
|
||||
protected final SpatialPrefixTree grid;
|
||||
private final Map<String, PointPrefixTreeFieldCacheProvider> provider = new ConcurrentHashMap<String, PointPrefixTreeFieldCacheProvider>();
|
||||
protected int defaultFieldValuesArrayLen = 2;
|
||||
protected double distErrPct = SpatialArgs.DEFAULT_DIST_PRECISION;
|
||||
|
||||
public PrefixTreeStrategy(SpatialPrefixTree grid) {
|
||||
super(grid.getSpatialContext());
|
||||
public PrefixTreeStrategy(SpatialPrefixTree grid, String fieldName) {
|
||||
super(grid.getSpatialContext(), fieldName);
|
||||
this.grid = grid;
|
||||
}
|
||||
|
||||
|
@ -64,7 +63,7 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy<SimpleSpatialFi
|
|||
}
|
||||
|
||||
@Override
|
||||
public IndexableField createField(SimpleSpatialFieldInfo fieldInfo, Shape shape, boolean index, boolean store) {
|
||||
public IndexableField createField(Shape shape, boolean index, boolean store) {
|
||||
int detailLevel = grid.getMaxLevelForPrecision(shape,distErrPct);
|
||||
List<Node> cells = grid.getNodes(shape, detailLevel, true);//true=intermediates cells
|
||||
//If shape isn't a point, add a full-resolution center-point so that
|
||||
|
@ -79,7 +78,7 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy<SimpleSpatialFi
|
|||
//TODO is CellTokenStream supposed to be re-used somehow? see Uwe's comments:
|
||||
// http://code.google.com/p/lucene-spatial-playground/issues/detail?id=4
|
||||
|
||||
String fname = fieldInfo.getFieldName();
|
||||
String fname = getFieldName();
|
||||
if( store ) {
|
||||
//TODO figure out how to re-use original string instead of reconstituting it.
|
||||
String wkt = grid.getSpatialContext().toString(shape);
|
||||
|
@ -153,19 +152,19 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy<SimpleSpatialFi
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValueSource makeValueSource(SpatialArgs args, SimpleSpatialFieldInfo fieldInfo) {
|
||||
public ValueSource makeValueSource(SpatialArgs args) {
|
||||
DistanceCalculator calc = grid.getSpatialContext().getDistCalc();
|
||||
return makeValueSource(args, fieldInfo, calc);
|
||||
return makeValueSource(args, calc);
|
||||
}
|
||||
|
||||
public ValueSource makeValueSource(SpatialArgs args, SimpleSpatialFieldInfo fieldInfo, DistanceCalculator calc) {
|
||||
PointPrefixTreeFieldCacheProvider p = provider.get( fieldInfo.getFieldName() );
|
||||
public ValueSource makeValueSource(SpatialArgs args, DistanceCalculator calc) {
|
||||
PointPrefixTreeFieldCacheProvider p = provider.get( getFieldName() );
|
||||
if( p == null ) {
|
||||
synchronized (this) {//double checked locking idiom is okay since provider is threadsafe
|
||||
p = provider.get( fieldInfo.getFieldName() );
|
||||
p = provider.get( getFieldName() );
|
||||
if (p == null) {
|
||||
p = new PointPrefixTreeFieldCacheProvider(grid, fieldInfo.getFieldName(), defaultFieldValuesArrayLen);
|
||||
provider.put(fieldInfo.getFieldName(),p);
|
||||
p = new PointPrefixTreeFieldCacheProvider(grid, getFieldName(), defaultFieldValuesArrayLen);
|
||||
provider.put(getFieldName(),p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.apache.lucene.spatial.prefix;
|
|||
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.spatial.SimpleSpatialFieldInfo;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||
|
@ -32,14 +31,15 @@ import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
|
|||
*/
|
||||
public class RecursivePrefixTreeStrategy extends PrefixTreeStrategy {
|
||||
|
||||
private int prefixGridScanLevel;//TODO how is this customized?
|
||||
private int prefixGridScanLevel;
|
||||
|
||||
public RecursivePrefixTreeStrategy(SpatialPrefixTree grid) {
|
||||
super(grid);
|
||||
public RecursivePrefixTreeStrategy(SpatialPrefixTree grid, String fieldName) {
|
||||
super(grid, fieldName);
|
||||
prefixGridScanLevel = grid.getMaxLevels() - 4;//TODO this default constant is dependent on the prefix grid size
|
||||
}
|
||||
|
||||
public void setPrefixGridScanLevel(int prefixGridScanLevel) {
|
||||
//TODO if negative then subtract from maxlevels
|
||||
this.prefixGridScanLevel = prefixGridScanLevel;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class RecursivePrefixTreeStrategy extends PrefixTreeStrategy {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Filter makeFilter(SpatialArgs args, SimpleSpatialFieldInfo fieldInfo) {
|
||||
public Filter makeFilter(SpatialArgs args) {
|
||||
final SpatialOperation op = args.getOperation();
|
||||
if (! SpatialOperation.is(op, SpatialOperation.IsWithin, SpatialOperation.Intersects, SpatialOperation.BBoxWithin, SpatialOperation.BBoxIntersects))
|
||||
throw new UnsupportedSpatialOperation(op);
|
||||
|
@ -59,7 +59,7 @@ public class RecursivePrefixTreeStrategy extends PrefixTreeStrategy {
|
|||
int detailLevel = grid.getMaxLevelForPrecision(shape,args.getDistPrecision());
|
||||
|
||||
return new RecursivePrefixTreeFilter(
|
||||
fieldInfo.getFieldName(), grid,shape, prefixGridScanLevel, detailLevel);
|
||||
getFieldName(), grid,shape, prefixGridScanLevel, detailLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import com.spatial4j.core.shape.Shape;
|
|||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.queries.TermsFilter;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.spatial.SimpleSpatialFieldInfo;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
|
@ -38,12 +37,12 @@ import java.util.List;
|
|||
*/
|
||||
public class TermQueryPrefixTreeStrategy extends PrefixTreeStrategy {
|
||||
|
||||
public TermQueryPrefixTreeStrategy(SpatialPrefixTree grid) {
|
||||
super(grid);
|
||||
public TermQueryPrefixTreeStrategy(SpatialPrefixTree grid, String fieldName) {
|
||||
super(grid, fieldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter makeFilter(SpatialArgs args, SimpleSpatialFieldInfo fieldInfo) {
|
||||
public Filter makeFilter(SpatialArgs args) {
|
||||
final SpatialOperation op = args.getOperation();
|
||||
if (! SpatialOperation.is(op, SpatialOperation.IsWithin, SpatialOperation.Intersects, SpatialOperation.BBoxWithin, SpatialOperation.BBoxIntersects))
|
||||
throw new UnsupportedSpatialOperation(op);
|
||||
|
@ -53,7 +52,7 @@ public class TermQueryPrefixTreeStrategy extends PrefixTreeStrategy {
|
|||
List<Node> cells = grid.getNodes(shape, detailLevel, false);
|
||||
TermsFilter filter = new TermsFilter();
|
||||
for (Node cell : cells) {
|
||||
filter.addTerm(new Term(fieldInfo.getFieldName(), cell.getTokenString()));
|
||||
filter.addTerm(new Term(getFieldName(), cell.getTokenString()));
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.apache.lucene.index.AtomicReaderContext;
|
|||
import org.apache.lucene.queries.function.FunctionValues;
|
||||
import org.apache.lucene.queries.function.ValueSource;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.FieldCache.DoubleParser;
|
||||
import org.apache.lucene.util.Bits;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -37,19 +36,17 @@ import java.util.Map;
|
|||
*/
|
||||
public class DistanceValueSource extends ValueSource {
|
||||
|
||||
private final TwoDoublesFieldInfo fields;
|
||||
private final DistanceCalculator calculator;
|
||||
private TwoDoublesStrategy strategy;
|
||||
private final Point from;
|
||||
private final DoubleParser parser;
|
||||
private final DistanceCalculator calculator;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public DistanceValueSource(Point from, DistanceCalculator calc, TwoDoublesFieldInfo fields, DoubleParser parser) {
|
||||
public DistanceValueSource(TwoDoublesStrategy strategy, Point from, DistanceCalculator calc) {
|
||||
this.strategy = strategy;
|
||||
this.from = from;
|
||||
this.fields = fields;
|
||||
this.calculator = calc;
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,10 +65,10 @@ public class DistanceValueSource extends ValueSource {
|
|||
public FunctionValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
|
||||
AtomicReader reader = readerContext.reader();
|
||||
|
||||
final double[] ptX = FieldCache.DEFAULT.getDoubles(reader, fields.getFieldNameX(), true);
|
||||
final double[] ptY = FieldCache.DEFAULT.getDoubles(reader, fields.getFieldNameY(), true);
|
||||
final Bits validX = FieldCache.DEFAULT.getDocsWithField(reader, fields.getFieldNameX());
|
||||
final Bits validY = FieldCache.DEFAULT.getDocsWithField(reader, fields.getFieldNameY());
|
||||
final double[] ptX = FieldCache.DEFAULT.getDoubles(reader, strategy.getFieldNameX(), true);
|
||||
final double[] ptY = FieldCache.DEFAULT.getDoubles(reader, strategy.getFieldNameY(), true);
|
||||
final Bits validX = FieldCache.DEFAULT.getDocsWithField(reader, strategy.getFieldNameX());
|
||||
final Bits validY = FieldCache.DEFAULT.getDocsWithField(reader, strategy.getFieldNameY());
|
||||
|
||||
return new FunctionValues() {
|
||||
@Override
|
||||
|
@ -108,7 +105,7 @@ public class DistanceValueSource extends ValueSource {
|
|||
DistanceValueSource that = (DistanceValueSource) o;
|
||||
|
||||
if (calculator != null ? !calculator.equals(that.calculator) : that.calculator != null) return false;
|
||||
if (fields != null ? !fields.equals(that.fields) : that.fields != null) return false;
|
||||
if (strategy != null ? !strategy.equals(that.strategy) : that.strategy != null) return false;
|
||||
if (from != null ? !from.equals(that.from) : that.from != null) return false;
|
||||
|
||||
return true;
|
||||
|
@ -116,7 +113,7 @@ public class DistanceValueSource extends ValueSource {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = fields != null ? fields.hashCode() : 0;
|
||||
int result = strategy != null ? strategy.hashCode() : 0;
|
||||
result = 31 * result + (calculator != null ? calculator.hashCode() : 0);
|
||||
result = 31 * result + (from != null ? from.hashCode() : 0);
|
||||
return result;
|
||||
|
|
|
@ -1,51 +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.vector;
|
||||
|
||||
import org.apache.lucene.spatial.SpatialFieldInfo;
|
||||
|
||||
/**
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public class TwoDoublesFieldInfo implements SpatialFieldInfo {
|
||||
|
||||
public static final String SUFFIX_X = "__x";
|
||||
public static final String SUFFIX_Y = "__y";
|
||||
|
||||
private final String fieldName;
|
||||
private final String fieldNameX;
|
||||
private final String fieldNameY;
|
||||
|
||||
public TwoDoublesFieldInfo(String fieldNamePrefix) {
|
||||
fieldName = fieldNamePrefix;
|
||||
fieldNameX = fieldNamePrefix + SUFFIX_X;
|
||||
fieldNameY = fieldNamePrefix + SUFFIX_Y;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
public String getFieldNameX() {
|
||||
return fieldNameX;
|
||||
}
|
||||
|
||||
public String getFieldNameY() {
|
||||
return fieldNameY;
|
||||
}
|
||||
}
|
|
@ -23,33 +23,58 @@ import com.spatial4j.core.shape.Circle;
|
|||
import com.spatial4j.core.shape.Point;
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
import com.spatial4j.core.shape.Shape;
|
||||
import org.apache.lucene.document.DoubleField;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.FieldType;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.apache.lucene.queries.function.FunctionQuery;
|
||||
import org.apache.lucene.queries.function.ValueSource;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.search.FieldCache.DoubleParser;
|
||||
import org.apache.lucene.search.BooleanClause;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.search.FilteredQuery;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.NumericRangeQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.QueryWrapperFilter;
|
||||
import org.apache.lucene.spatial.SpatialStrategy;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||
import org.apache.lucene.spatial.query.UnsupportedSpatialOperation;
|
||||
import org.apache.lucene.spatial.util.CachingDoubleValueSource;
|
||||
import org.apache.lucene.spatial.util.NumericFieldInfo;
|
||||
import org.apache.lucene.spatial.util.ValueSourceFilter;
|
||||
|
||||
/**
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
||||
public class TwoDoublesStrategy extends SpatialStrategy {
|
||||
|
||||
private final NumericFieldInfo finfo;
|
||||
private final DoubleParser parser;
|
||||
public static final String SUFFIX_X = "__x";
|
||||
public static final String SUFFIX_Y = "__y";
|
||||
|
||||
public TwoDoublesStrategy(SpatialContext ctx, NumericFieldInfo finfo, DoubleParser parser) {
|
||||
super(ctx);
|
||||
this.finfo = finfo;
|
||||
this.parser = parser;
|
||||
private final String fieldNameX;
|
||||
private final String fieldNameY;
|
||||
|
||||
public int precisionStep = 8; // same as solr default
|
||||
|
||||
public TwoDoublesStrategy(SpatialContext ctx, String fieldNamePrefix) {
|
||||
super(ctx, fieldNamePrefix);
|
||||
this.fieldNameX = fieldNamePrefix+SUFFIX_X;
|
||||
this.fieldNameY = fieldNamePrefix+SUFFIX_Y;
|
||||
}
|
||||
|
||||
public void setPrecisionStep( int p ) {
|
||||
precisionStep = p;
|
||||
if (precisionStep<=0 || precisionStep>=64)
|
||||
precisionStep=Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
String getFieldNameX() {
|
||||
return fieldNameX;
|
||||
}
|
||||
|
||||
String getFieldNameY() {
|
||||
return fieldNameY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,20 +83,19 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IndexableField[] createFields(TwoDoublesFieldInfo fieldInfo,
|
||||
Shape shape, boolean index, boolean store) {
|
||||
public IndexableField[] createFields(Shape shape, boolean index, boolean store) {
|
||||
if( shape instanceof Point ) {
|
||||
Point point = (Point)shape;
|
||||
|
||||
IndexableField[] f = new IndexableField[(index ? 2 : 0) + (store ? 1 : 0)];
|
||||
if (index) {
|
||||
f[0] = finfo.createDouble( fieldInfo.getFieldNameX(), point.getX() );
|
||||
f[1] = finfo.createDouble( fieldInfo.getFieldNameY(), point.getY() );
|
||||
f[0] = createDouble(fieldNameX, point.getX(), index, store);
|
||||
f[1] = createDouble(fieldNameY, point.getY(), index, store);
|
||||
}
|
||||
if(store) {
|
||||
FieldType customType = new FieldType();
|
||||
customType.setStored(true);
|
||||
f[f.length-1] = new Field( fieldInfo.getFieldName(), ctx.toString( shape ), customType );
|
||||
f[f.length-1] = new Field( getFieldName(), ctx.toString( shape ), customType );
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
@ -81,39 +105,50 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
return new IndexableField[0]; // nothing (solr does not support null)
|
||||
}
|
||||
|
||||
private IndexableField createDouble(String name, double v, boolean index, boolean store) {
|
||||
if (!store && !index)
|
||||
throw new IllegalArgumentException("field must be indexed or stored");
|
||||
|
||||
FieldType fieldType = new FieldType(DoubleField.TYPE_NOT_STORED);
|
||||
fieldType.setStored(store);
|
||||
fieldType.setIndexed(index);
|
||||
fieldType.setNumericPrecisionStep(precisionStep);
|
||||
return new DoubleField(name,v,fieldType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexableField createField(TwoDoublesFieldInfo indexInfo, Shape shape,
|
||||
boolean index, boolean store) {
|
||||
public IndexableField createField(Shape shape,
|
||||
boolean index, boolean store) {
|
||||
throw new UnsupportedOperationException("Point is poly field");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSource makeValueSource(SpatialArgs args, TwoDoublesFieldInfo fieldInfo) {
|
||||
public ValueSource makeValueSource(SpatialArgs args) {
|
||||
Point p = args.getShape().getCenter();
|
||||
return new DistanceValueSource(p, ctx.getDistCalc(), fieldInfo, parser);
|
||||
return new DistanceValueSource(this, p, ctx.getDistCalc());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Filter makeFilter(SpatialArgs args, TwoDoublesFieldInfo fieldInfo) {
|
||||
public Filter makeFilter(SpatialArgs args) {
|
||||
if( args.getShape() instanceof Circle) {
|
||||
if( SpatialOperation.is( args.getOperation(),
|
||||
SpatialOperation.Intersects,
|
||||
SpatialOperation.IsWithin )) {
|
||||
Circle circle = (Circle)args.getShape();
|
||||
Query bbox = makeWithin(circle.getBoundingBox(), fieldInfo);
|
||||
Query bbox = makeWithin(circle.getBoundingBox());
|
||||
|
||||
// Make the ValueSource
|
||||
ValueSource valueSource = makeValueSource(args, fieldInfo);
|
||||
ValueSource valueSource = makeValueSource(args);
|
||||
|
||||
return new ValueSourceFilter(
|
||||
new QueryWrapperFilter( bbox ), valueSource, 0, circle.getDistance() );
|
||||
}
|
||||
}
|
||||
return new QueryWrapperFilter( makeQuery(args, fieldInfo) );
|
||||
return new QueryWrapperFilter( makeQuery(args) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query makeQuery(SpatialArgs args, TwoDoublesFieldInfo fieldInfo) {
|
||||
public Query makeQuery(SpatialArgs args) {
|
||||
// For starters, just limit the bbox
|
||||
Shape shape = args.getShape();
|
||||
if (!(shape instanceof Rectangle || shape instanceof Circle)) {
|
||||
|
@ -135,17 +170,17 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
if( SpatialOperation.is( op,
|
||||
SpatialOperation.BBoxWithin,
|
||||
SpatialOperation.BBoxIntersects ) ) {
|
||||
spatial = makeWithin(bbox, fieldInfo);
|
||||
spatial = makeWithin(bbox);
|
||||
}
|
||||
else if( SpatialOperation.is( op,
|
||||
SpatialOperation.Intersects,
|
||||
SpatialOperation.IsWithin ) ) {
|
||||
spatial = makeWithin(bbox, fieldInfo);
|
||||
spatial = makeWithin(bbox);
|
||||
if( args.getShape() instanceof Circle) {
|
||||
Circle circle = (Circle)args.getShape();
|
||||
|
||||
// Make the ValueSource
|
||||
valueSource = makeValueSource(args, fieldInfo);
|
||||
valueSource = makeValueSource(args);
|
||||
|
||||
ValueSourceFilter vsf = new ValueSourceFilter(
|
||||
new QueryWrapperFilter( spatial ), valueSource, 0, circle.getDistance() );
|
||||
|
@ -154,7 +189,7 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
}
|
||||
}
|
||||
else if( op == SpatialOperation.IsDisjointTo ) {
|
||||
spatial = makeDisjoint(bbox, fieldInfo);
|
||||
spatial = makeDisjoint(bbox);
|
||||
}
|
||||
|
||||
if( spatial == null ) {
|
||||
|
@ -165,7 +200,7 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
valueSource = new CachingDoubleValueSource(valueSource);
|
||||
}
|
||||
else {
|
||||
valueSource = makeValueSource(args, fieldInfo);
|
||||
valueSource = makeValueSource(args);
|
||||
}
|
||||
Query spatialRankingQuery = new FunctionQuery(valueSource);
|
||||
BooleanQuery bq = new BooleanQuery();
|
||||
|
@ -178,17 +213,17 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
* Constructs a query to retrieve documents that fully contain the input envelope.
|
||||
* @return the spatial query
|
||||
*/
|
||||
private Query makeWithin(Rectangle bbox, TwoDoublesFieldInfo fieldInfo) {
|
||||
private Query makeWithin(Rectangle bbox) {
|
||||
Query qX = NumericRangeQuery.newDoubleRange(
|
||||
fieldInfo.getFieldNameX(),
|
||||
finfo.precisionStep,
|
||||
fieldNameX,
|
||||
precisionStep,
|
||||
bbox.getMinX(),
|
||||
bbox.getMaxX(),
|
||||
true,
|
||||
true);
|
||||
Query qY = NumericRangeQuery.newDoubleRange(
|
||||
fieldInfo.getFieldNameY(),
|
||||
finfo.precisionStep,
|
||||
fieldNameY,
|
||||
precisionStep,
|
||||
bbox.getMinY(),
|
||||
bbox.getMaxY(),
|
||||
true,
|
||||
|
@ -204,17 +239,17 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
* Constructs a query to retrieve documents that fully contain the input envelope.
|
||||
* @return the spatial query
|
||||
*/
|
||||
Query makeDisjoint(Rectangle bbox, TwoDoublesFieldInfo fieldInfo) {
|
||||
Query makeDisjoint(Rectangle bbox) {
|
||||
Query qX = NumericRangeQuery.newDoubleRange(
|
||||
fieldInfo.getFieldNameX(),
|
||||
finfo.precisionStep,
|
||||
fieldNameX,
|
||||
precisionStep,
|
||||
bbox.getMinX(),
|
||||
bbox.getMaxX(),
|
||||
true,
|
||||
true);
|
||||
Query qY = NumericRangeQuery.newDoubleRange(
|
||||
fieldInfo.getFieldNameY(),
|
||||
finfo.precisionStep,
|
||||
fieldNameY,
|
||||
precisionStep,
|
||||
bbox.getMinY(),
|
||||
bbox.getMaxY(),
|
||||
true,
|
||||
|
@ -225,6 +260,7 @@ public class TwoDoublesStrategy extends SpatialStrategy<TwoDoublesFieldInfo> {
|
|||
bq.add(qY,BooleanClause.Occur.MUST_NOT);
|
||||
return bq;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -58,27 +58,25 @@ public class PortedSolr3Test extends StrategyTestCase {
|
|||
SpatialStrategy strategy;
|
||||
|
||||
grid = new GeohashPrefixTree(ctx,12);
|
||||
strategy = new RecursivePrefixTreeStrategy(grid);
|
||||
ctorArgs.add(new Object[]{"recursive_geohash",strategy});
|
||||
strategy = new RecursivePrefixTreeStrategy(grid, "recursive_geohash");
|
||||
ctorArgs.add(new Object[]{strategy});
|
||||
|
||||
grid = new QuadPrefixTree(ctx,25);
|
||||
strategy = new RecursivePrefixTreeStrategy(grid);
|
||||
ctorArgs.add(new Object[]{"recursive_quad",strategy});
|
||||
strategy = new RecursivePrefixTreeStrategy(grid, "recursive_quad");
|
||||
ctorArgs.add(new Object[]{strategy});
|
||||
|
||||
grid = new GeohashPrefixTree(ctx,12);
|
||||
strategy = new TermQueryPrefixTreeStrategy(grid);
|
||||
ctorArgs.add(new Object[]{"termquery_geohash",strategy});
|
||||
strategy = new TermQueryPrefixTreeStrategy(grid, "termquery_geohash");
|
||||
ctorArgs.add(new Object[]{strategy});
|
||||
|
||||
return ctorArgs;
|
||||
}
|
||||
|
||||
// private String fieldName;
|
||||
|
||||
public PortedSolr3Test(String fieldName, SpatialStrategy strategy) {
|
||||
ctx = strategy.getSpatialContext();
|
||||
public PortedSolr3Test(SpatialStrategy strategy) {
|
||||
this.ctx = strategy.getSpatialContext();
|
||||
this.strategy = strategy;
|
||||
// this.fieldName = fieldName;
|
||||
fieldInfo = new SimpleSpatialFieldInfo( fieldName );
|
||||
}
|
||||
|
||||
private void setupDocs() throws IOException {
|
||||
|
@ -156,7 +154,7 @@ public class PortedSolr3Test extends StrategyTestCase {
|
|||
|
||||
private void checkHitsOrdered(String spatialQ, String... ids) {
|
||||
SpatialArgs args = this.argsParser.parse(spatialQ,ctx);
|
||||
Query query = strategy.makeQuery(args, fieldInfo);
|
||||
Query query = strategy.makeQuery(args);
|
||||
SearchResults results = executeQuery(query, 100);
|
||||
String[] resultIds = new String[results.numFound];
|
||||
int i = 0;
|
||||
|
@ -177,7 +175,7 @@ public class PortedSolr3Test extends StrategyTestCase {
|
|||
private Document newDoc(String id, Shape shape) {
|
||||
Document doc = new Document();
|
||||
doc.add(new StringField("id", id, Field.Store.YES));
|
||||
for (IndexableField f : strategy.createFields(fieldInfo, shape, true, storeShape)) {
|
||||
for (IndexableField f : strategy.createFields(shape, true, storeShape)) {
|
||||
doc.add(f);
|
||||
}
|
||||
return doc;
|
||||
|
@ -199,9 +197,9 @@ public class PortedSolr3Test extends StrategyTestCase {
|
|||
//args.setDistPrecision(0.025);
|
||||
Query query;
|
||||
if (random().nextBoolean()) {
|
||||
query = strategy.makeQuery(args, fieldInfo);
|
||||
query = strategy.makeQuery(args);
|
||||
} else {
|
||||
query = new FilteredQuery(new MatchAllDocsQuery(),strategy.makeFilter(args, fieldInfo));
|
||||
query = new FilteredQuery(new MatchAllDocsQuery(),strategy.makeFilter(args));
|
||||
}
|
||||
SearchResults results = executeQuery(query, 100);
|
||||
assertEquals(""+shape,assertNumFound,results.numFound);
|
||||
|
|
|
@ -31,10 +31,15 @@ import org.junit.Assert;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public abstract class StrategyTestCase<T extends SpatialFieldInfo> extends SpatialTestCase {
|
||||
public abstract class StrategyTestCase extends SpatialTestCase {
|
||||
|
||||
public static final String DATA_SIMPLE_BBOX = "simple-bbox.txt";
|
||||
public static final String DATA_STATES_POLY = "states-poly.txt";
|
||||
|
@ -52,9 +57,8 @@ public abstract class StrategyTestCase<T extends SpatialFieldInfo> extends Spati
|
|||
|
||||
protected final SpatialArgsParser argsParser = new SpatialArgsParser();
|
||||
|
||||
protected SpatialStrategy<T> strategy;
|
||||
protected SpatialStrategy strategy;
|
||||
protected SpatialContext ctx;
|
||||
protected T fieldInfo;
|
||||
protected boolean storeShape = true;
|
||||
|
||||
protected void executeQueries(SpatialMatchConcern concern, String... testQueryFile) throws IOException {
|
||||
|
@ -80,7 +84,7 @@ public abstract class StrategyTestCase<T extends SpatialFieldInfo> extends Spati
|
|||
document.add(new StringField("id", data.id, Field.Store.YES));
|
||||
document.add(new StringField("name", data.name, Field.Store.YES));
|
||||
Shape shape = ctx.readShape(data.shape);
|
||||
for (IndexableField f : strategy.createFields(fieldInfo, shape, true, storeShape)) {
|
||||
for (IndexableField f : strategy.createFields(shape, true, storeShape)) {
|
||||
if( f != null ) { // null if incompatibleGeometry && ignore
|
||||
document.add(f);
|
||||
}
|
||||
|
@ -108,7 +112,7 @@ public abstract class StrategyTestCase<T extends SpatialFieldInfo> extends Spati
|
|||
SpatialTestQuery q = queries.next();
|
||||
|
||||
String msg = q.line; //"Query: " + q.args.toString(ctx);
|
||||
SearchResults got = executeQuery(strategy.makeQuery(q.args, fieldInfo), 100);
|
||||
SearchResults got = executeQuery(strategy.makeQuery(q.args), 100);
|
||||
if (concern.orderIsImportant) {
|
||||
Iterator<String> ids = q.ids.iterator();
|
||||
for (SearchResult r : got.results) {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.lucene.spatial.bbox;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -15,30 +17,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.lucene.spatial.bbox;
|
||||
|
||||
import com.spatial4j.core.context.simple.SimpleSpatialContext;
|
||||
import org.apache.lucene.spatial.SpatialMatchConcern;
|
||||
import org.apache.lucene.spatial.StrategyTestCase;
|
||||
import org.apache.lucene.spatial.util.NumericFieldInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestBBoxStrategy extends StrategyTestCase<BBoxFieldInfo> {
|
||||
public class TestBBoxStrategy extends StrategyTestCase {
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
this.ctx = SimpleSpatialContext.GEO_KM;
|
||||
|
||||
BBoxStrategy s = new BBoxStrategy(ctx);
|
||||
s.finfo = new NumericFieldInfo();
|
||||
|
||||
this.strategy = s;
|
||||
this.fieldInfo = new BBoxFieldInfo("bbox");
|
||||
this.strategy = new BBoxStrategy(ctx, "bbox");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.apache.lucene.document.Document;
|
|||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.StringField;
|
||||
import org.apache.lucene.index.IndexableField;
|
||||
import org.apache.lucene.spatial.SimpleSpatialFieldInfo;
|
||||
import org.apache.lucene.spatial.SpatialMatchConcern;
|
||||
import org.apache.lucene.spatial.StrategyTestCase;
|
||||
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
|
||||
|
@ -37,11 +36,15 @@ import org.apache.lucene.spatial.query.SpatialOperation;
|
|||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.lang.Math.toRadians;
|
||||
|
||||
public class TestRecursivePrefixTreeStrategy extends StrategyTestCase<SimpleSpatialFieldInfo> {
|
||||
public class TestRecursivePrefixTreeStrategy extends StrategyTestCase {
|
||||
|
||||
private int maxLength;
|
||||
|
||||
|
@ -49,9 +52,8 @@ public class TestRecursivePrefixTreeStrategy extends StrategyTestCase<SimpleSpat
|
|||
private void init(int maxLength) {
|
||||
this.maxLength = maxLength;
|
||||
this.ctx = SimpleSpatialContext.GEO_KM;
|
||||
this.strategy = new RecursivePrefixTreeStrategy(new GeohashPrefixTree(
|
||||
ctx, maxLength ));
|
||||
this.fieldInfo = new SimpleSpatialFieldInfo( getClass().getSimpleName() );
|
||||
GeohashPrefixTree grid = new GeohashPrefixTree(ctx, maxLength);
|
||||
this.strategy = new RecursivePrefixTreeStrategy(grid, getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -134,7 +136,7 @@ public class TestRecursivePrefixTreeStrategy extends StrategyTestCase<SimpleSpat
|
|||
Shape shape = ctx.makeCircle(pt,dist);
|
||||
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects,shape);
|
||||
args.setDistPrecision(0.0);
|
||||
SearchResults got = executeQuery(strategy.makeQuery(args, fieldInfo), 100);
|
||||
SearchResults got = executeQuery(strategy.makeQuery(args), 100);
|
||||
assertEquals(""+shape,assertNumFound,got.numFound);
|
||||
if (assertIds != null) {
|
||||
Set<Integer> gotIds = new HashSet<Integer>();
|
||||
|
@ -151,7 +153,7 @@ public class TestRecursivePrefixTreeStrategy extends StrategyTestCase<SimpleSpat
|
|||
private Document newDoc(String id, Shape shape) {
|
||||
Document doc = new Document();
|
||||
doc.add(new StringField("id", id, Field.Store.YES));
|
||||
for (IndexableField f : strategy.createFields(fieldInfo, shape, true, storeShape)) {
|
||||
for (IndexableField f : strategy.createFields(shape, true, storeShape)) {
|
||||
doc.add(f);
|
||||
}
|
||||
return doc;
|
||||
|
|
|
@ -24,7 +24,6 @@ import com.spatial4j.core.shape.simple.PointImpl;
|
|||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
import org.apache.lucene.document.StringField;
|
||||
import org.apache.lucene.spatial.SimpleSpatialFieldInfo;
|
||||
import org.apache.lucene.spatial.SpatialTestCase;
|
||||
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgsParser;
|
||||
|
@ -38,15 +37,14 @@ public class TestTermQueryPrefixGridStrategy extends SpatialTestCase {
|
|||
|
||||
@Test
|
||||
public void testNGramPrefixGridLosAngeles() throws IOException {
|
||||
SimpleSpatialFieldInfo fieldInfo = new SimpleSpatialFieldInfo("geo");
|
||||
SpatialContext ctx = SimpleSpatialContext.GEO_KM;
|
||||
TermQueryPrefixTreeStrategy prefixGridStrategy = new TermQueryPrefixTreeStrategy(new QuadPrefixTree(ctx));
|
||||
TermQueryPrefixTreeStrategy prefixGridStrategy = new TermQueryPrefixTreeStrategy(new QuadPrefixTree(ctx), "geo");
|
||||
|
||||
Shape point = new PointImpl(-118.243680, 34.052230);
|
||||
|
||||
Document losAngeles = new Document();
|
||||
losAngeles.add(new StringField("name", "Los Angeles", Field.Store.YES));
|
||||
losAngeles.add(prefixGridStrategy.createField(fieldInfo, point, true, true));
|
||||
losAngeles.add(prefixGridStrategy.createField(point, true, true));
|
||||
|
||||
addDocumentsAndCommit(Arrays.asList(losAngeles));
|
||||
|
||||
|
|
|
@ -23,35 +23,31 @@ import com.spatial4j.core.shape.Circle;
|
|||
import com.spatial4j.core.shape.Point;
|
||||
import com.spatial4j.core.shape.simple.CircleImpl;
|
||||
import com.spatial4j.core.shape.simple.PointImpl;
|
||||
import org.apache.lucene.search.FieldCache;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.spatial.SpatialMatchConcern;
|
||||
import org.apache.lucene.spatial.StrategyTestCase;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||
import org.apache.lucene.spatial.util.NumericFieldInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class TestTwoDoublesStrategy extends StrategyTestCase<TwoDoublesFieldInfo> {
|
||||
public class TestTwoDoublesStrategy extends StrategyTestCase {
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
this.ctx = SimpleSpatialContext.GEO_KM;
|
||||
this.strategy = new TwoDoublesStrategy(ctx,
|
||||
new NumericFieldInfo(), FieldCache.NUMERIC_UTILS_DOUBLE_PARSER);
|
||||
this.fieldInfo = new TwoDoublesFieldInfo(getClass().getSimpleName());
|
||||
this.strategy = new TwoDoublesStrategy(ctx, getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCircleShapeSupport() {
|
||||
Circle circle = new CircleImpl(new PointImpl(0, 0), 10, this.ctx);
|
||||
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, circle);
|
||||
Query query = this.strategy.makeQuery(args, this.fieldInfo);
|
||||
Query query = this.strategy.makeQuery(args);
|
||||
|
||||
assertNotNull(query);
|
||||
}
|
||||
|
@ -60,7 +56,7 @@ public class TestTwoDoublesStrategy extends StrategyTestCase<TwoDoublesFieldInfo
|
|||
public void testInvalidQueryShape() {
|
||||
Point point = new PointImpl(0, 0);
|
||||
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, point);
|
||||
this.strategy.makeQuery(args, this.fieldInfo);
|
||||
this.strategy.makeQuery(args);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue