Add "did you mean" to ObjectParser#50938
Conversation
Check it out:
```
$ curl -u elastic:password -HContent-Type:application/json -XPOST localhost:9200/test/_update/foo?pretty -d'{
"dac": {}
}'
{
"error" : {
"root_cause" : [
{
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
}
],
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
},
"status" : 400
}
```
The tricky thing about implementing this is that x-content doesn't
depend on Lucene. So this works by creating an extension point for the
error message using SPI. Elasticsearch's server module provides the
"spell checking" implementation.
|
Pinging @elastic/es-core-infra (:Core/Infra/Core) |
nik9000
left a comment
There was a problem hiding this comment.
I thought about passing the "did you mean" implementation in at ObjectParser construction time. I think that'd mostly work too, but it'd require touching every place we build an ObjectParser which doesn't seem right.
This way does have a funny side effect - when the serve is on the classpath you'll get "did you mean" whether or not the request comes from a client. This doesn't seem like a huge problem though.
| void acceptUnknownField(String parserName, String field, XContentLocation location, XContentParser parser, | ||
| Value value, Context context) throws IOException; | ||
| void acceptUnknownField(ObjectParser<Value, Context> objectParser, String field, XContentLocation location, XContentParser parser, | ||
| Value value, Context context) throws IOException; |
There was a problem hiding this comment.
I think passing ObjectParser here is ok because the interface is entirely private already. I could certainly be convinced otherwise though.
| XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"not_supported_field\" : \"foo\"}"); | ||
| XContentParseException ex = expectThrows(XContentParseException.class, () -> objectParser.parse(parser, s, null)); | ||
| assertEquals(ex.getMessage(), "[1:2] [the_parser] unknown field [not_supported_field], parser not found"); | ||
| assertEquals(ex.getMessage(), "[1:2] [the_parser] unknown field [not_supported_field]"); |
There was a problem hiding this comment.
I could preserve this bit of the message, but I don't think it was really helping anything.
| --- | ||
| 'Misspelled fields get "did you mean"': | ||
| - do: | ||
| catch: /\[1:2\] \[UpdateRequest\] unknown field \[dac\] did you mean \[doc\]\?/ |
There was a problem hiding this comment.
I wanted some end to end test and a surprising number of things don't use ObjectParser in the server.
There was a problem hiding this comment.
This PR makes it even more compelling that we should migrate as much as possible away from hand-rolled parsing code - it might be worth a divide-and-rule effort like we did with the HLRC or Streamable->Writeable?
| @Override | ||
| public String errorMessage(String parserName, String unknownField, Iterable<String> candidates) { | ||
| String message = String.format(Locale.ROOT, "[%s] unknown field [%s]", parserName, unknownField); | ||
| // TODO it'd be nice to combine this with BaseRestHandler's implementation. |
There was a problem hiding this comment.
This seems like a problem for a follow up PR. I don't think it'd be hard, but a little fiddly.
|
@elasticmachine run elasticsearch-ci/2 |
|
Oh boy some tests failed. I guess I shouldn't be surprised. |
romseygeek
left a comment
There was a problem hiding this comment.
This is awesome, @nik9000!
| */ | ||
| public interface ErrorOnUnknown { | ||
| /** | ||
| * The implementation of this interface that was loaded form SPI. |
| --- | ||
| 'Misspelled fields get "did you mean"': | ||
| - do: | ||
| catch: /\[1:2\] \[UpdateRequest\] unknown field \[dac\] did you mean \[doc\]\?/ |
There was a problem hiding this comment.
This PR makes it even more compelling that we should migrate as much as possible away from hand-rolled parsing code - it might be worth a divide-and-rule effort like we did with the HLRC or Streamable->Writeable?
|
Thanks @romseygeek ! |
Check it out:
```
$ curl -u elastic:password -HContent-Type:application/json -XPOST localhost:9200/test/_update/foo?pretty -d'{
"dac": {}
}'
{
"error" : {
"root_cause" : [
{
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
}
],
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
},
"status" : 400
}
```
The tricky thing about implementing this is that x-content doesn't
depend on Lucene. So this works by creating an extension point for the
error message using SPI. Elasticsearch's server module provides the
"spell checking" implementation.
Check it out:
```
$ curl -u elastic:password -HContent-Type:application/json -XPOST localhost:9200/test/_update/foo?pretty -d'{
"dac": {}
}'
{
"error" : {
"root_cause" : [
{
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
}
],
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
},
"status" : 400
}
```
The tricky thing about implementing this is that x-content doesn't
depend on Lucene. So this works by creating an extension point for the
error message using SPI. Elasticsearch's server module provides the
"spell checking" implementation.
s
Now that we've backported elastic#50938 to 7.x it should be safe to run its test against BWC clusters that include that branch.
Now that we've backported #50938 to 7.x it should be safe to run its test against BWC clusters that include that branch.
When you declare an ObjectParser with top level named objects like we do with `significant_terms` we didn't support "did you mean". This fixes that. Relates elastic#50938
When you declare an ObjectParser with top level named objects like we do with `significant_terms` we didn't support "did you mean". This fixes that. Relates #50938
When you declare an ObjectParser with top level named objects like we do with `significant_terms` we didn't support "did you mean". This fixes that. Relates elastic#50938
Check it out:
```
$ curl -u elastic:password -HContent-Type:application/json -XPOST localhost:9200/test/_update/foo?pretty -d'{
"dac": {}
}'
{
"error" : {
"root_cause" : [
{
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
}
],
"type" : "x_content_parse_exception",
"reason" : "[2:3] [UpdateRequest] unknown field [dac] did you mean [doc]?"
},
"status" : 400
}
```
The tricky thing about implementing this is that x-content doesn't
depend on Lucene. So this works by creating an extension point for the
error message using SPI. Elasticsearch's server module provides the
"spell checking" implementation.
Now that we've backported elastic#50938 to 7.x it should be safe to run its test against BWC clusters that include that branch.
When you declare an ObjectParser with top level named objects like we do with `significant_terms` we didn't support "did you mean". This fixes that. Relates elastic#50938
Check it out:
The tricky thing about implementing this is that x-content doesn't
depend on Lucene. So this works by creating an extension point for the
error message using SPI. Elasticsearch's server module provides the
"spell checking" implementation.