-
Notifications
You must be signed in to change notification settings - Fork 25.2k
Move merge compatibility logic from MappedFieldType to FieldMapper #56915
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
Conversation
Pinging @elastic/es-search (:Search/Mapping) |
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.
It's great you're cleaning up FieldMapper
! I'm excited about the plan in #56814.
I was wondering if we could simplify the method structure more by combining the compatibility checks and merging together. This seems natural to me -- for each option you validate if it can be changed, and then apply the change if possible. Subclasses would only need to override a single method.
A new call structure would look something like this:
FieldMapper#merge
-> FieldMapper#mergeSharedOptions
(handles both compatibility checks and updates field type, copy to, etc.)
-> FieldMapper#mergeOptions
(overridden by subclasses to perform both compatibility checks and updates options)
This could be done as a follow-up refactor if we wanted to keep the current PR simple, as a straight reshuffling of methods.
|
||
protected abstract T newBuilder(); | ||
|
||
private static class BogusFieldType extends MappedFieldType { |
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.
It seems like we could reuse the existing test classes MockFieldMapper
and FakeFieldType
here.
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.
++
} | ||
} | ||
|
||
public void testFreeze() { |
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.
It looks like this test was lost in the refactor. Do we have plans to replace it or make it no longer necessary?
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.
The next step will be to decouple FieldType and MappedFieldType entirely, so there won't need to be a freeze() method here at all.
I like this a lot, it would make things a lot clearer. Let's do it in a follow-up to keep this PR reasonably contained? |
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 a last round of comments.
Let's do it in a follow-up to keep this PR reasonably contained?
Sounds good to me.
} | ||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> | ||
mapperService.merge("type", new CompressedXContent(Strings.toString(update)), MapperService.MergeReason.MAPPING_UPDATE)); | ||
assertThat(e.getMessage(), containsString("mapper [foo] of different type, current_type [long], merged_type [double]")); |
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.
To me the error message "mapper [foo] cannot be changed from type [long] to [double]" is a lot clearer, we could prefer that original wording.
On a related note, it looks like MappedFieldType#checkTypeName
is now unused and can be removed.
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.
++
ft1 = createNamedDefaultFieldType(); | ||
ft2 = createNamedDefaultFieldType(); | ||
modifier.modify(ft2); | ||
assertFieldTypeNotEquals(modifier.property, ft1, ft2); |
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 just noticed we've lost test coverage for the equals
method, which is used in FieldTypeLookup
. This is too bad, I wonder if we could we keep these modifiers around or switch to using EqualsHashCodeTestUtils#checkEqualsAndHashCode
.
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.
With luck we'll be able to simplify a lot of the MapperService lookup stuff once things have been rearranged, but for now I agree we still need these tests. I've modified FieldTypeTestCase to allow testing of subtypes with modifiers, using EqualsHashCodeTestUtils
.
@@ -203,8 +179,8 @@ public void testMergeConflicts() { | |||
} | |||
{ | |||
FieldMapper mapper = (FieldMapper) newBuilder().build(context); | |||
FieldMapper toMerge = new FieldMapper("bogus", new BogusFieldType(), new BogusFieldType(), | |||
SETTINGS, FieldMapper.MultiFields.empty(), FieldMapper.CopyTo.empty()) { | |||
FieldMapper toMerge = new FieldMapper("bogus", new MockFieldMapper.FakeFieldType(), |
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 think this could just be FIeldMapper toMerge = new MockFieldMapper("bogus")
?
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.
It could, thanks!
This turned out to make the final patch slightly smaller and easier to review, so I added it in. Thanks for the suggestion @jtibshirani ! |
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 some comments about field type tests that were deleted. I think they need to be restored, but once that's done it looks ready to merge.
import org.elasticsearch.index.mapper.MappedFieldType; | ||
import org.junit.Before; | ||
|
||
public class GeoShapeWithDocValuesFieldTypeTests extends FieldTypeTestCase { |
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.
Should this test have been deleted?
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.
It should not! Have restored it.
/** | ||
* Merge type-specific options and check for incompatible settings in mappings to be merged | ||
*/ | ||
protected abstract void mergeOptions(FieldMapper other, List<String> conflicts); |
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.
Great that this is abstract, I like how it encourages implementors to think through what can be updated vs. not.
throw new IllegalArgumentException("mapper [" + fieldType.name() + "] cannot be changed from type [" | ||
+ contentType() + "] to [" + mergeWith.getClass().getSimpleName() + "]"); | ||
} | ||
merged.mergeSharedOptions((FieldMapper)mergeWith, conflicts); |
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.
Small comment, calling mergeOptions
directly from here could be nice:
FieldMapper fieldMapper = (FieldMapper) mergeWith;
merged.mergeSharedOptions(fieldMapper, conflicts);
merged.mergeOptions(fieldMapper, conflicts);
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've rearranged things here.
@@ -51,22 +50,6 @@ protected MappedFieldType createDefaultFieldType() { | |||
return ft; | |||
} | |||
|
|||
@Before | |||
public void setupProperties() { |
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 think we dropped this modifier accidentally.
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.
scaling_factor
can't be updated, so we'd never be in a position when FieldTypeLookup would be comparing and old and new types with different scaling factors.
|
||
import java.util.Arrays; | ||
|
||
public class CompletionFieldTypeTests extends FieldTypeTestCase { |
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.
Should this have been deleted?
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.
Again, none of these values can be updated in a merge, so we don't need an equality check.
…56915) Merging logic is currently split between FieldMapper, with its merge() method, and MappedFieldType, which checks for merging compatibility. The compatibility checks are called from a third class, MappingMergeValidator. This makes it difficult to reason about what is or is not compatible in updates, and even what is in fact updateable - we have a number of tests that check compatibility on changes in mapping configuration that are not in fact possible. This commit refactors the compatibility logic so that it all sits on FieldMapper, and makes it called at merge time. It adds a new FieldMapperTestCase base class that FieldMapper tests can extend, and moves the compatibility testing machinery from FieldTypeTestCase to here. Relates to #56814
I think this is a left-over from elastic#56915 where a change in assertion message didn't make it to this very rare-case assertion.
I think this is a left-over from #56915 where a change in assertion message didn't make it to this very rare-case assertion.
…7085) I think this is a left-over from elastic#56915 where a change in assertion message didn't make it to this very rare-case assertion.
Merging logic is currently split between FieldMapper, with its
merge()
method, andMappedFieldType, which checks for merging compatibility. The compatibility checks
are called from a third class,
MappingMergeValidator
. This makes it difficult to reasonabout what is or is not compatible in updates, and even what is in fact updateable - we
have a number of tests that check compatibility on changes in mapping configuration
that are not in fact possible.
This commit refactors the compatibility logic so that it all sits on FieldMapper, and
makes it called at merge time. It adds a new
FieldMapperTestCase
base class thatFieldMapper
tests can extend, and moves the compatibility testing machinery fromFieldTypeTestCase
to here.Relates to #56814