Skip to content

Conversation

@javanna
Copy link
Member

@javanna javanna commented Jun 18, 2021

DocumentParser takes care of parsing documents and applying dynamic mapping updates for each new field it encounters, if applicable, as well as applying the matching dynamic templates.

To do this, it needs to be able to parse mappings, which requires a ParserContext that the ParseContext exposes given a DateFormatter. So far, we have carried around a function that allows to create a new ParserContext given a date formatter, and then call a specific method that allows to wrap it to provide a special parser context that is specific for dynamic templates, which is needed to make some decisions down the line based on whether mappings come from dynamic templates or not.

This commit tries to simplify this by exposing the specific dynamic template parser context only to the document parse context, as that's all it needs. We recently ended up using the wrong context and with this change it would not be possible.

Relates to #74177

DocumentParser takes care of parsing documents and applying dynamic mapping updates for each new field it encounters, if applicable, as well as applying the matching dynamic templates.

To do this, it needs to be able to parse mappings, which requires a ParserContext that the ParseContext exposes given a DateFormatter. So far, we have carried around a function that allows to create a new ParserContext given a date formatter, and then call a specific method that allows to wrap it to provide a special parser context that is specific for dynamic templates, which is needed to make some decisions down the line based on whether mappings come from dynamic templates or not.

This commit tries to simplify this by exposing the specific dynamic template parser context only to the document parse context, as that's all it needs. We recently ended up using the wrong context and with this change it would not be possible. The function that is passed around is the one that create a DynamicTemplateParserContext, so it cannot be mistaken for the one that creates a generic ParserContext.

Relates to elastic#74177
@javanna javanna added :Search Foundations/Mapping Index mappings, including merging and defining field types >refactoring v8.0.0 v7.14.0 labels Jun 18, 2021
@javanna javanna requested a review from romseygeek June 18, 2021 18:39
@elasticmachine elasticmachine added the Team:Search Meta label for search team label Jun 18, 2021
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-search (Team:Search)


@Override
public Mapper.TypeParser.ParserContext dynamicTemplateParserContext(DateFormatter dateFormatter) {
public Mapper.TypeParser.ParserContext.DynamicTemplateParserContext dynamicTemplateParserContext(DateFormatter dateFormatter) {
Copy link
Member Author

Choose a reason for hiding this comment

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

For conciseness, I would consider renaming this method back to parserContext now that its return type is specific

Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively, I think the type of this method can stay as just Mapper.TypeParser.ParserContext? And then DynamicTemplateParserContext can become a top-level package-private class and we lose some of the crazy nesting :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Counter proposal: shall we get ParserContext out of Mapper.TypeParser completely as a follow-up? it's used for runtime fields too so it is not specific to Mappers, and we could rename it to to something that is less confusing compared to ParseContext that is instead used for documents.

Copy link
Contributor

Choose a reason for hiding this comment

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

shall we get ParserContext out of Mapper.TypeParser completely as a follow-up?

Strong +1 from me! I think we can still leave this method return type untouched though?

Copy link
Member Author

@javanna javanna Jun 21, 2021

Choose a reason for hiding this comment

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

Ok good discussion: changing the type makes sure that the wrong context cannot be provided, and helps readers understand that when parsing dynamic templates only the appropriate context can be used.

I guess I see how it can be cleaner and tempting to use the more generic type, but what are the advantages in this case compared to the confusion that it adds in that it is hard to follow and very easy to miss?

Copy link
Contributor

Choose a reason for hiding this comment

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

My argument would be that: we only have a single concrete implementation of ParseContext (and are unlikely to add more) so I don't think we need to worry about returning an incorrect type elsewhere; that the name of the method describes the fact that it's specifically for dynamic templates; in general it's best to return interfaces rather than implementations; and that having four layers of nested class name makes my eyes hurt.

Copy link
Member Author

Choose a reason for hiding this comment

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

the nesting I agree on. My point is that with keeping the type generic we may end up making the same mistake that got us here aka carrying around the wrong context. The name of a method does not enforce anything, while the return type does. I agree on the software engineering guidelines around using interfaces but they also introduce complexity. The important bit is that parsing mappings requires a ParserContext, which is the case. But we can clarify that when we parse as part of dynamic templates, the context that is provided will be specific, we don't need to keep things overly generic everywhere as that brings no benefits?

Copy link
Contributor

Choose a reason for hiding this comment

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

The previous bug was because you had do to two things: 1) get a new parser context from the ParseContext, and 2) convert it to a dynamic context. This commit merges the two, so that what you get back from 1) is always a dynamic context. There's no way of getting a parser context from ParseContext that isn't dynamic. So I don't see how we could make the same mistake again?

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 feel like it is still a bit delicate if we use the more generic type, we may change that due to refactoring, not too sure. Maybe I am being a bit paranoid but this is still a bit sketchy. Anyways, I will do as you ask.

return new DynamicTemplateParserContext(this);
}

private static class MultiFieldParserContext extends ParserContext {
Copy link
Member Author

Choose a reason for hiding this comment

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

we may want to look into taking the same approach with MultiFieldParseContext, to prevent mistakes in the future.

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.

Nice, I tried to do this earlier and got mixed up with the different functions in the MapperService constructor but this cleans things up. I left a suggestion about class/package structure.


@Override
public Mapper.TypeParser.ParserContext dynamicTemplateParserContext(DateFormatter dateFormatter) {
public Mapper.TypeParser.ParserContext.DynamicTemplateParserContext dynamicTemplateParserContext(DateFormatter dateFormatter) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively, I think the type of this method can stay as just Mapper.TypeParser.ParserContext? And then DynamicTemplateParserContext can become a top-level package-private class and we lose some of the crazy nesting :)

@javanna javanna merged commit 4c33e3e into elastic:master Jun 21, 2021
javanna added a commit that referenced this pull request Jun 21, 2021
DocumentParser takes care of parsing documents and applying dynamic mapping updates for each new field it encounters, if applicable, as well as applying the matching dynamic templates.

To do this, it needs to be able to parse mappings, which requires a ParserContext that the ParseContext exposes given a DateFormatter. So far, we have carried around a function that allows to create a new ParserContext given a date formatter, and then call a specific method that allows to wrap it to provide a special parser context that is specific for dynamic templates, which is needed to make some decisions down the line based on whether mappings come from dynamic templates or not.

This commit tries to simplify this by exposing the specific dynamic template parser context only to the document parse context, as that's all it needs. We recently ended up using the wrong context and with this change it would not be possible.

Relates to #74177
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

>refactoring :Search Foundations/Mapping Index mappings, including merging and defining field types Team:Search Meta label for search team v7.14.0 v8.0.0-alpha1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants