-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Disallow "enabled" attribute change for types in mapping update (#33566) #33933
Disallow "enabled" attribute change for types in mapping update (#33566) #33933
Conversation
This commit adds a check for "enabled" attribute change for types when a RestPutMappingAction is received. A MappingException is thrown when such a change is detected. Change are prevented in both ways: "false -> true" and "true -> false". Tests are not part of this commit, they will be developed after design validation.
Pinging @elastic/es-search-aggs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -33,11 +33,15 @@ public MapperException(String message) { | |||
super(message); | |||
} | |||
|
|||
public MapperException(String msg, Object... args) { | |||
super(msg, args); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not sure we need another constructor here, can you just insert the args into the message String in the call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
Is LoggerMessageFormat#format
preferred over String#format
or maybe just string concatenation?
@@ -458,6 +458,8 @@ protected void doMerge(final ObjectMapper mergeWith) { | |||
|
|||
for (Mapper mergeWithMapper : mergeWith) { | |||
Mapper mergeIntoMapper = mappers.get(mergeWithMapper.simpleName()); | |||
throwExceptionIfEnabledAttributeIsUpdatedForType(mergeWith, mergeWithMapper, mergeIntoMapper); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: ImNotABigFanOfOverlyLongMethodNamesButWhatTheHeckIfYouReallyLikeIt ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll shorten it, I'm not a big fan neither.
As I wasn't sure of the suggested design I've chosen (very) (very) explicit name to make myself understood.
final ObjectMapper mergeWithObjectMapper = (ObjectMapper) mergeWithMapper; | ||
|
||
if (mergeIntoObjectMapper.isEnabled() != mergeWithObjectMapper.isEnabled()) { | ||
if (mergeIntoObjectMapper.nestedTypeFilter() instanceof TermQuery) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure I understand what the enable
setting in mappings that are merged have to do with nested queries, especially with TermQuery. Maybe I'm missing sth., could you explain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dug into this with a debugger and the _type
attribute happened to be wrapped into a TermQuery
.
I've been a (tiny) bit paranoiac as I wanted to be sure to not make other things break.
I'll have another debugging session to see how things work when updating mapping with "_source": { "enabled": false }
. I'll let you know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it looks like updating the _source
attribute in a mapping is not allowed.
command
curl -XPUT "${ES_CLUSTER}/index1/_mapping/type1" -H "Content-Type: application/json" --data '{
"properties": {
"foo": {
"source": {
"enabled": false
},
"properties": {
"bar": {
"type": "text"
}
}
}
}
}'
output
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "Mapping definition for [foo] has unsupported parameters: [source : {enabled=false}]"
}
],
"type": "mapper_parsing_exception",
"reason": "Mapping definition for [foo] has unsupported parameters: [source : {enabled=false}]"
},
"status": 400
}
I'll now have a look if removing this conditional block doesn't conflict with other enabled
-like metadata attributes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No gradlew check -p server
test failure after removing paranoiac conditional block 👍
Thank you @cbuescher 👍 I'll update this PR with your comments and add test cases. |
Hi @cbuescher, I've added test cases to ensure added behavior is covered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @cbismuth, thanks a lot for the update, the test looks good and I left only a few very minor comments.
|
||
if (mergeIntoObjectMapper.isEnabled() != mergeWithObjectMapper.isEnabled()) { | ||
final String path = mergeWith.fullPath() + "." + mergeWithObjectMapper.simpleName() + ".enabled"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: maybe delete this line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, these two lines are related, no need to add a blank line, I'll remove it.
server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java
Show resolved
Hide resolved
server/src/test/java/org/elasticsearch/index/mapper/ObjectMapperMergeTests.java
Show resolved
Hide resolved
private static Explicit<Boolean> dateDetection = new Explicit<>(false, false); | ||
private static Explicit<Boolean> numericDetection = new Explicit<>(false, false); | ||
private static Explicit<FormatDateTimeFormatter[]> dynamicDateTimeFormatters = new Explicit<>(new FormatDateTimeFormatter[0], false); | ||
private static Explicit<DynamicTemplate[]> dynamicTemplates = new Explicit<>(new DynamicTemplate[0], false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was a bit suprised by these until I saw them being used in createRootObjectMapper(), maybe you could just instantiate them there locally, even if that means a few more instances. I think it makes the test more readable although this way is certainly "better" in terms of object creation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you're right. It would be a better balance between performances and readability. I'll do it, thank you.
Thank you @cbuescher for your review. I've added comments to your comments and I'll update my PR very soon. |
PR updated with your comments, thank you @cbuescher. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left two more small comment, but generally this looks almost ready.
|
||
private static TextFieldMapper createTextFieldMapper(String name) { | ||
final TextFieldType fieldType = new TextFieldType(); | ||
final Settings indexSettings = Settings.builder().put(SETTING_VERSION_CREATED, "1").build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I guess it doesn't matter here too much, but normally one of the version constants from org.elasticsearch.Version
is used in these cases, usually Version.CURRENT
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's better as it's closer to production code.
dynamicDateTimeFormatters, dynamicTemplates, | ||
dateDetection, numericDetection, | ||
Settings.EMPTY | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I'm not too familiar with mapper creation (especially in tests) myself, but I saw that the RootObjectMapper.Builder already takes care of a lot of the defaults, so maybe this can be simplified to something like:
final Settings indexSettings = Settings.builder().put(SETTING_VERSION_CREATED, Version.CURRENT).build();
BuilderContext context = new BuilderContext(indexSettings, new ContentPath());
RootObjectMapper rootObjectMapper = new RootObjectMapper.Builder(fieldName).enabled(enabled).build(context);
mappers.values().stream().forEach(rootObjectMapper::putMapper);
return rootObjectMapper;
Or maybe even the dummy settings could be a test-wide constant.
I don't think this is necesarry but removes a bit of boilerplate code (which I admit testing the mappers seems to require quite a bit).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's far more better, builders are far more expressive than lengthy constructors.
Thank you @cbuescher for your attention to details, I know it can be very time consuming. PR is up-to-date with your comments 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cbismuth thanks, this looks good to me. I will kick of final CI test runs now, hope they pass in one go 🤞
@elasticmachine test this please
@elasticmachine test this please |
Great! Thanks @cbuescher! |
That's a lot of failures! I've downloaded the plain text output log and I'll replay failed tests on my laptop on Monday morning. Anyway, number of them seem to have the same stash dump, here is a sample below.
|
@cbismuth That's from BWC issues that can happen when another change is merged to 6.x. Those should go away if you merge master into your branch. |
Thank you @cbuescher 👍 Would you like me to test it on a 6.5 branch and let you know? |
@cbismuth thanks, I think it should be a straigtforward backport, the question is more if this is breaking users applications even though the feature never worked as intended. But throwing an error is different than silently ignoring. It could be considered a bugfix though, in that case if would justify the backport. But I'll see what others think. |
It is indeed a good question 😉 |
@cbismuth I got some feedback that it would probably better not to backport the new strict checking since it would be considered breaking. However, it would be nice to change the PR slightly so that instead of throwing and error, a deprecation warning is emitted warning users that their request was silently ignored and we will throw an error here in the next major version. I will open a separate issue for this, it would be great if you would like to adapt this PR slightly to address it, but its also no problem if you don't like to do that. There a only a few thing that need changing for this I think, I can give you directions if you like to work on this as well. |
@cbismuth I have to correct myself, the general opinion shifted to backporting this change to 6.5 and add it to the breaking changes log. I will do this with the backport. |
This commit adds a check for "enabled" attribute change for types when a RestPutMappingAction is received. A MappingException is thrown when such a change is detected. Change are prevented in both ways: "false -> true" and "true -> false". Closes #33566
That's fine, thank you @cbuescher. |
This commit adds a check for "enabled" attribute change for types when a RestPutMappingAction is received. A MappingException is thrown when such a change is detected. Change are prevented in both ways: "false -> true" and "true -> false". Closes #33566
Removed the invalid tip that enabled can be updated for existing fields and clarified instead that it cannot. Related to elastic#33566 and elastic#33933
In #33933 we disallowed changing the `enabled` parameter in object mappings. However, the fix didn't cover the root object mapper. This PR adjusts the change to also include the root mapper and clarifies the error message.
In #33933 we disallowed changing the `enabled` parameter in object mappings. However, the fix didn't cover the root object mapper. This PR adjusts the change to also include the root mapper and clarifies the error message.
This commit adds a check for
enabled
attribute change for types when aRestPutMappingAction
is received. AMappingException
is thrown when such a change is detected.Change are prevented in both ways:
false
totrue
andtrue
tofalse
.Here is a sample cURL output:
Tests are not part of this commit, they will be developed after design validation.