Skip to content

Conversation

@GalLalouche
Copy link
Contributor

Reduce boilerplate associated with creating FieldCapabilities instances.
Since it's a class with a huge number of fields, it makes sense to define a builder object, as that can also help with all the Boolean and null blindness going on.
Note while there is a static Builder class in FieldCapabilities, it is not a proper builder object (no setters, still need to pass a lot of otherwise default parameters) and also package-private. To avoid changing that, I defined a new FieldCapabilitiesBuilder class. I also went over the code and refactored places which used the old constructor.

@elasticsearchmachine elasticsearchmachine added needs:triage Requires assignment of a team area label v9.1.0 labels Jan 30, 2025
@GalLalouche GalLalouche requested a review from jimczi January 30, 2025 16:12
@benwtrent benwtrent added the :Search Foundations/Search Catch all for Search Foundations label Jan 30, 2025
@elasticsearchmachine elasticsearchmachine added the Team:Search Foundations Meta label for the Search Foundations team in Elasticsearch label Jan 30, 2025
@elasticsearchmachine
Copy link
Collaborator

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

@elasticsearchmachine elasticsearchmachine removed the needs:triage Requires assignment of a team area label label Jan 30, 2025
@GalLalouche GalLalouche removed the request for review from jimczi January 30, 2025 17:03
@GalLalouche GalLalouche force-pushed the tests/field_caps_refactor branch from c87de3e to 09f5c33 Compare January 30, 2025 17:57
@GalLalouche GalLalouche force-pushed the tests/field_caps_refactor branch from 09f5c33 to 085ae87 Compare January 30, 2025 17:57
assertThat(fooRankField, Matchers.hasKey("rank_feature"));
assertEquals(
new FieldCapabilities("fooRank", "rank_feature", false, true, false, null, null, null, Collections.emptyMap()),
new FieldCapabilitiesBuilder("fooRank", "rank_feature").isAggregatable(false).build(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't you use the fieldCapabilities method to create a builder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch! Done.

return this;
}

public FieldCapabilitiesBuilder indices(String... indices) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This class is used only for testing, but this could be used in the main code in the future. Should we have defensive copies of the indices passed as parameters to avoid mutating the array content?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

this.isSearchable = true;
this.isAggregatable = true;

this.meta = Map.of();
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the use of Collections.emptyMap() is more appropriate for creating an immutable empty map in the consturctor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.


private Map<String, Set<String>> meta;

public FieldCapabilitiesBuilder(String name, String type) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The name and type look like required fields. Should any validation be applied?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What kind of validation did you have in mind? No piece of code validates these anywhere in the AFAICT.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is minor; I was thinking of checking for nullity. I believe the @NotNull annotation should be enough

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since this annotation is very rarely used in the code base, and since IMHO everything is not nullable by default, unless explicitly marked as @Nullable, let's keep it as it is.

return this;
}

public FieldCapabilitiesBuilder meta(Map<String, Set<String>> meta) {
Copy link
Contributor

Choose a reason for hiding this comment

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

As previously, should the map be copied?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

type,
new FieldCapabilities(field, type, isMetadataField, true, isAggregatable, null, null, null, Collections.emptyMap())
new FieldCapabilitiesBuilder(field, type).isMetadataField(isMetadataField)
.isSearchable(true)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is optional

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed.

)
);
multi.put("long", new FieldCapabilitiesBuilder(fieldName, "long").indices("one-index").build());
multi.put("text", new FieldCapabilitiesBuilder(fieldName, "text").indices("another-index").build());
Copy link
Contributor

Choose a reason for hiding this comment

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

Should the method be called isAggregatable(false) in the builder?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Done.

@drempapis
Copy link
Contributor

Thank you, @GalLalouche, for working on this. The readability of the code has been increased, avoiding the 'telescoping constructor' annoying issue. I've left some minor comments to address.

@GalLalouche GalLalouche force-pushed the tests/field_caps_refactor branch 2 times, most recently from 25ab4b5 to 3211c62 Compare March 3, 2025 13:23
@GalLalouche GalLalouche requested a review from drempapis March 3, 2025 14:31
@GalLalouche GalLalouche force-pushed the tests/field_caps_refactor branch from 9767d5f to cbc52e5 Compare March 3, 2025 14:36
@elastic elastic deleted a comment from cla-checker-service bot Mar 3, 2025
@GalLalouche GalLalouche force-pushed the tests/field_caps_refactor branch from cbc52e5 to d5bd523 Compare March 3, 2025 14:38
Copy link
Contributor

@drempapis drempapis left a comment

Choose a reason for hiding this comment

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

LGTM, thank you @GalLalouche for this update

@GalLalouche GalLalouche enabled auto-merge (squash) March 5, 2025 11:04
@GalLalouche GalLalouche merged commit a6e47ae into elastic:main Mar 5, 2025
17 checks passed
georgewallace pushed a commit to georgewallace/elasticsearch that referenced this pull request Mar 11, 2025
…elastic#121310)

Reduce boilerplate associated with creating `FieldCapabilities` instances.
Since it's a class with a huge number of fields, it makes sense to define a builder object, as that can also help with all the Boolean and null blindness going on.
Note while there is a static Builder class in `FieldCapabilities`, it is not a proper builder object (no setters, still need to pass a lot of otherwise default parameters) and also package-private. To avoid changing that, I defined a new `FieldCapabilitiesBuilder` class. I also went over the code and refactored places which used the old constructor.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

>refactoring :Search Foundations/Search Catch all for Search Foundations Team:Search Foundations Meta label for the Search Foundations team in Elasticsearch v9.1.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants