mirror of https://github.com/apache/lucene.git
LUCENE-7072: always use WGS84 planet model in Geo3DPoint
This commit is contained in:
parent
6ce6c01318
commit
b79067a456
|
@ -125,6 +125,9 @@ API Changes
|
|||
* LUCENE-7064: MultiPhraseQuery is now immutable and should be constructed
|
||||
with MultiPhraseQuery.Builder. (Luc Vanlerberghe via Adrien Grand)
|
||||
|
||||
* LUCENE-7072: Geo3DPoint always uses WGS84 planet model.
|
||||
(Robert Muir, Mike McCandless)
|
||||
|
||||
Optimizations
|
||||
|
||||
* LUCENE-6891: Use prefix coding when writing points in
|
||||
|
|
|
@ -34,6 +34,11 @@ public abstract class BasePlanetObject {
|
|||
public BasePlanetObject(final PlanetModel planetModel) {
|
||||
this.planetModel = planetModel;
|
||||
}
|
||||
|
||||
/** Returns the {@link PlanetModel} provided when this shape was created. */
|
||||
public PlanetModel getPlanetModel() {
|
||||
return planetModel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
|
|
@ -36,8 +36,6 @@ import org.apache.lucene.util.RamUsageEstimator;
|
|||
* @lucene.experimental */
|
||||
public final class Geo3DPoint extends Field {
|
||||
|
||||
private final PlanetModel planetModel;
|
||||
|
||||
/** Indexing {@link FieldType}. */
|
||||
public static final FieldType TYPE = new FieldType();
|
||||
static {
|
||||
|
@ -46,16 +44,15 @@ public final class Geo3DPoint extends Field {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a new Geo3DPoint field with the specified lat, lon (in radians), given a planet model.
|
||||
* Creates a new Geo3DPoint field with the specified lat, lon (in radians).
|
||||
*
|
||||
* @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
|
||||
*/
|
||||
public Geo3DPoint(String name, PlanetModel planetModel, double lat, double lon) {
|
||||
public Geo3DPoint(String name, double lat, double lon) {
|
||||
super(name, TYPE);
|
||||
this.planetModel = planetModel;
|
||||
// Translate lat/lon to x,y,z:
|
||||
final GeoPoint point = new GeoPoint(planetModel, lat, lon);
|
||||
fillFieldsData(planetModel, point.x, point.y, point.z);
|
||||
final GeoPoint point = new GeoPoint(PlanetModel.WGS84, lat, lon);
|
||||
fillFieldsData(point.x, point.y, point.z);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,40 +60,38 @@ public final class Geo3DPoint extends Field {
|
|||
*
|
||||
* @throws IllegalArgumentException if the field name is null or lat or lon are out of bounds
|
||||
*/
|
||||
public Geo3DPoint(String name, PlanetModel planetModel, double x, double y, double z) {
|
||||
public Geo3DPoint(String name, double x, double y, double z) {
|
||||
super(name, TYPE);
|
||||
this.planetModel = planetModel;
|
||||
fillFieldsData(planetModel, x, y, z);
|
||||
fillFieldsData(x, y, z);
|
||||
}
|
||||
|
||||
private void fillFieldsData(PlanetModel planetModel, double x, double y, double z) {
|
||||
private void fillFieldsData(double x, double y, double z) {
|
||||
byte[] bytes = new byte[12];
|
||||
encodeDimension(planetModel, x, bytes, 0);
|
||||
encodeDimension(planetModel, y, bytes, Integer.BYTES);
|
||||
encodeDimension(planetModel, z, bytes, 2*Integer.BYTES);
|
||||
encodeDimension(x, bytes, 0);
|
||||
encodeDimension(y, bytes, Integer.BYTES);
|
||||
encodeDimension(z, bytes, 2*Integer.BYTES);
|
||||
fieldsData = new BytesRef(bytes);
|
||||
}
|
||||
|
||||
// public helper methods (e.g. for queries)
|
||||
|
||||
/** Encode single dimension */
|
||||
public static void encodeDimension(PlanetModel planetModel, double value, byte bytes[], int offset) {
|
||||
NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(planetModel.getMaximumMagnitude(), value), bytes, offset);
|
||||
public static void encodeDimension(double value, byte bytes[], int offset) {
|
||||
NumericUtils.intToSortableBytes(Geo3DUtil.encodeValue(PlanetModel.WGS84.getMaximumMagnitude(), value), bytes, offset);
|
||||
}
|
||||
|
||||
/** Decode single dimension */
|
||||
public static double decodeDimension(PlanetModel planetModel, byte value[], int offset) {
|
||||
return Geo3DUtil.decodeValueCenter(planetModel.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
|
||||
public static double decodeDimension(byte value[], int offset) {
|
||||
return Geo3DUtil.decodeValueCenter(PlanetModel.WGS84.getMaximumMagnitude(), NumericUtils.sortableBytesToInt(value, offset));
|
||||
}
|
||||
|
||||
/** Returns a query matching all points inside the provided shape.
|
||||
*
|
||||
* @param planetModel The {@link PlanetModel} to use, which must match what was used during indexing
|
||||
* @param field field name. must not be {@code null}.
|
||||
* @param shape Which {@link GeoShape} to match
|
||||
*/
|
||||
public static Query newShapeQuery(PlanetModel planetModel, String field, GeoShape shape) {
|
||||
return new PointInGeo3DShapeQuery(planetModel, field, shape);
|
||||
public static Query newShapeQuery(String field, GeoShape shape) {
|
||||
return new PointInGeo3DShapeQuery(field, shape);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -108,9 +103,9 @@ public final class Geo3DPoint extends Field {
|
|||
result.append(':');
|
||||
|
||||
BytesRef bytes = (BytesRef) fieldsData;
|
||||
result.append(" x=" + decodeDimension(planetModel, bytes.bytes, bytes.offset));
|
||||
result.append(" y=" + decodeDimension(planetModel, bytes.bytes, bytes.offset + Integer.BYTES));
|
||||
result.append(" z=" + decodeDimension(planetModel, bytes.bytes, bytes.offset + 2*Integer.BYTES));
|
||||
result.append(" x=" + decodeDimension(bytes.bytes, bytes.offset));
|
||||
result.append(" y=" + decodeDimension(bytes.bytes, bytes.offset + Integer.BYTES));
|
||||
result.append(" z=" + decodeDimension(bytes.bytes, bytes.offset + 2*Integer.BYTES));
|
||||
result.append('>');
|
||||
return result.toString();
|
||||
}
|
||||
|
|
|
@ -40,14 +40,19 @@ import org.apache.lucene.util.NumericUtils;
|
|||
|
||||
class PointInGeo3DShapeQuery extends Query {
|
||||
final String field;
|
||||
final PlanetModel planetModel;
|
||||
final GeoShape shape;
|
||||
|
||||
/** The lats/lons must be clockwise or counter-clockwise. */
|
||||
public PointInGeo3DShapeQuery(PlanetModel planetModel, String field, GeoShape shape) {
|
||||
public PointInGeo3DShapeQuery(String field, GeoShape shape) {
|
||||
this.field = field;
|
||||
this.planetModel = planetModel;
|
||||
this.shape = shape;
|
||||
|
||||
if (shape instanceof BasePlanetObject) {
|
||||
BasePlanetObject planetObject = (BasePlanetObject) shape;
|
||||
if (planetObject.getPlanetModel().equals(PlanetModel.WGS84) == false) {
|
||||
throw new IllegalArgumentException("this qurey requires PlanetModel.WGS84, but got: " + planetObject.getPlanetModel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,7 +93,7 @@ class PointInGeo3DShapeQuery extends Query {
|
|||
assert xyzSolid.getRelationship(shape) == GeoArea.WITHIN || xyzSolid.getRelationship(shape) == GeoArea.OVERLAPS: "expected WITHIN (1) or OVERLAPS (2) but got " + xyzSolid.getRelationship(shape) + "; shape="+shape+"; XYZSolid="+xyzSolid;
|
||||
*/
|
||||
|
||||
double planetMax = planetModel.getMaximumMagnitude();
|
||||
double planetMax = PlanetModel.WGS84.getMaximumMagnitude();
|
||||
|
||||
DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc());
|
||||
|
||||
|
@ -103,9 +108,9 @@ class PointInGeo3DShapeQuery extends Query {
|
|||
@Override
|
||||
public void visit(int docID, byte[] packedValue) {
|
||||
assert packedValue.length == 12;
|
||||
double x = Geo3DPoint.decodeDimension(planetModel, packedValue, 0);
|
||||
double y = Geo3DPoint.decodeDimension(planetModel, packedValue, Integer.BYTES);
|
||||
double z = Geo3DPoint.decodeDimension(planetModel, packedValue, 2 * Integer.BYTES);
|
||||
double x = Geo3DPoint.decodeDimension(packedValue, 0);
|
||||
double y = Geo3DPoint.decodeDimension(packedValue, Integer.BYTES);
|
||||
double z = Geo3DPoint.decodeDimension(packedValue, 2 * Integer.BYTES);
|
||||
if (shape.isWithin(x, y, z)) {
|
||||
result.add(docID);
|
||||
}
|
||||
|
@ -129,7 +134,7 @@ class PointInGeo3DShapeQuery extends Query {
|
|||
assert yMin <= yMax;
|
||||
assert zMin <= zMax;
|
||||
|
||||
GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(planetModel, xMin, xMax, yMin, yMax, zMin, zMax);
|
||||
GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, xMin, xMax, yMin, yMax, zMin, zMax);
|
||||
|
||||
switch(xyzSolid.getRelationship(shape)) {
|
||||
case GeoArea.CONTAINS:
|
||||
|
@ -165,10 +170,6 @@ class PointInGeo3DShapeQuery extends Query {
|
|||
return field;
|
||||
}
|
||||
|
||||
public PlanetModel getPlanetModel() {
|
||||
return planetModel;
|
||||
}
|
||||
|
||||
public GeoShape getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
@ -182,13 +183,12 @@ class PointInGeo3DShapeQuery extends Query {
|
|||
|
||||
PointInGeo3DShapeQuery that = (PointInGeo3DShapeQuery) o;
|
||||
|
||||
return planetModel.equals(that.planetModel) && shape.equals(that.shape);
|
||||
return shape.equals(that.shape);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + planetModel.hashCode();
|
||||
result = 31 * result + shape.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
@ -203,8 +203,6 @@ class PointInGeo3DShapeQuery extends Query {
|
|||
sb.append(this.field);
|
||||
sb.append(':');
|
||||
}
|
||||
sb.append(" PlanetModel: ");
|
||||
sb.append(planetModel);
|
||||
sb.append(" Shape: ");
|
||||
sb.append(shape);
|
||||
return sb.toString();
|
||||
|
|
|
@ -106,13 +106,12 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
iwc.setCodec(getCodec());
|
||||
IndexWriter w = new IndexWriter(dir, iwc);
|
||||
Document doc = new Document();
|
||||
doc.add(new Geo3DPoint("field", PlanetModel.WGS84, toRadians(50.7345267), toRadians(-97.5303555)));
|
||||
doc.add(new Geo3DPoint("field", toRadians(50.7345267), toRadians(-97.5303555)));
|
||||
w.addDocument(doc);
|
||||
IndexReader r = DirectoryReader.open(w);
|
||||
// We can't wrap with "exotic" readers because the query must see the BKD3DDVFormat:
|
||||
IndexSearcher s = newSearcher(r, false);
|
||||
assertEquals(1, s.search(Geo3DPoint.newShapeQuery(PlanetModel.WGS84,
|
||||
"field",
|
||||
assertEquals(1, s.search(Geo3DPoint.newShapeQuery("field",
|
||||
GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
|
||||
w.close();
|
||||
r.close();
|
||||
|
@ -640,8 +639,6 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
private static void verify(double[] lats, double[] lons) throws Exception {
|
||||
IndexWriterConfig iwc = newIndexWriterConfig();
|
||||
|
||||
PlanetModel planetModel = getPlanetModel();
|
||||
|
||||
// Else we can get O(N^2) merging:
|
||||
int mbd = iwc.getMaxBufferedDocs();
|
||||
if (mbd != -1 && mbd < lats.length/100) {
|
||||
|
@ -662,7 +659,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
doc.add(newStringField("id", ""+id, Field.Store.NO));
|
||||
doc.add(new NumericDocValuesField("id", id));
|
||||
if (Double.isNaN(lats[id]) == false) {
|
||||
doc.add(new Geo3DPoint("point", planetModel, lats[id], lons[id]));
|
||||
doc.add(new Geo3DPoint("point", lats[id], lons[id]));
|
||||
}
|
||||
w.addDocument(doc);
|
||||
if (id > 0 && random().nextInt(100) == 42) {
|
||||
|
@ -710,13 +707,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
|
||||
for (int iter=0;iter<iters && failed.get() == false;iter++) {
|
||||
|
||||
GeoShape shape = randomShape(planetModel);
|
||||
GeoShape shape = randomShape(PlanetModel.WGS84);
|
||||
|
||||
if (VERBOSE) {
|
||||
System.err.println("\n" + Thread.currentThread() + ": TEST: iter=" + iter + " shape="+shape);
|
||||
}
|
||||
|
||||
Query query = Geo3DPoint.newShapeQuery(planetModel, "point", shape);
|
||||
Query query = Geo3DPoint.newShapeQuery("point", shape);
|
||||
|
||||
if (VERBOSE) {
|
||||
System.err.println(" using query: " + query);
|
||||
|
@ -753,10 +750,10 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
if (Double.isNaN(lats[id]) == false) {
|
||||
|
||||
// Accurate point:
|
||||
GeoPoint point1 = new GeoPoint(planetModel, lats[id], lons[id]);
|
||||
GeoPoint point1 = new GeoPoint(PlanetModel.WGS84, lats[id], lons[id]);
|
||||
|
||||
// Quantized point (32 bits per dim):
|
||||
GeoPoint point2 = quantize(planetModel.getMaximumMagnitude(), point1);
|
||||
GeoPoint point2 = quantize(PlanetModel.WGS84.getMaximumMagnitude(), point1);
|
||||
|
||||
if (shape.isWithin(point1) != shape.isWithin(point2)) {
|
||||
if (VERBOSE) {
|
||||
|
@ -789,13 +786,13 @@ public class TestGeo3DPoint extends LuceneTestCase {
|
|||
}
|
||||
|
||||
public void testToString() {
|
||||
Geo3DPoint point = new Geo3DPoint("point", PlanetModel.SPHERE, toRadians(44.244272), toRadians(7.769736));
|
||||
assertEquals("Geo3DPoint <point: x=0.9242545719837093 y=0.06276412683667808 z=0.37658219569203544>", point.toString());
|
||||
Geo3DPoint point = new Geo3DPoint("point", toRadians(44.244272), toRadians(7.769736));
|
||||
assertEquals("Geo3DPoint <point: x=0.9248467864160119 y=0.06280434265368656 z=0.37682349005486243>", point.toString());
|
||||
}
|
||||
|
||||
public void testShapeQueryToString() {
|
||||
assertEquals("PointInGeo3DShapeQuery: field=point: PlanetModel: PlanetModel.SPHERE Shape: GeoStandardCircle: {planetmodel=PlanetModel.SPHERE, center=[lat=0.3861041107739683, lon=0.06780373760536706], radius=0.1(5.729577951308232)}",
|
||||
Geo3DPoint.newShapeQuery(PlanetModel.SPHERE, "point", GeoCircleFactory.makeGeoCircle(PlanetModel.SPHERE, toRadians(44.244272), toRadians(7.769736), 0.1)).toString());
|
||||
assertEquals("PointInGeo3DShapeQuery: field=point: Shape: GeoStandardCircle: {planetmodel=PlanetModel.WGS84, center=[lat=0.3861041107739683, lon=0.06780373760536706], radius=0.1(5.729577951308232)}",
|
||||
Geo3DPoint.newShapeQuery("point", GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(44.244272), toRadians(7.769736), 0.1)).toString());
|
||||
}
|
||||
|
||||
private static Directory getDirectory() {
|
||||
|
|
Loading…
Reference in New Issue