-
Notifications
You must be signed in to change notification settings - Fork 25.3k
Fix bug in rule_query where text_expansion errored because it was not rewritten #105365
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 all commits
433ae23
61af185
c97642a
3d931bc
6d7047e
76f8d63
7156651
0215ce6
5b19bc8
c7e869a
abc3e6b
8032652
9455df6
d24e74e
5fc0d93
2673143
f566734
4572620
fedbc9f
f956001
2194683
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,6 @@ | ||
pr: 105365 | ||
summary: Fix bug in `rule_query` where `text_expansion` errored because it was not | ||
rewritten | ||
area: Application | ||
type: bug | ||
issues: [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -111,18 +111,6 @@ private RuleQueryBuilder( | |
throw new IllegalArgumentException("rulesetId must not be null or empty"); | ||
} | ||
|
||
// PinnedQueryBuilder will return an error if we attempt to return more than the maximum number of | ||
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. @benwtrent had a great observation that these checks don't do anything because pinnedIds and docs are interstitial - moved these checks down into rewrite. 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. They are so interstitial, they are never set in this constructor, as once we have them (or not) we return a different kind of query. Could we remove them from the ctor here? Its private, so not that big of a deal, but we always pass 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 was going to remove them, but then ran into the transport client changes, so figured I'd hold off for this PR... |
||
// pinned hits. Here, we truncate matching rules rather than return an error. | ||
if (pinnedIds != null && pinnedIds.size() > MAX_NUM_PINNED_HITS) { | ||
HeaderWarning.addWarning("Truncating query rule pinned hits to " + MAX_NUM_PINNED_HITS + " documents"); | ||
pinnedIds = pinnedIds.subList(0, MAX_NUM_PINNED_HITS); | ||
} | ||
|
||
if (pinnedDocs != null && pinnedDocs.size() > MAX_NUM_PINNED_HITS) { | ||
HeaderWarning.addWarning("Truncating query rule pinned hits to " + MAX_NUM_PINNED_HITS + " documents"); | ||
pinnedDocs = pinnedDocs.subList(0, MAX_NUM_PINNED_HITS); | ||
} | ||
|
||
this.organicQuery = organicQuery; | ||
this.matchCriteria = matchCriteria; | ||
this.rulesetId = rulesetId; | ||
|
@@ -174,6 +162,9 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep | |
|
||
@Override | ||
protected Query doToQuery(SearchExecutionContext context) throws IOException { | ||
// NOTE: this is old query logic, as in 8.12.2+ and 8.13.0+ we will always rewrite this query | ||
// into a pinned query or the organic query. This logic remains here for backwards compatibility | ||
// with coordinator nodes running versions 8.10.0 - 8.12.1. | ||
kderusso marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ((pinnedIds != null && pinnedIds.isEmpty() == false) && (pinnedDocs != null && pinnedDocs.isEmpty() == false)) { | ||
throw new IllegalArgumentException("applied rules contain both pinned ids and pinned docs, only one of ids or docs is allowed"); | ||
kderusso marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
@@ -187,21 +178,25 @@ protected Query doToQuery(SearchExecutionContext context) throws IOException { | |
} else { | ||
return organicQuery.toQuery(context); | ||
} | ||
|
||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws IOException { | ||
if (pinnedIds != null || pinnedDocs != null) { | ||
return this; | ||
} else if (pinnedIdsSupplier != null || pinnedDocsSupplier != null) { | ||
List<String> identifiedPinnedIds = pinnedIdsSupplier != null ? pinnedIdsSupplier.get() : null; | ||
List<Item> identifiedPinnedDocs = pinnedDocsSupplier != null ? pinnedDocsSupplier.get() : null; | ||
if (identifiedPinnedIds == null && identifiedPinnedDocs == null) { | ||
return this; // not executed yet | ||
protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) { | ||
if (pinnedIdsSupplier != null && pinnedDocsSupplier != null) { | ||
List<String> identifiedPinnedIds = pinnedIdsSupplier.get(); | ||
List<Item> identifiedPinnedDocs = pinnedDocsSupplier.get(); | ||
if (identifiedPinnedIds == null || identifiedPinnedDocs == null) { | ||
return this; // Not executed yet | ||
kderusso marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else if (identifiedPinnedIds.isEmpty() && identifiedPinnedDocs.isEmpty()) { | ||
return organicQuery; // Nothing to pin here | ||
} else if (identifiedPinnedIds.isEmpty() == false && identifiedPinnedDocs.isEmpty() == false) { | ||
throw new IllegalArgumentException( | ||
"applied rules contain both pinned ids and pinned docs, only one of ids or docs is allowed" | ||
); | ||
} else if (identifiedPinnedIds.isEmpty() == false) { | ||
return new PinnedQueryBuilder(organicQuery, truncateList(identifiedPinnedIds).toArray(new String[0])); | ||
} else { | ||
return new RuleQueryBuilder(organicQuery, matchCriteria, rulesetId, identifiedPinnedIds, identifiedPinnedDocs, null, null); | ||
return new PinnedQueryBuilder(organicQuery, truncateList(identifiedPinnedDocs).toArray(new Item[0])); | ||
} | ||
} | ||
|
||
|
@@ -244,18 +239,19 @@ public void onFailure(Exception e) { | |
}); | ||
}); | ||
|
||
QueryBuilder newOrganicQuery = organicQuery.rewrite(queryRewriteContext); | ||
RuleQueryBuilder rewritten = new RuleQueryBuilder( | ||
newOrganicQuery, | ||
matchCriteria, | ||
this.rulesetId, | ||
null, | ||
null, | ||
pinnedIdsSetOnce::get, | ||
pinnedDocsSetOnce::get | ||
); | ||
rewritten.boost(this.boost); | ||
return rewritten; | ||
return new RuleQueryBuilder(organicQuery, matchCriteria, this.rulesetId, null, null, pinnedIdsSetOnce::get, pinnedDocsSetOnce::get) | ||
.boost(this.boost) | ||
.queryName(this.queryName); | ||
} | ||
|
||
private List<?> truncateList(List<?> input) { | ||
// PinnedQueryBuilder will return an error if we attempt to return more than the maximum number of | ||
// pinned hits. Here, we truncate matching rules rather than return an error. | ||
if (input.size() > MAX_NUM_PINNED_HITS) { | ||
HeaderWarning.addWarning("Truncating query rule pinned hits to " + MAX_NUM_PINNED_HITS + " documents"); | ||
return input.subList(0, MAX_NUM_PINNED_HITS); | ||
} | ||
return input; | ||
} | ||
|
||
@Override | ||
|
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.
My guess is that this needs to have a
skip
version for the version that this is fixed in. Generally, how to handle this, is to make it restrictive on main (e.g. 8.13 only) (this may be even trickier if 8.13 branch is already cut, if so, this skip should initially be 8.14, and after backports, adjust). and in the back port adjust it to8.12.2/3
. Once the backport is merged, adjust main to8.12.2/3
.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.
Thanks for this - I'll make sure to do this