Completion Suggester: Fix CompletionFieldMapper to correctly parse weight
- Allows weight to be defined as a string representation of a positive integer closes #8090
This commit is contained in:
parent
462336c135
commit
96f1606cdc
|
@ -119,8 +119,9 @@ The following parameters are supported:
|
||||||
might not yield any results, if `input` and `output` differ strongly).
|
might not yield any results, if `input` and `output` differ strongly).
|
||||||
|
|
||||||
`weight`::
|
`weight`::
|
||||||
A positive integer, which defines a weight and allows you to
|
A positive integer or a string containing a positive integer,
|
||||||
rank your suggestions. This field is optional.
|
which defines a weight and allows you to rank your suggestions.
|
||||||
|
This field is optional.
|
||||||
|
|
||||||
NOTE: Even though you will lose most of the features of the
|
NOTE: Even though you will lose most of the features of the
|
||||||
completion suggest, you can choose to use the following shorthand form.
|
completion suggest, you can choose to use the following shorthand form.
|
||||||
|
|
|
@ -295,16 +295,24 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
|
||||||
if (Fields.CONTENT_FIELD_NAME_INPUT.equals(currentFieldName)) {
|
if (Fields.CONTENT_FIELD_NAME_INPUT.equals(currentFieldName)) {
|
||||||
inputs.add(parser.text());
|
inputs.add(parser.text());
|
||||||
}
|
}
|
||||||
|
if (Fields.CONTENT_FIELD_NAME_WEIGHT.equals(currentFieldName)) {
|
||||||
|
Number weightValue;
|
||||||
|
try {
|
||||||
|
weightValue = Long.parseLong(parser.text());
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new ElasticsearchIllegalArgumentException("Weight must be a string representing a numeric value, but was [" + parser.text() + "]");
|
||||||
|
}
|
||||||
|
weight = weightValue.longValue(); // always parse a long to make sure we don't get overflow
|
||||||
|
checkWeight(weight);
|
||||||
|
}
|
||||||
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||||
if (Fields.CONTENT_FIELD_NAME_WEIGHT.equals(currentFieldName)) {
|
if (Fields.CONTENT_FIELD_NAME_WEIGHT.equals(currentFieldName)) {
|
||||||
NumberType numberType = parser.numberType();
|
NumberType numberType = parser.numberType();
|
||||||
if (NumberType.LONG != numberType && NumberType.INT != numberType) {
|
if (NumberType.LONG != numberType && NumberType.INT != numberType) {
|
||||||
throw new ElasticsearchIllegalArgumentException("Weight must be an integer, but was [" + parser.numberValue() + "]");
|
throw new ElasticsearchIllegalArgumentException("Weight must be an integer, but was [" + parser.numberValue() + "]");
|
||||||
}
|
}
|
||||||
weight = parser.longValue(); // always parse a long to make sure we don't get the overflow value
|
weight = parser.longValue(); // always parse a long to make sure we don't get overflow
|
||||||
if (weight < 0 || weight > Integer.MAX_VALUE) {
|
checkWeight(weight);
|
||||||
throw new ElasticsearchIllegalArgumentException("Weight must be in the interval [0..2147483647], but was [" + weight + "]");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||||
if (Fields.CONTENT_FIELD_NAME_INPUT.equals(currentFieldName)) {
|
if (Fields.CONTENT_FIELD_NAME_INPUT.equals(currentFieldName)) {
|
||||||
|
@ -341,6 +349,12 @@ public class CompletionFieldMapper extends AbstractFieldMapper<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkWeight(long weight) {
|
||||||
|
if (weight < 0 || weight > Integer.MAX_VALUE) {
|
||||||
|
throw new ElasticsearchIllegalArgumentException("Weight must be in the interval [0..2147483647], but was [" + weight + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the context mapping associated with this completion field.
|
* Get the context mapping associated with this completion field.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -178,6 +178,68 @@ public class CompletionSuggestSearchTests extends ElasticsearchIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThatWeightCanBeAString() throws Exception {
|
||||||
|
createIndexAndMapping(completionMappingBuilder);
|
||||||
|
|
||||||
|
client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder()
|
||||||
|
.startObject().startObject(FIELD)
|
||||||
|
.startArray("input").value("testing").endArray()
|
||||||
|
.field("weight", "10")
|
||||||
|
.endObject().endObject()
|
||||||
|
).get();
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
SuggestResponse suggestResponse = client().prepareSuggest(INDEX).addSuggestion(
|
||||||
|
new CompletionSuggestionBuilder("testSuggestions").field(FIELD).text("test").size(10)
|
||||||
|
).execute().actionGet();
|
||||||
|
|
||||||
|
assertSuggestions(suggestResponse, "testSuggestions", "testing");
|
||||||
|
Suggest.Suggestion.Entry.Option option = suggestResponse.getSuggest().getSuggestion("testSuggestions").getEntries().get(0).getOptions().get(0);
|
||||||
|
assertThat(option, is(instanceOf(CompletionSuggestion.Entry.Option.class)));
|
||||||
|
CompletionSuggestion.Entry.Option prefixOption = (CompletionSuggestion.Entry.Option) option;
|
||||||
|
|
||||||
|
assertThat(prefixOption.getText().string(), equalTo("testing"));
|
||||||
|
assertThat((long) prefixOption.getScore(), equalTo(10l));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThatWeightMustNotBeANonNumberString() throws Exception {
|
||||||
|
createIndexAndMapping(completionMappingBuilder);
|
||||||
|
|
||||||
|
try {
|
||||||
|
client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder()
|
||||||
|
.startObject().startObject(FIELD)
|
||||||
|
.startArray("input").value("sth").endArray()
|
||||||
|
.field("weight", "thisIsNotValid")
|
||||||
|
.endObject().endObject()
|
||||||
|
).get();
|
||||||
|
fail("Indexing with a non-number representing string as weight was successful, but should not be");
|
||||||
|
} catch (MapperParsingException e) {
|
||||||
|
assertThat(ExceptionsHelper.detailedMessage(e), containsString("thisIsNotValid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThatWeightAsStringMustBeInt() throws Exception {
|
||||||
|
createIndexAndMapping(completionMappingBuilder);
|
||||||
|
|
||||||
|
String weight = String.valueOf(Long.MAX_VALUE - 4);
|
||||||
|
try {
|
||||||
|
client().prepareIndex(INDEX, TYPE, "1").setSource(jsonBuilder()
|
||||||
|
.startObject().startObject(FIELD)
|
||||||
|
.startArray("input").value("testing").endArray()
|
||||||
|
.field("weight", weight)
|
||||||
|
.endObject().endObject()
|
||||||
|
).get();
|
||||||
|
fail("Indexing with weight string representing value > Int.MAX_VALUE was successful, but should not be");
|
||||||
|
} catch (MapperParsingException e) {
|
||||||
|
assertThat(ExceptionsHelper.detailedMessage(e), containsString(weight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testThatInputCanBeAStringInsteadOfAnArray() throws Exception {
|
public void testThatInputCanBeAStringInsteadOfAnArray() throws Exception {
|
||||||
createIndexAndMapping(completionMappingBuilder);
|
createIndexAndMapping(completionMappingBuilder);
|
||||||
|
|
Loading…
Reference in New Issue