-
Notifications
You must be signed in to change notification settings - Fork 25k
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
Extend support of allowedFields to getMatchingFieldNames and getAllFields #106862
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pr: 106862 | ||
summary: Extend support of `allowedFields` to `getMatchingFieldNames` and `getAllFields` | ||
area: "Mapping" | ||
type: bug | ||
issues: [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,6 +37,7 @@ | |
import java.util.function.BooleanSupplier; | ||
import java.util.function.LongSupplier; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
|
||
/** | ||
* Context object used to rewrite {@link QueryBuilder} instances into simplified version. | ||
|
@@ -318,35 +319,45 @@ public boolean indexMatches(String pattern) { | |
* @param pattern the field name pattern | ||
*/ | ||
public Set<String> getMatchingFieldNames(String pattern) { | ||
Set<String> matches; | ||
if (runtimeMappings.isEmpty()) { | ||
return mappingLookup.getMatchingFieldNames(pattern); | ||
} | ||
Set<String> matches = new HashSet<>(mappingLookup.getMatchingFieldNames(pattern)); | ||
if ("*".equals(pattern)) { | ||
matches.addAll(runtimeMappings.keySet()); | ||
} else if (Regex.isSimpleMatchPattern(pattern) == false) { | ||
// no wildcard | ||
if (runtimeMappings.containsKey(pattern)) { | ||
matches.add(pattern); | ||
} | ||
matches = mappingLookup.getMatchingFieldNames(pattern); | ||
} else { | ||
for (String name : runtimeMappings.keySet()) { | ||
if (Regex.simpleMatch(pattern, name)) { | ||
matches.add(name); | ||
matches = new HashSet<>(mappingLookup.getMatchingFieldNames(pattern)); | ||
if ("*".equals(pattern)) { | ||
matches.addAll(runtimeMappings.keySet()); | ||
} else if (Regex.isSimpleMatchPattern(pattern) == false) { | ||
// no wildcard | ||
if (runtimeMappings.containsKey(pattern)) { | ||
matches.add(pattern); | ||
} | ||
} else { | ||
for (String name : runtimeMappings.keySet()) { | ||
if (Regex.simpleMatch(pattern, name)) { | ||
matches.add(name); | ||
} | ||
} | ||
} | ||
} | ||
return matches; | ||
// If the field is not allowed, behave as if it is not mapped | ||
return allowedFields == null ? matches : matches.stream().filter(allowedFields).collect(Collectors.toSet()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly this is just the same we were doing before + an additional filter on allowed fields based n field names...maybe we can just extract the existing method into something like a private There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is the gain compared to a single method? |
||
} | ||
|
||
/** | ||
* @return An {@link Iterable} with key the field name and value the MappedFieldType | ||
*/ | ||
public Iterable<Map.Entry<String, MappedFieldType>> getAllFields() { | ||
var allFromMapping = mappingLookup.getFullNameToFieldType(); | ||
// runtime mappings and non-runtime fields don't overlap, so we can simply concatenate the iterables here | ||
return runtimeMappings.isEmpty() | ||
Map<String, MappedFieldType> allFromMapping = mappingLookup.getFullNameToFieldType(); | ||
Set<Map.Entry<String, MappedFieldType>> allEntrySet = allowedFields == null | ||
? allFromMapping.entrySet() | ||
: () -> Iterators.concat(allFromMapping.entrySet().iterator(), runtimeMappings.entrySet().iterator()); | ||
: allFromMapping.entrySet().stream().filter(entry -> allowedFields.test(entry.getKey())).collect(Collectors.toSet()); | ||
if (runtimeMappings.isEmpty()) { | ||
return allEntrySet; | ||
} | ||
Set<Map.Entry<String, MappedFieldType>> runtimeEntrySet = allowedFields == null | ||
? runtimeMappings.entrySet() | ||
: runtimeMappings.entrySet().stream().filter(entry -> allowedFields.test(entry.getKey())).collect(Collectors.toSet()); | ||
// runtime mappings and non-runtime fields don't overlap, so we can simply concatenate the iterables here | ||
return () -> Iterators.concat(allEntrySet.iterator(), runtimeEntrySet.iterator()); | ||
} | ||
} |
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 see here and below we always need to check for
allowedFields
to be null or not to decide if we need to filter one or more fields. I am wondering if we should require it to be not null and force the caller to use an identity predicate lambda (fieldName -> true) in case no field is filtered out.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 am not too sure what is best here. Skip the filtering entirely when the predicate is null, or always filter although the predicate always returns true? I went for the former, which leaves things as close as they are outside of api keys queries (when setAllowedFields is not called).
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 agree that, maybe, performance-wise not applying the filter at all might be better if there is nothing to filter out...which is the reason why I said it looks good to me...it is just that all those null checks are annoying for me.