Skip to content

Explanation

Relevance

This document explains how Exofind calculates relevance scores and how its ranking layers interact when ordering search results. When a search query does not specify a sort order, Exofind orders results by relevance: how well each document matches the query. Ranking is calculated in separate layers that evaluate match quality, field location, intrinsic document values, and tie breaking.

The layers run in a fixed order, and each one reads what the layer before it produced:

The ranking layers of one search, from what a match is worth through ordering and a second pass to the results returned

For setting names and accepted values, see Field types and the Search API.

The foundation of relevance is standard Lucene text scoring:

  • A rare word contributes more to the score than a common word.
  • A word that appears repeatedly in a field value contributes more, with diminishing returns.
  • A field value’s length counts against its score. The same query words matching a short value indicate a better match than those matching inside a long value.

Exofind lets a field definition configure length normalization through lengthNormalization, because the importance of value length depends on what the field contains. A field containing names needs full normalization, because extra words distinguish the target item from a merely related item. A field containing prose needs much less normalization. A field containing all document content needs no normalization, because a fuller value there is not a worse answer.

Exofind stores the field length when indexing a document. The field definition controls only how much of that length Exofind reads at query time. Therefore, changing lengthNormalization reorders results on subsequent searches without requiring reindexing.

A search can query several fields at once, and a match in a title carries more weight than a match in a footnote. The weight setting under a field’s matching configuration controls how much a match in that field contributes to the score. A search request can override these field weights by mapping each field to a number in its text clause.

The combine setting controls how Exofind combines matches across fields. The default behavior is per-word combination: Exofind looks for each word across all fields and counts it in whichever field matches best. This default fits a general search box where a query like red nike shoes describes attributes across color, brand, and name fields. For fields that represent parallel versions of the same content, such as a title and a body, set combine to field so that a single field must satisfy the search query.

Combining words across fields works only when the fields tokenize text into the same words. When fields analyze text differently—for example, if one decompounds words while another drops stopwords—Exofind combines the fields that share the same tokenization into groups. Exofind then ranks the document by the best-matching group.

The exact setting on a field boosts a document when a search matches the entire field value, rather than merely matching the words within it. For example, this boost ranks a product named iphone 15 above a case designed for iphone 15.

The exact setting acts as a score boost, not a filter. It applies only to documents that the search query already matched, preserving hit counts and facet counts. This design ensures that ranking adjustments do not alter result counts. Because Exofind writes exact data during indexing, enabling exact applies only to documents indexed after the setting is enabled.

A boost clause ranks matching documents higher without excluding non-matching documents. For example, you can rank featured products above standard products, or in-stock items above out-of-stock items. While filters remove non-matching results, boost clauses reorder them.

Boost clauses contribute to the relevance score of a match. For this reason, highlighting evaluates boost clauses rather than filter clauses. A document does not receive highlighting for a category filter that matches it.

Text scoring evaluates only the search match. The signals configuration provides the other half of relevance: intrinsic document values, such as sales volume or publication date. Exofind transforms a ranking signal value into a number between 0 and 1, and multiplies it into the score as 1 + weight * shape.

The transformation shape prevents ranking signals from distorting search quality:

  • A document with no value for a ranking signal receives a shape value of 0. It is not penalized or multiplied away, so adding a ranking signal does not bury existing documents that lack the value.
  • A ranking signal can boost a document score by at most its weight, regardless of how large the underlying value is. A high-selling item cannot outrank a document with a significantly better text match.

The choice of shape depends on what the ranking signal measures. An unbounded count saturates toward 1, while an age decays by halving over time. A score computed outside the engine that already lies in a known range, such as an engagement score between 0 and 1 or a margin in percent, uses a linear shape, because saturation would bend a score that is already bounded. Because Exofind evaluates ranking signals at query time rather than storing them in index structures, you can adjust the ranking signals in the index definition or pass your own in a search request without reindexing documents.

A ranking signal reads any field that has sort enabled. A field whose value changes more often than the document it belongs to can be declared a signal field, which refreshes the value without indexing the document again. See Signal fields.

Ranking signals produce continuous scores, but ties can still occur. For example, a search that only applies filters matches all returned documents equally. The index’s tieBreakers setting defines fallback ordering rules. Exofind appends these tie breakers after the requested sort order and evaluates them in sequence until one resolves the tie between two documents. Tie breakers resolve ordering within ties without changing the primary sort order.

Ranking signals and tie breakers are defined in the index definition. Because the definition travels with the index data, updating it requires the writer node, and other nodes receive changes only on their next pull. To update query-time settings faster, an index can use search settings. A search settings request can be sent to any node - it runs on the index’s holder - and all nodes re-read the settings on their own refresh interval.

When search settings define a ranking configuration, it completely replaces the ranking configuration from the index definition. The index definition provides the default ranking, and deleting search settings restores this default.

The index and the search request own different layers of the same ranking. Whichever ranking is in force on the index is the base layer, and a search request adds its own signals on top of it. A ranking signal in the request that names the same field as one on the index replaces it, so a search moves one weight without resending the rest. Setting signalsMode to replace drops the index layer entirely, which is how you try out a complete ranking before adopting it.

Layering keeps the two parties separable. A per-request ranking signal about the person searching does not take the merchant’s configured ranking off the search, and a later change to that ranking still reaches personalized searches.

Tuning proceeds in small steps - one weight, one pivot - so search settings also accept a change that names only the part it moves, described the same way a change to part of a document is. See Changing part of the search settings.

Search settings also carry synonym sets that widen what a search asks for. Synonyms are a relevance decision because the words a rule adds are counted together with the word that was typed as one term. Consequently, a document found through a rare synonym is not scored by how rare the synonym is. The set’s boost weighs an added word against the typed one.

The two sides have different costs. An index-time set reaches only documents indexed after it, whereas a query-time set reaches everything already in the index. Putting the same rule on both sides counts it twice.

Search settings attach to the index name rather than to a specific index generation, so promoting a generation preserves your ranking tuning. This approach involves two trade-offs:

  • Nodes update independently, so two nodes can rank the same query differently for up to one refresh interval.
  • If a newer generation lacks a field configured in search settings, searches skip that ranking entry rather than failing.

Reordering the best results in a second pass

Section titled “Reordering the best results in a second pass”

Every other ranking control takes part in retrieval: a boost that lifts a document also decides whether the document is retrieved at all. That behavior is correct for a ranking signal about the documents, but wrong for a ranking signal about the person searching. For example, a shopper who looks at one brand should see that brand ranked higher among relevant results, but should never see a poor match promoted onto the first page.

The rescore block draws that boundary. The first pass retrieves and ranks every match by relevance. The second pass scores only the best results within a specified window and adds the second score to the first-pass score. Results below the window keep the order relevance gave them. Because boosts inside the window apply only to documents that already matched, they reorder what is already relevant and reach nothing else.

The window is also where per-request work that is too expensive for every match belongs, such as evaluating user affinity boosts. Scoring a window of a few hundred results costs a fixed amount per search, regardless of the size of the index.

Ranking a window instead of a complete result set leads to several specific behaviors:

  • Facets and totals come from the first pass, so rescoring never changes a count.
  • Rescoring never changes which documents matched the query.
  • Paging inside the window counts results instead of carrying a cursor position, because a reordered window contains no position that a first-pass key can name. See Paging a rescored search.
  • Numbered pages stop at the window boundary, while cursors past the window continue in the order relevance ranked them.

When a search request specifies an explicit sort parameter, Exofind orders results by that sort. Exofind does not calculate relevance scores or evaluate ranking signals for explicit sorts. If an application provides a “sort by price” option, it must provide a way to switch back to relevance ordering by requesting a score sort. Exofind still appends tie breakers to explicit sort orders to resolve ties.

A knn clause scores documents based on vector distance, which uses a different scale from text matching. In a hybrid search combining both scoring methods with an or clause, Exofind adds the vector and text scores together without normalizing them. Because the appropriate balance depends on the specific embedding model and text data, you must measure your search results and tune the balance using a boost clause.

Adding a BM25 score to a cosine similarity assumes the two numbers mean something comparable. They do not, and the balance that works for one embedding model and one corpus does not carry to the next. Requiring both clauses to match is worse still: it drops the documents that only one method found, which is the recall that holding vectors beside text is for.

The fuse clause avoids both problems. Each ranking runs separately, and a document is scored by the sum of weight / (rankConstant + rank) over the rankings that reached it. Only the position a ranking gave a document is read, so no score has to be normalized into another and no scale can drown another out.

Fusing by rank leads to several specific behaviors:

  • A document that several rankings placed well outranks a document that one ranking placed first.
  • The result set is the union of what the rankings found, so a document only one ranking reached is still a result.
  • A ranking that answers badly contributes noise proportional to its weight, and cannot take over the result list. This bound is what makes it safe to fuse a ranking nobody vouched for, such as a retrieval by a vector built from what a person read before. A profile vector added into the query instead would hijack the search whenever the profile was wrong.
  • The clause matches the depth best results of each ranking and nothing else, so the total, the facet counts and paging are all bounded by depth, the way a knn clause is bounded by k.
  • The fused score is a sum of reciprocal ranks, close to 1 / rankConstant. A clause beside the fusion that also scores adds a different scale on top, which is the blend the fusion exists to avoid.

Relaxing changes the result set, not the ranking

Section titled “Relaxing changes the result set, not the ranking”

When a text search matches no documents, query relaxation can drop terms instead of returning an empty result set. The response reports which terms were dropped. Dropped terms still contribute to ranking: documents that contain a dropped term rank higher among the returned results. Relaxation alters which documents are eligible to be ranked, not the ranking mechanics themselves.

The following table summarizes where you configure each ranking component and when changes take effect:

ComponentConfiguration locationTakes effect
Length normalizationIndex definitionNext search
Field weightsIndex definition (overridable per search)Next search
Whole-value match (exact)Index definitionNewly indexed documents
Boost clausesSearch requestNext search
Rank fusion (fuse)Search requestNext search
Second-pass rescoring (rescore)Search requestNext search
Ranking signalsIndex definition, replaceable by search settings (a search adds its own on top)Next search on the node serving it, within the settings refresh interval elsewhere
Tie breakersIndex definition, replaceable by search settingsNext search on the node serving it, within the settings refresh interval elsewhere
Index-time synonymsIndex definitionNewly indexed documents
Query-time synonymsSearch settingsNext search on the node serving it, within the settings refresh interval elsewhere

Exofind evaluates most ranking components at query time, making ranking adjustments fast to test: update the definition, the search settings, or the search query and compare results immediately. Only exact requires reindexing documents. Changes to text analysis (how text is tokenized into words) require reindexing into a new index generation rather than modifying ranking configuration.

  • Field types - Reference for ranking, signals, and field-level settings.
  • Search API - Reference for text, boost, fuse, signals, rescore, and sort parameters.
  • Search an index - How-to guide for constructing search queries.
  • Tuning ranking - How-to guide for changing the order with boosts, ranking signals, tie breakers, and rescoring.
  • Searching from a search box - How-to guide for the user match mode, the join mode, and relaxation.
  • Signal fields - Explanation of how a value a ranking signal reads is refreshed without reindexing.

Exofind is built by Level Four AB and is available under the Apache License 2.0.