Query rules offer users a way to have fine grained control over specific queries. Currently, the capabilities of query rules allow you to pin the search results you choose at the top of the result set, and/or exclude specific documents from a result set based on contextual query data.
There are several use cases for this type of find tuned control. These include applying business rules such as promotional campaigns to your search results or “fixing” highly visible problematic queries.
Query rules are accessible using the rule query and will soon be available as a retriever that works with reranking strategies such as RRF!
This post is about how you know whether your query rules are working as intended.
Let's start with a very simple example, that contains a single pinned rule and a single exclude rule:
PUT my-index/_doc/my-pinned-doc
{
"title": "My pinned document"
}
PUT my-index/_doc/my-excluded-doc
{
"title": "My excluded document"
}
PUT _query_rules/my-ruleset
{
"rules": [
{
"rule_id": "my-pinned-rule",
"type": "pinned",
"criteria": [
{
"type": "exact",
"metadata": "match",
"values": [
"pinned"
]
}
],
"actions": {
"ids": [
"my-pinned-doc"
]
}
},
{
"rule_id": "my-exclude-rule",
"type": "exclude",
"criteria": [
{
"type": "exact",
"metadata": "match",
"values": [
"exclude"
]
}
],
"actions": {
"ids": [
"my-excluded-doc"
]
}
}
]
}
When query rules launched, we only supported the pinned
rule. This rule guarantees that specified document(s) appear at the top of search results, regardless of whether they would have been returned in the original query. Therefore, a workaround to validate that rules are applied could be to issue a match_none query as the organic
part of the rule query, ensuring that any returned documents were pinned hits due to rule matches.
For the above example, that might look like:
POST my-index/_search
{
"query": {
"rule": {
"organic": {
"match_none": {}
},
"ruleset_ids": [
"my-ruleset"
],
"match_criteria": {
"match": "pinned"
}
}
}
}
We have since added exclude
rules, which identify documents that should never be returned in a result set.
Similarly, for exclude
rules, you could run a rule query against an ids query or maybe a match_all query for a very small dataset:
POST my-index/_search
{
"query": {
"rule": {
"organic": {
"ids": {
"values": [
"my-excluded-doc"
]
}
},
"ruleset_ids": [
"my-ruleset"
],
"match_criteria": {
"match": "exclude"
}
}
}
}
This isn't the best solution, so with Elasticsearch version 8.16 we introduced a new query rule tester API call, that allows you to determine which rules would have matched specific criteria, and the order that they would be applied. Here's an example of how to call it:
POST _query_rules/my-ruleset/_test
{
"match_criteria": {
"match": "exclude"
}
}
This call will return the following response:
{
"total_matched_rules": 1,
"matched_rules": [
{
"ruleset_id": "my-ruleset",
"rule_id": "my-exclude-rule"
}
]
}
This will also work in the future if new rules are added that don't select or exclude documents from the search results.
Happy search result curation!