From 6b30bbef6d426226d1f0025c9debd78d8f3d193c Mon Sep 17 00:00:00 2001 From: zoharsan Date: Thu, 30 Jul 2026 15:15:34 -0400 Subject: [PATCH] Expand rank() operator reference: composite conditions, matches(), negations Document behavior of ranking-only arguments verified against master: - rank() is variadic; arguments after the first never affect matching - all query operators usable in ranking-only arguments (in, range, grouped conditions) - observing arguments with matches(field) and matches(field, n), including several conditions on the same field - grouped conditions are evaluated as a unit (terms expose match information only where the whole condition is true) - negation-only arguments are not observable by rank features; documented the invert-in-the-expression alternative - note on unused ranking-only arguments being pruned (no cost, no effect) Replaces the hybrid-search example with a worked boost example, as the section now focuses on the boost-without-filtering use case. Co-Authored-By: Claude Fable 5 --- en/reference/querying/yql.html | 102 +++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/en/reference/querying/yql.html b/en/reference/querying/yql.html index 28865f95a1..ca2090804b 100644 --- a/en/reference/querying/yql.html +++ b/en/reference/querying/yql.html @@ -732,19 +732,111 @@

where

The first, and only the first, argument of the rank() function determines whether a document is a match, but all arguments are used for calculating rank features. The rank operator - is useful for boosting documents based on the presence of certain terms without impacting matching or retrieval logic. + is useful for boosting documents based on the presence of certain conditions without impacting matching or retrieval logic.

 where rank(a contains "A", b contains "B", c contains "C")
 

- It's also useful in hybrid search use cases. See blog post - for usage examples. For example, retrieve using the nearestNeighbor query operator - as the first argument and have matching features calculated for the other arguments. + rank() takes any number of arguments. + Arguments after the first never affect which documents match: + they can neither exclude documents from, nor add documents to, the result set. + Any query operator can be used in these arguments, including + in, numeric ranges and grouped conditions:

-where rank(nearestNeighbor(field, queryVector), a contains "A", b contains "B", c contains "C")
+where rank(userQuery(),
+           country in ("italy", "france"),
+           range(price, 0, 1000),
+           (is_new = true and range(rating, 4, 5)))
 
+

+ Observing the ranking-only arguments: + terms in arguments after the first expose match information to + rank features like ordinary query terms: + use matches(field) for a match indicator. + In the example above, matches(country) is 1 for documents with + country italy or france, and matches(price) is 1 for documents + priced 1000 or less, so a rank profile can boost with e.g. + nativeRank + 3.0 * matches(country) + 1.0 * matches(price). + Text features like bm25 and + fieldMatch require index fields with position data; + operators such as in and numeric ranges are visible to + matches() but do not contribute to text features. +

+

+ Several conditions using the same field: + matches(field) is 1 if any query term on the field + matched, so it cannot distinguish between multiple conditions on the same + field. Use matches(field, n) to test the n'th query term instead, + where n counts the query's terms in order, starting from 0: +

+
+where rank(title contains "vacation package",
+           country in ("italy"),
+           country in ("norway"))
+
+

+ Here, term 0 is the title term, term 1 the italy condition and term 2 the + norway condition, so this rank profile boosts italy documents by 3 + and norway documents by 1: +

+
+first-phase {
+    expression: nativeRank + 3.0 * matches(country, 1) + 1.0 * matches(country, 2)
+}
+
+

+ Note that the term numbering follows the query structure: + adding, removing or reordering query terms changes the indexes, + so rank profiles using matches(field, n) must be kept in sync + with the queries sent. +

+

+ Grouped conditions are evaluated as a unit: + terms inside a grouped ranking-only argument expose match information + only for documents where the whole condition is true. + This makes a grouped condition usable as a single boost rule, + observable through any of its fields not used elsewhere in the query: +

+
+where rank(userQuery(),
+           (country in ("italy") and range(price, 0, 1000)))
+
+

+ Here, matches(price) is 1 only for documents that are both + from italy and priced 1000 or less - a document satisfying only + one of the two conditions gets no match information from this argument. + This rank profile hence boosts documents satisfying the full rule: +

+
+first-phase {
+    expression: nativeRank + 3.0 * matches(price)
+}
+
+

+ Negations are not observable: + only positively matching terms expose match information. + A ranking-only argument consisting of only a negation, such as + rank(userQuery(), !(country in ("norway"))), matches correctly + but cannot be observed by any rank feature - the negated term does not + match precisely the documents where the condition is true. + To boost on a negative condition, state it positively in the query + and invert it in the ranking expression: +

+
+where rank(userQuery(), country in ("norway"))
+
+
+first-phase {
+    expression: nativeRank + 100 * (1 - matches(country))
+}
+
+ {% include note.html content='A ranking-only argument only affects ranking + if the selected rank profile reads it, using a rank feature such as + matches(field) over one of its fields. + Arguments not read by any rank feature are removed from query execution: + they have no cost, but also no effect.' %}