Skip to content
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

Add "did you mean" to ObjectParser #50938

Merged
merged 8 commits into from
Jan 14, 2020

Conversation

nik9000
Copy link
Member

@nik9000 nik9000 commented Jan 13, 2020

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.
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra (:Core/Infra/Core)

Copy link
Member Author

@nik9000 nik9000 left a comment

Choose a reason for hiding this comment

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

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;
Copy link
Member Author

Choose a reason for hiding this comment

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

I think passing ObjectParser here is ok because the interface is entirely private already. I could certainly be convinced otherwise though.

@@ -206,7 +206,7 @@ public void setTest(int test) {
{
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]");
Copy link
Member Author

Choose a reason for hiding this comment

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

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\]\?/
Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted some end to end test and a surprising number of things don't use ObjectParser in the server.

Copy link
Contributor

Choose a reason for hiding this comment

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

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?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, I think so!

@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.
Copy link
Member Author

Choose a reason for hiding this comment

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

This seems like a problem for a follow up PR. I don't think it'd be hard, but a little fiddly.

@nik9000
Copy link
Member Author

nik9000 commented Jan 13, 2020

@elasticmachine run elasticsearch-ci/2

@nik9000
Copy link
Member Author

nik9000 commented Jan 13, 2020

Oh boy some tests failed. I guess I shouldn't be surprised.

Copy link
Contributor

@romseygeek romseygeek left a comment

Choose a reason for hiding this comment

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

This is awesome, @nik9000!

*/
public interface ErrorOnUnknown {
/**
* The implementation of this interface that was loaded form SPI.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: s/form/from/

---
'Misspelled fields get "did you mean"':
- do:
catch: /\[1:2\] \[UpdateRequest\] unknown field \[dac\] did you mean \[doc\]\?/
Copy link
Contributor

Choose a reason for hiding this comment

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

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?

@nik9000 nik9000 merged commit 5da5f44 into elastic:master Jan 14, 2020
@nik9000
Copy link
Member Author

nik9000 commented Jan 14, 2020

Thanks @romseygeek !

nik9000 added a commit to nik9000/elasticsearch that referenced this pull request Jan 14, 2020
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.
nik9000 added a commit that referenced this pull request Jan 14, 2020
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
nik9000 added a commit to nik9000/elasticsearch that referenced this pull request Jan 14, 2020
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.
nik9000 added a commit that referenced this pull request Jan 15, 2020
Now that we've backported #50938 to 7.x it should be safe to run its
test against BWC clusters that include that branch.
nik9000 added a commit to nik9000/elasticsearch that referenced this pull request Jan 15, 2020
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
nik9000 added a commit that referenced this pull request Jan 17, 2020
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
nik9000 added a commit to nik9000/elasticsearch that referenced this pull request Jan 17, 2020
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
nik9000 added a commit that referenced this pull request Jan 17, 2020
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
SivagurunathanV pushed a commit to SivagurunathanV/elasticsearch that referenced this pull request Jan 23, 2020
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.
SivagurunathanV pushed a commit to SivagurunathanV/elasticsearch that referenced this pull request Jan 23, 2020
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.
SivagurunathanV pushed a commit to SivagurunathanV/elasticsearch that referenced this pull request Jan 23, 2020
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants