-
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
Fix bug in rule_query where text_expansion errored because it was not rewritten #105365
Conversation
Hi @kderusso, I've created a changelog YAML for you. |
Pinging @elastic/ent-search-eng (Team:Enterprise Search) |
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
LGTM. Just a non-blocking suggestion. |
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 regarding the rewrite logic. I think we also need an integration test with an organic query that requires an async rewrite. If it's too difficult to test with an existing query with async rewrite, we can add a custom one for the test.
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
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 more comments. We still needs an integration test to ensure that the bug is fixed. The unit tests are not enough here.
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
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 adding the yml tests! We're almost there ;). I left some comments to remove unneeded conditions and class members.
I also wonder if we can avoid the breaking change by being more lenient when dealing with queries coming from older nodes?
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Outdated
Show resolved
Hide resolved
@@ -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 comment
The 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 comment
The 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 null
, so seems like we could remove them.
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 was going to remove them, but then ran into the transport client changes, so figured I'd hold off for this PR...
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.
Only one more concern around validation when both lists are non-empty. The rest is minor cleanup stuff. Looking much cleaner!
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Show resolved
Hide resolved
} else if ((identifiedPinnedIds != null && identifiedPinnedIds.isEmpty()) | ||
&& (identifiedPinnedDocs != null && identifiedPinnedDocs.isEmpty())) { | ||
return organicQuery; // Nothing to pin here | ||
} else if (identifiedPinnedIds != null && identifiedPinnedIds.isEmpty() == false) { | ||
return new PinnedQueryBuilder(organicQuery, truncateList(identifiedPinnedIds).toArray(new String[0])); | ||
} else if (identifiedPinnedDocs != null && identifiedPinnedDocs.isEmpty() == false) { | ||
return new PinnedQueryBuilder(organicQuery, truncateList(identifiedPinnedDocs).toArray(new Item[0])); | ||
} else { | ||
return this; // Should never happen | ||
} |
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 don't see how these lists are ever null, down in the async action:
pinnedIdsSetOnce.set(appliedRules.pinnedIds().stream().distinct().toList());
pinnedDocsSetOnce.set(appliedRules.pinnedDocs().stream().distinct().toList());
If either were null
, we would have thrown an NPE on List.stream()
So, once they are set, they aren't null. The only time the suppliers will return null
from what I can tell is when the fetch hasn't finished yet.
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.
You're right, this is annoyingly defensive, I've cleaned it up a bit.
return this; // Not executed yet | ||
} else if ((identifiedPinnedIds != null && identifiedPinnedIds.isEmpty()) | ||
&& (identifiedPinnedDocs != null && identifiedPinnedDocs.isEmpty())) { | ||
return organicQuery; // Nothing to pin 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.
We should check
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");
}
As that will never be checked and we arbitrarily (seemingly) identifiedPinnedIds
first if both are supplied.
...gin/ent-search/src/main/java/org/elasticsearch/xpack/application/rules/RuleQueryBuilder.java
Show resolved
Hide resolved
@@ -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 comment
The 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 null
, so seems like we could remove them.
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.
There is still some minor cleanup to do, but I think this is fine to go.
Don't forget the test skips, I think you may need that for your new yaml test.
@@ -236,4 +236,151 @@ setup: | |||
- match: { hits.total.value: 1 } | |||
- match: { hits.hits.0._id: 'doc1' } | |||
|
|||
--- | |||
"Perform a rule query with an organic query that must be rewritten to another query type": | |||
|
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 to 8.12.2/3
. Once the backport is merged, adjust main to 8.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
Query rules has a bug where a
rule_query
with an underlying organictext_expansion
query will fail with the reason"failed to create query: text_expansion should have been rewritten to another query type"
.The reason for this is that the
text_expansion
query will throw this as it expects to be rewritten as a boolean query of weighted tokens. However, when we change it to a pinned query during the rewrite phase, it never gets re-written again when the pinned query tries to generate a query.Here's an example script to test the functionality. It requires an index pipeline set up using ELSER on a field called
text
.