SOLR-11731: one more decimal place (8) and we get the target/theoretical precision

This commit is contained in:
David Smiley 2018-04-13 17:05:51 -04:00
parent e2e89d1a60
commit e4eb8a870c
3 changed files with 18 additions and 15 deletions

View File

@ -165,7 +165,7 @@ Optimizations
a few segments diverge. (Ishan Chattopadhyaya, Shaun Sabo, John Gallagher) a few segments diverge. (Ishan Chattopadhyaya, Shaun Sabo, John Gallagher)
* SOLR-11731: LatLonPointSpatialField can now decode points from docValues when stored=false docValues=true, * SOLR-11731: LatLonPointSpatialField can now decode points from docValues when stored=false docValues=true,
albeit with maximum precision of 1.33cm (Karthik Ramachandran, David Smiley) albeit with maximum precision of 1.04cm (Karthik Ramachandran, David Smiley)
* SOLR-11891: DocStreamer now respects the ReturnFields when populating a SolrDocument, reducing the * SOLR-11891: DocStreamer now respects the ReturnFields when populating a SolrDocument, reducing the
number of unneccessary fields a ResponseWriter will see if documentCache is used (wei wang, hossman) number of unneccessary fields a ResponseWriter will see if documentCache is used (wei wang, hossman)

View File

@ -19,6 +19,7 @@ package org.apache.solr.schema;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects; import java.util.Objects;
import org.apache.lucene.document.Field; import org.apache.lucene.document.Field;
@ -53,7 +54,7 @@ import static java.math.RoundingMode.CEILING;
/** /**
* A spatial implementation based on Lucene's {@code LatLonPoint} and {@code LatLonDocValuesField}. The * A spatial implementation based on Lucene's {@code LatLonPoint} and {@code LatLonDocValuesField}. The
* first is based on Lucene's "Points" API, which is a BKD Index. This field type is strictly limited to * first is based on Lucene's "Points" API, which is a BKD Index. This field type is strictly limited to
* coordinates in lat/lon decimal degrees. The accuracy is about a centimeter. * coordinates in lat/lon decimal degrees. The accuracy is about a centimeter (1.042cm).
*/ */
// TODO once LLP & LLDVF are out of Lucene Sandbox, we should be able to javadoc reference them. // TODO once LLP & LLDVF are out of Lucene Sandbox, we should be able to javadoc reference them.
public class LatLonPointSpatialField extends AbstractSpatialFieldType implements SchemaAware { public class LatLonPointSpatialField extends AbstractSpatialFieldType implements SchemaAware {
@ -81,16 +82,18 @@ public class LatLonPointSpatialField extends AbstractSpatialFieldType implements
* The encoding is governed by {@code LatLonDocValuesField}. The decimal output representation is reflective * The encoding is governed by {@code LatLonDocValuesField}. The decimal output representation is reflective
* of the available precision. * of the available precision.
* @param value Non-null; stored location field data * @param value Non-null; stored location field data
* @return Non-null; "lat, lon" with 6 decimal point precision * @return Non-null; "lat, lon"
*/ */
public static String decodeDocValueToString(long value) { public static String decodeDocValueToString(long value) {
final double latDouble = GeoEncodingUtils.decodeLatitude((int) (value >> 32)); final double latDouble = GeoEncodingUtils.decodeLatitude((int) (value >> 32));
final double lonDouble = GeoEncodingUtils.decodeLongitude((int) (value & 0xFFFFFFFFL)); final double lonDouble = GeoEncodingUtils.decodeLongitude((int) (value & 0xFFFFFFFFL));
// 7 decimal places maximizes our available precision to just over a centimeter; we have a test for it. // This # decimal places maximizes our available precision to just over a centimeter; we have a test for it.
// CEILING round-trips (decode then re-encode then decode to get identical results). Others did not. It also // CEILING round-trips (decode then re-encode then decode to get identical results). Others did not. It also
// reverses the "floor" that occurs when we encode. // reverses the "floor" that occurred when we encoded.
BigDecimal latitudeDecoded = BigDecimal.valueOf(latDouble).setScale(7, CEILING); final int DECIMAL_PLACES = 8;
BigDecimal longitudeDecoded = BigDecimal.valueOf(lonDouble).setScale(7, CEILING); final RoundingMode ROUND_MODE = CEILING;
BigDecimal latitudeDecoded = BigDecimal.valueOf(latDouble).setScale(DECIMAL_PLACES, ROUND_MODE);
BigDecimal longitudeDecoded = BigDecimal.valueOf(lonDouble).setScale(DECIMAL_PLACES, ROUND_MODE);
return latitudeDecoded.stripTrailingZeros().toPlainString() + "," return latitudeDecoded.stripTrailingZeros().toPlainString() + ","
+ longitudeDecoded.stripTrailingZeros().toPlainString(); + longitudeDecoded.stripTrailingZeros().toPlainString();
// return ((float)latDouble) + "," + ((float)lonDouble); crude but not quite as accurate // return ((float)latDouble) + "," + ((float)lonDouble); crude but not quite as accurate

View File

@ -145,12 +145,12 @@ public class TestSolr4Spatial2 extends SolrTestCaseJ4 {
String ptOrig = GeoTestUtil.nextLatitude() + "," + GeoTestUtil.nextLongitude(); String ptOrig = GeoTestUtil.nextLatitude() + "," + GeoTestUtil.nextLongitude();
assertU(adoc("id", "0", fld, ptOrig)); assertU(adoc("id", "0", fld, ptOrig));
assertU(commit()); assertU(commit());
// retrieve it (probably less precision // retrieve it (probably less precision)
String ptDecoded1 = (String) client.query(params("q", "id:0")).getResults().get(0).get(fld); String ptDecoded1 = (String) client.query(params("q", "id:0")).getResults().get(0).get(fld);
// now write it back // now write it back
assertU(adoc("id", "0", fld, ptDecoded1)); assertU(adoc("id", "0", fld, ptDecoded1));
assertU(commit()); assertU(commit());
// retrieve it and hopefully the same // retrieve it; assert that it's the same as written
String ptDecoded2 = (String) client.query(params("q", "id:0")).getResults().get(0).get(fld); String ptDecoded2 = (String) client.query(params("q", "id:0")).getResults().get(0).get(fld);
assertEquals("orig:" + ptOrig, ptDecoded1, ptDecoded2); assertEquals("orig:" + ptOrig, ptDecoded1, ptDecoded2);
@ -158,13 +158,13 @@ public class TestSolr4Spatial2 extends SolrTestCaseJ4 {
final Point ptOrigObj = SpatialUtils.parsePoint(ptOrig, SpatialContext.GEO); final Point ptOrigObj = SpatialUtils.parsePoint(ptOrig, SpatialContext.GEO);
final Point ptDecodedObj = SpatialUtils.parsePoint(ptDecoded1, SpatialContext.GEO); final Point ptDecodedObj = SpatialUtils.parsePoint(ptDecoded1, SpatialContext.GEO);
double deltaCentimeters = SpatialContext.GEO.calcDistance(ptOrigObj, ptDecodedObj) * DistanceUtils.DEG_TO_KM * 1000.0 * 100.0; double deltaCentimeters = SpatialContext.GEO.calcDistance(ptOrigObj, ptDecodedObj) * DistanceUtils.DEG_TO_KM * 1000.0 * 100.0;
// //See javadocs of LatLonDocValuesField //See javadocs of LatLonDocValuesField for these constants
// final Point absErrorPt = SpatialContext.GEO.getShapeFactory().pointXY(8.381903171539307E-8, 4.190951585769653E-8); final Point absErrorPt = SpatialContext.GEO.getShapeFactory().pointXY(8.381903171539307E-8, 4.190951585769653E-8);
// double deltaCentimetersMax double deltaCentimetersMax
// = SpatialContext.GEO.calcDistance(absErrorPt, 0,0) * DistanceUtils.DEG_TO_KM * 1000.0 * 100.0; = SpatialContext.GEO.calcDistance(absErrorPt, 0,0) * DistanceUtils.DEG_TO_KM * 1000.0 * 100.0;
// // equals 1.0420371840922256 which is a bit lower than what we're able to do assertEquals(1.0420371840922256, deltaCentimetersMax, 0.0);// just so that we see it in black & white in the test
assertTrue("deltaCm too high: " + deltaCentimeters, deltaCentimeters < 1.33); assertTrue("deltaCm too high: " + deltaCentimeters, deltaCentimeters <= deltaCentimetersMax);
} }
@Test @Test