LUCENE-7047: improve Geo3DPoint, core XXXPoint.toString

This commit is contained in:
Mike McCandless 2016-02-24 11:13:01 -05:00
parent 77e62276f9
commit dc95d5248a
16 changed files with 132 additions and 63 deletions

View File

@ -101,8 +101,8 @@ public final class DoublePoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');
@ -133,12 +133,12 @@ public final class DoublePoint extends Field {
// public helper methods (e.g. for queries)
/** Encode single double dimension */
public static void encodeDimension(Double value, byte dest[], int offset) {
public static void encodeDimension(double value, byte dest[], int offset) {
NumericUtils.longToBytesDirect(NumericUtils.doubleToSortableLong(value), dest, offset);
}
/** Decode single double dimension */
public static Double decodeDimension(byte value[], int offset) {
public static double decodeDimension(byte value[], int offset) {
return NumericUtils.sortableLongToDouble(NumericUtils.bytesToLongDirect(value, offset));
}
@ -209,7 +209,7 @@ public final class DoublePoint extends Field {
return new PointRangeQuery(field, DoublePoint.encode(lowerValue), lowerInclusive, DoublePoint.encode(upperValue), upperInclusive) {
@Override
protected String toString(int dimension, byte[] value) {
return DoublePoint.decodeDimension(value, 0).toString();
return Double.toString(DoublePoint.decodeDimension(value, 0));
}
};
}

View File

@ -433,12 +433,15 @@ public class FieldType implements IndexableFieldType {
result.append(",numericPrecisionStep=");
result.append(numericPrecisionStep);
}
if (dimensionCount != 0) {
result.append(",pointDimensionCount=");
result.append(dimensionCount);
result.append(",pointNumBytes=");
result.append(dimensionNumBytes);
}
if (dimensionCount != 0) {
if (result.length() > 0) {
result.append(",");
}
result.append("pointDimensionCount=");
result.append(dimensionCount);
result.append(",pointNumBytes=");
result.append(dimensionNumBytes);
}
if (docValuesType != DocValuesType.NONE) {
if (result.length() > 0) {
@ -514,4 +517,5 @@ public class FieldType implements IndexableFieldType {
if (tokenized != other.tokenized) return false;
return true;
}
}

View File

@ -101,8 +101,8 @@ public final class FloatPoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');
@ -133,12 +133,12 @@ public final class FloatPoint extends Field {
// public helper methods (e.g. for queries)
/** Encode single float dimension */
public static void encodeDimension(Float value, byte dest[], int offset) {
public static void encodeDimension(float value, byte dest[], int offset) {
NumericUtils.intToBytesDirect(NumericUtils.floatToSortableInt(value), dest, offset);
}
/** Decode single float dimension */
public static Float decodeDimension(byte value[], int offset) {
public static float decodeDimension(byte value[], int offset) {
return NumericUtils.sortableIntToFloat(NumericUtils.bytesToIntDirect(value, offset));
}
@ -209,7 +209,7 @@ public final class FloatPoint extends Field {
return new PointRangeQuery(field, FloatPoint.encode(lowerValue), lowerInclusive, FloatPoint.encode(upperValue), upperInclusive) {
@Override
protected String toString(int dimension, byte[] value) {
return FloatPoint.decodeDimension(value, 0).toString();
return Float.toString(FloatPoint.decodeDimension(value, 0));
}
};
}

View File

@ -101,8 +101,8 @@ public final class IntPoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');
@ -133,12 +133,12 @@ public final class IntPoint extends Field {
// public helper methods (e.g. for queries)
/** Encode single integer dimension */
public static void encodeDimension(Integer value, byte dest[], int offset) {
public static void encodeDimension(int value, byte dest[], int offset) {
NumericUtils.intToBytes(value, dest, offset);
}
/** Decode single integer dimension */
public static Integer decodeDimension(byte value[], int offset) {
public static int decodeDimension(byte value[], int offset) {
return NumericUtils.bytesToInt(value, offset);
}
@ -209,7 +209,7 @@ public final class IntPoint extends Field {
return new PointRangeQuery(field, IntPoint.encode(lowerValue), lowerInclusive, IntPoint.encode(upperValue), upperInclusive) {
@Override
protected String toString(int dimension, byte[] value) {
return IntPoint.decodeDimension(value, 0).toString();
return Integer.toString(IntPoint.decodeDimension(value, 0));
}
};
}

View File

@ -101,8 +101,8 @@ public final class LongPoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');
@ -133,12 +133,12 @@ public final class LongPoint extends Field {
// public helper methods (e.g. for queries)
/** Encode single long dimension */
public static void encodeDimension(Long value, byte dest[], int offset) {
public static void encodeDimension(long value, byte dest[], int offset) {
NumericUtils.longToBytes(value, dest, offset);
}
/** Decode single long dimension */
public static Long decodeDimension(byte value[], int offset) {
public static long decodeDimension(byte value[], int offset) {
return NumericUtils.bytesToLong(value, offset);
}
@ -209,7 +209,7 @@ public final class LongPoint extends Field {
return new PointRangeQuery(field, LongPoint.encode(lowerValue), lowerInclusive, LongPoint.encode(upperValue), upperInclusive) {
@Override
protected String toString(int dimension, byte[] value) {
return LongPoint.decodeDimension(value, 0).toString();
return Long.toString(LongPoint.decodeDimension(value, 0));
}
};
}

View File

@ -52,7 +52,7 @@ public class TestField extends LuceneTestCase {
trySetTokenStreamValue(field);
assertEquals(6d, field.numericValue().doubleValue(), 0.0d);
assertEquals("<foo:6.0>", field.toString());
assertEquals("DoublePoint <foo:6.0>", field.toString());
}
public void testDoublePoint2D() throws Exception {
@ -76,7 +76,7 @@ public class TestField extends LuceneTestCase {
field.numericValue();
});
assertTrue(expected.getMessage().contains("cannot convert to a single numeric value"));
assertEquals("<foo:6.0,7.0>", field.toString());
assertEquals("DoublePoint <foo:6.0,7.0>", field.toString());
}
public void testLegacyDoubleField() throws Exception {
@ -158,7 +158,7 @@ public class TestField extends LuceneTestCase {
trySetTokenStreamValue(field);
assertEquals(6f, field.numericValue().floatValue(), 0.0f);
assertEquals("<foo:6.0>", field.toString());
assertEquals("FloatPoint <foo:6.0>", field.toString());
}
public void testFloatPoint2D() throws Exception {
@ -182,7 +182,7 @@ public class TestField extends LuceneTestCase {
field.numericValue();
});
assertTrue(expected.getMessage().contains("cannot convert to a single numeric value"));
assertEquals("<foo:6.0,7.0>", field.toString());
assertEquals("FloatPoint <foo:6.0,7.0>", field.toString());
}
public void testLegacyFloatField() throws Exception {
@ -226,7 +226,7 @@ public class TestField extends LuceneTestCase {
trySetTokenStreamValue(field);
assertEquals(6, field.numericValue().intValue());
assertEquals("<foo:6>", field.toString());
assertEquals("IntPoint <foo:6>", field.toString());
}
public void testIntPoint2D() throws Exception {
@ -250,7 +250,7 @@ public class TestField extends LuceneTestCase {
field.numericValue();
});
assertTrue(expected.getMessage().contains("cannot convert to a single numeric value"));
assertEquals("<foo:6,7>", field.toString());
assertEquals("IntPoint <foo:6,7>", field.toString());
}
public void testLegacyIntField() throws Exception {
@ -313,7 +313,7 @@ public class TestField extends LuceneTestCase {
trySetTokenStreamValue(field);
assertEquals(6, field.numericValue().intValue());
assertEquals("<foo:6>", field.toString());
assertEquals("LongPoint <foo:6>", field.toString());
}
public void testLongPoint2D() throws Exception {
@ -337,7 +337,7 @@ public class TestField extends LuceneTestCase {
field.numericValue();
});
assertTrue(expected.getMessage().contains("cannot convert to a single numeric value"));
assertEquals("<foo:6,7>", field.toString());
assertEquals("LongPoint <foo:6,7>", field.toString());
}
public void testLegacyLongField() throws Exception {

View File

@ -72,6 +72,12 @@ public class TestFieldType extends LuceneTestCase {
assertFalse(ft10.equals(ft));
}
public void testPointsToString() {
FieldType ft = new FieldType();
ft.setDimensions(1, Integer.BYTES);
assertEquals("pointDimensionCount=1,pointNumBytes=4", ft.toString());
}
private static Object randomValue(Class<?> clazz) {
if (clazz.isEnum()) {
return RandomPicks.randomFrom(random(), clazz.getEnumConstants());

View File

@ -101,8 +101,8 @@ public class BigIntegerPoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');

View File

@ -85,8 +85,8 @@ public class InetAddressPoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');

View File

@ -80,8 +80,8 @@ public class LatLonPoint extends Field {
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(type.toString());
result.append('<');
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
result.append(':');

View File

@ -81,7 +81,7 @@ public class TestBigIntegerPoint extends LuceneTestCase {
}
public void testToString() throws Exception {
assertEquals("<field:1>", new BigIntegerPoint("field", BigInteger.ONE).toString());
assertEquals("<field:1,-2>", new BigIntegerPoint("field", BigInteger.ONE, BigInteger.valueOf(-2)).toString());
assertEquals("BigIntegerPoint <field:1>", new BigIntegerPoint("field", BigInteger.ONE).toString());
assertEquals("BigIntegerPoint <field:1,-2>", new BigIntegerPoint("field", BigInteger.ONE, BigInteger.valueOf(-2)).toString());
}
}

View File

@ -74,9 +74,9 @@ public class TestInetAddressPoint extends LuceneTestCase {
}
public void testToString() throws Exception {
assertEquals("<field:1.2.3.4>", new InetAddressPoint("field", InetAddress.getByName("1.2.3.4")).toString());
assertEquals("<field:1.2.3.4>", new InetAddressPoint("field", InetAddress.getByName("::FFFF:1.2.3.4")).toString());
assertEquals("<field:[fdc8:57ed:f042:ad1:f66d:4ff:fe90:ce0c]>", new InetAddressPoint("field", InetAddress.getByName("fdc8:57ed:f042:0ad1:f66d:4ff:fe90:ce0c")).toString());
assertEquals("InetAddressPoint <field:1.2.3.4>", new InetAddressPoint("field", InetAddress.getByName("1.2.3.4")).toString());
assertEquals("InetAddressPoint <field:1.2.3.4>", new InetAddressPoint("field", InetAddress.getByName("::FFFF:1.2.3.4")).toString());
assertEquals("InetAddressPoint <field:[fdc8:57ed:f042:ad1:f66d:4ff:fe90:ce0c]>", new InetAddressPoint("field", InetAddress.getByName("fdc8:57ed:f042:0ad1:f66d:4ff:fe90:ce0c")).toString());
assertEquals("field:[1.2.3.4 TO 1.2.3.4]", InetAddressPoint.newExactQuery("field", InetAddress.getByName("1.2.3.4")).toString());
assertEquals("field:[0:0:0:0:0:0:0:1 TO 0:0:0:0:0:0:0:1]", InetAddressPoint.newExactQuery("field", InetAddress.getByName("::1")).toString());

View File

@ -48,7 +48,7 @@ public class TestLatLonPoint extends LuceneTestCase {
public void testToString() throws Exception {
// looks crazy due to lossiness
assertEquals("<field:18.313693958334625,-65.22744392976165>",(new LatLonPoint("field", 18.313694, -65.227444)).toString());
assertEquals("LatLonPoint <field:18.313693958334625,-65.22744392976165>",(new LatLonPoint("field", 18.313694, -65.227444)).toString());
// looks crazy due to lossiness
assertEquals("field:[17.99999997485429 TO 18.999999999068677},[-65.9999999217689 TO -64.99999998137355}", LatLonPoint.newBoxQuery("field", 18, 19, -66, -65).toString());

View File

@ -18,17 +18,26 @@ package org.apache.lucene.geo3d;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.NumericUtils;
import org.apache.lucene.util.RamUsageEstimator;
/** Add this to a document to index lat/lon or x/y/z point, indexed as a dimensional value.
* Multiple values are allowed: just add multiple Geo3DPoint to the document with the
* same field name.
/**
* Add this to a document to index lat/lon or x/y/z point, indexed as a 3D point.
* Multiple values are allowed: just add multiple Geo3DPoint to the document with the
* same field name.
* <p>
* This field defines static factory methods for creating a shape query:
* <ul>
* <li>{@link #newShapeQuery newShapeQuery()} for matching all points inside a specified shape
* </ul>
*
* @lucene.experimental */
public final class Geo3DPoint extends Field {
private final PlanetModel planetModel;
/** Indexing {@link FieldType}. */
public static final FieldType TYPE = new FieldType();
static {
@ -43,9 +52,10 @@ public final class Geo3DPoint extends Field {
*/
public Geo3DPoint(String name, PlanetModel planetModel, 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.getMaximumMagnitude(), point.x, point.y, point.z);
fillFieldsData(planetModel, point.x, point.y, point.z);
}
/**
@ -55,14 +65,53 @@ public final class Geo3DPoint extends Field {
*/
public Geo3DPoint(String name, PlanetModel planetModel, double x, double y, double z) {
super(name, TYPE);
fillFieldsData(planetModel.getMaximumMagnitude(), x, y, z);
this.planetModel = planetModel;
fillFieldsData(planetModel, x, y, z);
}
private void fillFieldsData(double planetMax, double x, double y, double z) {
private void fillFieldsData(PlanetModel planetModel, double x, double y, double z) {
byte[] bytes = new byte[12];
NumericUtils.intToBytes(Geo3DUtil.encodeValue(planetMax, x), bytes, 0);
NumericUtils.intToBytes(Geo3DUtil.encodeValue(planetMax, y), bytes, Integer.BYTES);
NumericUtils.intToBytes(Geo3DUtil.encodeValue(planetMax, z), bytes, 2 * Integer.BYTES);
encodeDimension(planetModel, x, bytes, 0);
encodeDimension(planetModel, y, bytes, Integer.BYTES);
encodeDimension(planetModel, 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.intToBytes(Geo3DUtil.encodeValue(planetModel.getMaximumMagnitude(), value), bytes, offset);
}
/** Decode single dimension */
public static double decodeDimension(PlanetModel planetModel, byte value[], int offset) {
return Geo3DUtil.decodeValueCenter(planetModel.getMaximumMagnitude(), NumericUtils.bytesToInt(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);
}
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append(getClass().getSimpleName());
result.append(" <");
result.append(name);
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('>');
return result.toString();
}
}

View File

@ -38,7 +38,7 @@ import org.apache.lucene.util.NumericUtils;
*
* @lucene.experimental */
public class PointInGeo3DShapeQuery extends Query {
class PointInGeo3DShapeQuery extends Query {
final String field;
final PlanetModel planetModel;
final GeoShape shape;
@ -105,9 +105,9 @@ public class PointInGeo3DShapeQuery extends Query {
@Override
public void visit(int docID, byte[] packedValue) {
assert packedValue.length == 12;
double x = Geo3DUtil.decodeValueCenter(planetMax, NumericUtils.bytesToInt(packedValue, 0));
double y = Geo3DUtil.decodeValueCenter(planetMax, NumericUtils.bytesToInt(packedValue, 1 * Integer.BYTES));
double z = Geo3DUtil.decodeValueCenter(planetMax, NumericUtils.bytesToInt(packedValue, 2 * Integer.BYTES));
double x = Geo3DPoint.decodeDimension(planetModel, packedValue, 0);
double y = Geo3DPoint.decodeDimension(planetModel, packedValue, Integer.BYTES);
double z = Geo3DPoint.decodeDimension(planetModel, packedValue, 2 * Integer.BYTES);
if (shape.isWithin(x, y, z)) {
result.add(docID);
hitCount[0]++;
@ -195,7 +195,7 @@ public class PointInGeo3DShapeQuery extends Query {
sb.append(this.field);
sb.append(':');
}
sb.append("PlanetModel: ");
sb.append(" PlanetModel: ");
sb.append(planetModel);
sb.append(" Shape: ");
sb.append(shape);

View File

@ -111,9 +111,9 @@ public class TestGeo3DPoint extends LuceneTestCase {
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(new PointInGeo3DShapeQuery(PlanetModel.WGS84,
"field",
GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
assertEquals(1, s.search(Geo3DPoint.newShapeQuery(PlanetModel.WGS84,
"field",
GeoCircleFactory.makeGeoCircle(PlanetModel.WGS84, toRadians(50), toRadians(-97), Math.PI/180.)), 1).totalHits);
w.close();
r.close();
dir.close();
@ -716,7 +716,7 @@ public class TestGeo3DPoint extends LuceneTestCase {
System.err.println("\n" + Thread.currentThread() + ": TEST: iter=" + iter + " shape="+shape);
}
Query query = new PointInGeo3DShapeQuery(planetModel, "point", shape);
Query query = Geo3DPoint.newShapeQuery(planetModel, "point", shape);
if (VERBOSE) {
System.err.println(" using query: " + query);
@ -788,6 +788,16 @@ public class TestGeo3DPoint extends LuceneTestCase {
IOUtils.close(r, dir);
}
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());
}
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());
}
private static Directory getDirectory() {
return newDirectory();
}