Skip to content

Reject out of range numbers for float, double and half_float #25826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Aug 9, 2017

Conversation

fred84
Copy link
Contributor

@fred84 fred84 commented Jul 21, 2017

Fix for #25534

@colings86 Please take a look.

@elasticmachine
Copy link
Collaborator

Since this is a community submitted pull request, a Jenkins build has not been kicked off automatically. Can an Elastic organization member please verify the contents of this patch and then kick off a build manually?

@fred84 fred84 changed the title 25534 reject out of range numbers Reject out of range numbers Jul 21, 2017
@fred84 fred84 changed the title Reject out of range numbers Reject out of range numbers for float, double and half_float Jul 21, 2017
Copy link
Contributor

@colings86 colings86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fred84 Thanks for the PR, I left a few small comments.

@@ -370,6 +390,13 @@ Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
}

@Override
void validateParsed(Number value) {
if (!Double.isFinite(value.doubleValue())) {
throw new IllegalArgumentException("[double] supports only finite values, but got [" + value.toString() + "]");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this message format where we show what we got as an invalid value in the error messages for the other types too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated message format.

* @throws IllegalArgumentException if value is not finite for this type
*/
void validateParsed(Number value) {
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since every numeric type should implement this method, can we have this throw an UnsupportedOperationException here so we get an error if we implement a new numeric type and forget to override this method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or just make it abstract

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made validation as a part of parse method in the same way as it did in byte/short/int/long. Thanks for suggestion, @rjernst!

final Map<String, String> outOfRangeValues = new HashMap<>();
outOfRangeValues.put("float", new BigDecimal("3.4028235E39").toString());
outOfRangeValues.put("double", new BigDecimal("1.7976931348623157E309").toString());
outOfRangeValues.put("half_float", new BigDecimal("65504.1").toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As well as these values can we add infinite and Nan values to this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are ready. Also added out of range tests for byte/short/int/long

@colings86
Copy link
Contributor

jenkins test this

@colings86
Copy link
Contributor

@fred84 the build failed but the failure doesn't seem to be related to your change. It also doesn't reproduce for me locally so I'm going to kick off another build and see if we get the error again.

@colings86
Copy link
Contributor

jenkins retest this

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the validation just be part of the parse method for each type? Then it would not have to be retrieved back out of Number.

* @throws IllegalArgumentException if value is not finite for this type
*/
void validateParsed(Number value) {
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or just make it abstract

@fred84
Copy link
Contributor Author

fred84 commented Jul 23, 2017

@colings86 I updated PR. There some code duplication left, I'm not sure where to put Triple class used in 2 test cases.

Copy link
Contributor

@colings86 colings86 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fred84 Thanks for updating the PR, I left a comment about the Triple class but I think this is getting close.

Could you also rebase your branch on the latest master and resolve the merge conflicts?

}
}

private static class Triple<K,V,M> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this being a generic class with a generic name can we call this OutOfRangeSpec, remove the generic arguments and instead use K -> String, V -> Number, M -> String. Also I think it would be ok for you to declare this class here and then reuse it in the NumberFieldTypeTests below instead of re-defining it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I only keep generic argument for value because I use both strings and numbers (BigInteger and BigDecimal) as input values.

@fred84
Copy link
Contributor Author

fred84 commented Jul 27, 2017

@colings86 PR is updated. I also found that validation for min/max values in short/integer/long works not as intended. I will provide more details a bit later).

@fred84
Copy link
Contributor Author

fred84 commented Jul 28, 2017

@colings86 I moved proposed changes for byte/short/int/long validation to separate PR: fred84#2

@colings86
Copy link
Contributor

@fred84 I'm a little confused, are you saying that fred84#2 replaces this PR? IF so, could you open that PR against this repo instead of against your fork?

@fred84
Copy link
Contributor Author

fred84 commented Aug 1, 2017

@colings86 I think we should solve half_float/float/double validation in this PR and then I will create separate PR for byte/short/int/double.

Copy link
Contributor

@jpountz jpountz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks good to me overall but I left some minor comments about the handling of half floats and boxing.

private void validateParsed(Float value) {
if (
value.isNaN() || value.isInfinite()
|| value > 65504
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably be Math.abs(value) >= 65520 rather than 65504. 65504 is indeed the maximum value but values up to 65520 excluded would be rounded to 65504

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with Math.abs, but do not understand about 65520. As I understand all finite floats greater than 65504 will be rounded to 65504 inside HalfFloatPoint.halfFloatToShortBits. Am I right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Floats that are between 65504 and 65520 will be rounded to 65504 however floats that are equal or greater than 65520 will be converted to +Infinity.

if (
value.isNaN() || value.isInfinite()
|| value > 65504
|| !Float.isFinite(HalfFloatPoint.sortableShortToHalfFloat(HalfFloatPoint.halfFloatToSortableShort(value)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those last checks are redundant. We should do only one of them.

@@ -231,22 +244,39 @@ Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
}
return fields;
}

private void validateParsed(Float value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make it take a float so that we do not have to worry about null values

@@ -162,12 +162,25 @@ public TypeParser(NumberType type) {
HALF_FLOAT("half_float", NumericType.HALF_FLOAT) {
@Override
Float parse(Object value, boolean coerce) {
return (Float) FLOAT.parse(value, false);
final Float result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's store it as a float in order to delay boxing as much as possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, I will fix in half_float, float and double.

},
FLOAT("float", NumericType.FLOAT) {
@Override
Float parse(Object value, boolean coerce) {
final Float result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's store it as a float in order to delay boxing as much as possible?

@@ -308,16 +338,26 @@ Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
}
return fields;
}

private void validateParsed(Float value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make it a float rather than Float and use Float.isFinite(value) == false below

},
DOUBLE("double", NumericType.DOUBLE) {
@Override
Double parse(Object value, boolean coerce) {
return objectToDouble(value);
Double parsed = objectToDouble(value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's store it as a double in order to delay boxing as much as possible?

@@ -379,6 +419,12 @@ Query rangeQuery(String field, Object lowerTerm, Object upperTerm,
}
return fields;
}

private void validateParsed(Double value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please make it a double rather than Double and use Double.isFinite(value) == false below

} catch (IllegalArgumentException e) {
assertThat("Incorrect error message for [" + item.type + "] with value [" + item.value + "]",
e.getMessage(), containsString(item.message));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you use expectThrows instead of try/fail/catch/assert?

Copy link
Contributor Author

@fred84 fred84 Aug 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite expectThrows is more concise and readable, I think we should keep try/fail/catch/assert because
fail("Mapper parsing exception expected for [" + item.type + "] with value [" + item.value + "]");
shows which numbertype with which value failed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fair enough


OutOfRangeSpec.of(NumberType.HALF_FLOAT, 65504.1, "[half_float] supports only finite values"),
OutOfRangeSpec.of(NumberType.FLOAT, 3.4028235E39, "[float] supports only finite values"),
OutOfRangeSpec.of(NumberType.DOUBLE, new BigDecimal("1.7976931348623157E309"), "[double] supports only finite values"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you test negative values too?

fred84 added 2 commits August 8, 2017 09:29
2) no redudant checks in half_float validation
3) tests with negative values for half_float/float/double
@fred84
Copy link
Contributor Author

fred84 commented Aug 8, 2017

@jpountz I updated PR. Please take a look.

Copy link
Contributor

@jpountz jpountz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks @fred84 !


private static Double parse(XContentParser parser, boolean coerce) throws IOException {
return parser.doubleValue(coerce);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this helper method does not look very useful

@colings86
Copy link
Contributor

jenkins please test this

@colings86 colings86 merged commit d8ff6e9 into elastic:master Aug 9, 2017
colings86 pushed a commit that referenced this pull request Aug 9, 2017
* validate half float values

* test upper bound for numeric mapper

* test for upper bound for float, double and half_float

* more tests on NaN and Infinity for NumberFieldMapper

* fix checkstyle errors

* minor renaming

* comments for disabled test

* tests for byte/short/integer/long removed and will be added in separate PR

* remove unused import

* Fix scaledfloat out of range validation message

* 1) delayed autoboxing in numbertype.parse(...)
2) no redudant checks in half_float validation
3) tests with negative values for half_float/float/double
colings86 pushed a commit that referenced this pull request Aug 9, 2017
* validate half float values

* test upper bound for numeric mapper

* test for upper bound for float, double and half_float

* more tests on NaN and Infinity for NumberFieldMapper

* fix checkstyle errors

* minor renaming

* comments for disabled test

* tests for byte/short/integer/long removed and will be added in separate PR

* remove unused import

* Fix scaledfloat out of range validation message

* 1) delayed autoboxing in numbertype.parse(...)
2) no redudant checks in half_float validation
3) tests with negative values for half_float/float/double
@colings86
Copy link
Contributor

@fred84 thanks for the PR, its now merged and backported to 6.x and 6.0.

@fred84
Copy link
Contributor Author

fred84 commented Aug 9, 2017

@colings86 @jpountz Thanks for review!

@lcawl lcawl removed the v6.1.0 label Dec 12, 2017
cbuescher pushed a commit to cbuescher/elasticsearch that referenced this pull request Jan 16, 2018
Since elastic#25826 we reject infinite values for float, double and half_float
datatypes. This change adds this restriction to the documentation for the
supported datatypes.

Closes elastic#27653
@fred84 fred84 deleted the 25534_reject_out_of_range_numbers branch January 16, 2018 11:18
cbuescher pushed a commit that referenced this pull request Jan 16, 2018
Since #25826 we reject infinite values for float, double and half_float
datatypes. This change adds this restriction to the documentation for the
supported datatypes.

Closes #27653
cbuescher pushed a commit that referenced this pull request Jan 16, 2018
Since #25826 we reject infinite values for float, double and half_float
datatypes. This change adds this restriction to the documentation for the
supported datatypes.

Closes #27653
cbuescher pushed a commit that referenced this pull request Jan 16, 2018
Since #25826 we reject infinite values for float, double and half_float
datatypes. This change adds this restriction to the documentation for the
supported datatypes.

Closes #27653
cbuescher pushed a commit that referenced this pull request Jan 16, 2018
Since #25826 we reject infinite values for float, double and half_float
datatypes. This change adds this restriction to the documentation for the
supported datatypes.

Closes #27653
@jimczi jimczi added v7.0.0-beta1 and removed v7.0.0 labels Feb 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>breaking >bug :Search Foundations/Mapping Index mappings, including merging and defining field types v6.0.0-beta2 v7.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants