-
Notifications
You must be signed in to change notification settings - Fork 25.7k
resolve indices for prefixed _all expressions #137330
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
Changes from 3 commits
9c7e04b
2ecdc40
b19ec68
84ea19d
8bbfd8f
aaea6cf
7812375
ef0417d
13ceafc
d3470c9
9730e5e
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 |
|---|---|---|
|
|
@@ -2956,6 +2956,91 @@ public void testCrossProjectSearchSelectorsNotAllowed() { | |
| assertThat(exception.getMessage(), equalTo("Selectors are not currently supported but was found in the expression [_all::data]")); | ||
| } | ||
|
|
||
| public void testResolveAllWithWildcardRemotePrefix() { | ||
| when(crossProjectModeDecider.resolvesCrossProject(any(IndicesRequest.Replaceable.class))).thenReturn(true); | ||
|
|
||
| var request = new SearchRequest().indices("*:_all"); | ||
| request.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), true, true)); | ||
| var resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases( | ||
| "indices:/" + randomAlphaOfLength(8), | ||
| request, | ||
| projectMetadata, | ||
| buildAuthorizedIndices(user, TransportSearchAction.TYPE.name()), | ||
| new TargetProjects( | ||
| createRandomProjectWithAlias("local"), | ||
| List.of(createRandomProjectWithAlias("P1"), createRandomProjectWithAlias("P2"), createRandomProjectWithAlias("P3")) | ||
| ) | ||
| ); | ||
|
|
||
| var expectedIndices = new String[] { "bar", "foobarfoo", "bar-closed", "foofoobar", "foofoo-closed", "foofoo" }; | ||
|
|
||
| assertThat(resolvedIndices.getLocal(), contains(expectedIndices)); | ||
| assertThat(resolvedIndices.getRemote(), containsInAnyOrder("P1:_all", "P2:_all", "P3:_all")); | ||
|
|
||
| final var resolved = request.getResolvedIndexExpressions(); | ||
| assertThat(resolved, is(notNullValue())); | ||
| assertThat( | ||
| resolved.expressions(), | ||
| contains(resolvedIndexExpression("*:_all", Set.of(expectedIndices), SUCCESS, Set.of("P1:_all", "P2:_all", "P3:_all"))) | ||
| ); | ||
| } | ||
|
|
||
| public void testResolveAllWithRemotePrefix() { | ||
| when(crossProjectModeDecider.resolvesCrossProject(any(IndicesRequest.Replaceable.class))).thenReturn(true); | ||
|
|
||
| var expression = randomBoolean() ? "local:_all" : "_origin:_all"; | ||
| var request = new SearchRequest().indices(expression); | ||
| request.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), true, true)); | ||
| var resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases( | ||
| "indices:/" + randomAlphaOfLength(8), | ||
| request, | ||
| projectMetadata, | ||
| buildAuthorizedIndices(user, TransportSearchAction.TYPE.name()), | ||
| new TargetProjects( | ||
| createRandomProjectWithAlias("local"), | ||
| List.of(createRandomProjectWithAlias("P1"), createRandomProjectWithAlias("P2"), createRandomProjectWithAlias("P3")) | ||
| ) | ||
| ); | ||
|
|
||
| var expectedIndices = new String[] { "bar", "foobarfoo", "bar-closed", "foofoobar", "foofoo-closed", "foofoo" }; | ||
|
|
||
| assertThat(resolvedIndices.getLocal(), contains(expectedIndices)); | ||
| assertThat(resolvedIndices.getRemote(), is(empty())); | ||
|
|
||
| final var resolved = request.getResolvedIndexExpressions(); | ||
| assertThat(resolved, is(notNullValue())); | ||
| assertThat(resolved.expressions(), contains(resolvedIndexExpression(expression, Set.of(expectedIndices), SUCCESS, Set.of()))); | ||
| } | ||
|
|
||
| public void testResolveIndexWithRemotePrefix() { | ||
|
Contributor
Author
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. I noticed that I could just set all cross project requests to go down the "all indices" path and all the tests would pass, even though this is obviously wrong; I've added this test which fails under that scenario
Member
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.
Do you mean all tests in this test class? I am surprised unless all existing tests are effectively resolving to all accessible indices. Is that the case? Also, I assume tests in other places, e.g. the serverless REST test, should fail?
Contributor
Author
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. I think it's because the majority of the other tests in this file have CPS mode disabled; I'll see if the REST test guards against this, but I don't want it to be the only test that would fail - it makes the feedback loop too long
Contributor
Author
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. Confirmed that the REST test fails when this functionality is implemented incorrectly |
||
| when(crossProjectModeDecider.resolvesCrossProject(any(IndicesRequest.Replaceable.class))).thenReturn(true); | ||
|
|
||
| var request = new SearchRequest().indices("*:bar"); | ||
| request.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), true, true)); | ||
| var resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases( | ||
| "indices:/" + randomAlphaOfLength(8), | ||
| request, | ||
| projectMetadata, | ||
| buildAuthorizedIndices(user, TransportSearchAction.TYPE.name()), | ||
| new TargetProjects( | ||
| createRandomProjectWithAlias("local"), | ||
| List.of(createRandomProjectWithAlias("P1"), createRandomProjectWithAlias("P2"), createRandomProjectWithAlias("P3")) | ||
| ) | ||
| ); | ||
|
|
||
| var expectedIndices = new String[] { "bar" }; | ||
|
|
||
| assertThat(resolvedIndices.getLocal(), contains(expectedIndices)); | ||
| assertThat(resolvedIndices.getRemote(), containsInAnyOrder("P1:bar", "P2:bar", "P3:bar")); | ||
|
|
||
| final var resolved = request.getResolvedIndexExpressions(); | ||
| assertThat(resolved, is(notNullValue())); | ||
| assertThat( | ||
| resolved.expressions(), | ||
| contains(resolvedIndexExpression("*:bar", Set.of(expectedIndices), SUCCESS, Set.of("P1:bar", "P2:bar", "P3:bar"))) | ||
| ); | ||
| } | ||
|
|
||
| private void assertIndicesMatch(IndicesRequest.Replaceable request, String expression, List<String> indices, String[] expectedIndices) { | ||
| assertThat(indices, hasSize(expectedIndices.length)); | ||
| assertThat(request.indices().length, equalTo(expectedIndices.length)); | ||
|
|
||
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.
This matches what I was thinking, i.e. let cases like
*:_allgo through the all indices handling. I suggest we useRemoteClusterAware#splitIndexNameinstead ofrewriteIndexExpression. It is lighter and we don't care about resolving projects at this point. It also needs to handle syntax like selector. I'd prefer we don't error out atisAllIndicescheck. The unsupported syntax will still be caught later when we callrewriteIndexExpression. So overall I am suggeting something likeThere 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 appears this isn't enough, as this means any expression targeting
_allwill resolve all indices on the local project, even if that expression is e.g.some_remote_project:_all.We need to check if the expression is
_all, and that the prefix includes the local project. It looks to me likerewriteIndexExpressionhandles all the edge cases here, even if it does more than what's necessary 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.
Yes we will resolve local indices unnecessarily in this case. But I think local indices should still be excluded because of this code. I was going to leave the unnecessary expansion for a future optimization.
Even if we use
rewriteIndexExpressionhere, it is not sufficient due toproject_routing, e.g. we will still expand local indices unnecessarily when the request has expression_alland project routingsome_remote_project. If you are keen to avoid local expansion, I'd rather prefer we solve this more comprehensively to cover this TODO as well.What I have in mind is something like the follows:
splitIndexNameandsplitSelectorExpressionfor checkingisAllIndiceswhich IMO should be interpreted as "is it an all indices pattern for any project".crossProjectModeDecider.resolvesCrossProjectand only expand locally if the final resolved projects include the origin project.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 appears that this logic only handles project routing filtering but not the qualified projects in index expression. So it does not work for
linked_project:_all.I am still a little suspicious on the latest change. IIUC, it means an expression like
linked_project:_allgoes through theelsebranch of theisAllIndicescheck? While expressions like*:_allor_allwith project routinglinked_projectstill go through theifbranch. The later is functionally equivalent tolinked_project:_alland it would great if they follow the same path. Maybe we just need to resolve the project routing before invokingrewriteIndexExpression? If we take this path, I think we should also rename theisAllIndicesvariable to something likecontainsLocalAllIndices?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 switched back to using
splitIndexNameagain, and extended theshouldExcludeLocalResolutioncheck to check iflocalExpressionis set, and this seems to work (including the REST test). Does this align with what you were thinking?I could also take a look at moving the condition earlier to see if we can skip the redundant local expansion as well.
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.
That works for me as well. We can have separate PR to address the TODO for skipping redundant local expansion.