6565import org .opensearch .search .lookup .SearchLookup ;
6666
6767import java .io .IOException ;
68- import java .math .BigDecimal ;
6968import java .time .ZoneId ;
7069import java .util .ArrayList ;
7170import java .util .Arrays ;
@@ -212,19 +211,23 @@ public byte[] encodePoint(Number value) {
212211 } else if (doubleValue == Double .NEGATIVE_INFINITY ) {
213212 LongPoint .encodeDimension (Long .MIN_VALUE , point , 0 );
214213 } else {
215- LongPoint .encodeDimension (scaleToLong ( doubleValue , scalingFactor ), point , 0 );
214+ LongPoint .encodeDimension (Math . round ( scale ( value ) ), point , 0 );
216215 }
217216 return point ;
218217 }
219218
219+ @ Override
220220 public byte [] encodePoint (Object value , boolean roundUp ) {
221- double doubleValue = parse ( value );
221+ long scaledValue = Math . round ( scale ( value ) );
222222 if (roundUp ) {
223- doubleValue = Math .nextUp (doubleValue );
223+ if (scaledValue < Long .MAX_VALUE ) {
224+ scaledValue = scaledValue + 1 ;
225+ }
224226 } else {
225- doubleValue = Math .nextDown (doubleValue );
227+ if (scaledValue > Long .MIN_VALUE ) {
228+ scaledValue = scaledValue - 1 ;
229+ }
226230 }
227- long scaledValue = scaleToLong (doubleValue , scalingFactor );
228231 byte [] point = new byte [Long .BYTES ];
229232 LongPoint .encodeDimension (scaledValue , point , 0 );
230233 return point ;
@@ -242,7 +245,7 @@ public String typeName() {
242245 @ Override
243246 public Query termQuery (Object value , QueryShardContext context ) {
244247 failIfNotIndexedAndNoDocValues ();
245- long scaledValue = scaleToLong ( parse (value ), scalingFactor );
248+ long scaledValue = Math . round ( scale (value ));
246249 Query query = NumberFieldMapper .NumberType .LONG .termQuery (name (), scaledValue , hasDocValues (), isSearchable ());
247250 if (boost () != 1f ) {
248251 query = new BoostQuery (query , boost ());
@@ -255,7 +258,7 @@ public Query termsQuery(List<?> values, QueryShardContext context) {
255258 failIfNotIndexedAndNoDocValues ();
256259 List <Long > scaledValues = new ArrayList <>(values .size ());
257260 for (Object value : values ) {
258- long scaledValue = scaleToLong ( parse (value ), scalingFactor );
261+ long scaledValue = Math . round ( scale (value ));
259262 scaledValues .add (scaledValue );
260263 }
261264 Query query = NumberFieldMapper .NumberType .LONG .termsQuery (
@@ -279,15 +282,15 @@ public Query rangeQuery(Object lowerTerm, Object upperTerm, boolean includeLower
279282 if (includeLower == false ) {
280283 dValue = Math .nextUp (dValue );
281284 }
282- lo = scaleToLong ( dValue , scalingFactor );
285+ lo = Math . round ( Math . ceil ( dValue ) );
283286 }
284287 Long hi = null ;
285288 if (upperTerm != null ) {
286289 double dValue = scale (upperTerm );
287290 if (includeUpper == false ) {
288291 dValue = Math .nextDown (dValue );
289292 }
290- hi = scaleToLong ( dValue , scalingFactor );
293+ hi = Math . round ( Math . floor ( dValue ) );
291294 }
292295 Query query = NumberFieldMapper .NumberType .LONG .rangeQuery (name (), lo , hi , true , true , hasDocValues (), isSearchable (), context );
293296 if (boost () != 1f ) {
@@ -327,8 +330,7 @@ protected Double parseSourceValue(Object value) {
327330 }
328331
329332 double scalingFactor = getScalingFactor ();
330- long scaledLong = scaleToLong (doubleValue , scalingFactor );
331- return scaledLong / scalingFactor ;
333+ return Math .round (doubleValue * scalingFactor ) / scalingFactor ;
332334 }
333335 };
334336 }
@@ -357,15 +359,16 @@ public DocValueFormat docValueFormat(String format, ZoneId timeZone) {
357359
358360 /**
359361 * Parses input value and multiplies it with the scaling factor.
360- * Uses the round-trip of creating a {@link BigDecimal} from the stringified {@code double}
361- * input to ensure intuitively exact floating point operations.
362- * (e.g. for a scaling factor of 100, JVM behaviour results in {@code 79.99D * 100 ==> 7998.99..} compared to
363- * {@code scale(79.99) ==> 7999})
362+ * Note: Uses direct floating-point multiplication for consistency
363+ * between indexing and querying. While this may result in
364+ * floating-point imprecision (e.g., 79.99 * 100 = 7998.999...),
365+ * the consistent behavior ensures search queries work correctly.
366+ *
364367 * @param input Input value to parse floating point num from
365368 * @return Scaled value
366369 */
367370 private double scale (Object input ) {
368- return new BigDecimal ( Double . toString ( parse (input ))). multiply ( BigDecimal . valueOf ( scalingFactor )). doubleValue () ;
371+ return parse (input ) * scalingFactor ;
369372 }
370373
371374 @ Override
@@ -480,7 +483,7 @@ protected void parseCreateField(ParseContext context) throws IOException {
480483 throw new IllegalArgumentException ("[scaled_float] only supports finite values, but got [" + doubleValue + "]" );
481484 }
482485 }
483- long scaledValue = scaleToLong (doubleValue , scalingFactor );
486+ long scaledValue = Math . round (doubleValue * scalingFactor );
484487
485488 List <Field > fields = NumberFieldMapper .NumberType .LONG .createFields (
486489 fieldType ().name (),
@@ -501,12 +504,6 @@ static Double parse(Object value) {
501504 return objectToDouble (value );
502505 }
503506
504- private static long scaleToLong (double doubleValue , double scalingFactor ) {
505- BigDecimal scaledValue = new BigDecimal (Double .toString (doubleValue )).multiply (BigDecimal .valueOf (scalingFactor ));
506- return scaledValue .setScale (0 , java .math .RoundingMode .HALF_UP ).longValueExact ();
507- }
508-
509-
510507 private static Double parse (XContentParser parser , boolean coerce ) throws IOException {
511508 return parser .doubleValue (coerce );
512509 }
0 commit comments