Skip to main content
Weaviate Docs (migrated from docs.weaviate.io) Docs

Search documentation

Type to search this documentation.

On this pageOverview

Boost

Boost soft-ranks search results: it promotes or demotes matching documents without removing them from the result set. Matching documents move up. Non-matching documents stay in the results but rank lower.

Apply boost to vector, hybrid, BM25, near-text, near-vector, near-object, near-image, and near-media queries.

A boost is a post-retrieval rescorer:

  1. The primary search (vector, hybrid, BM25, ...) fetches depth candidate results. Set depth higher than offset + limit if you want boost to consider candidates beyond the first page.
  2. The boost scorer rescores those candidates in memory by evaluating each condition per candidate, normalizing per result set, and blending with the primary score. There are no new index queries. The cost is per-candidate in-memory scoring, not extra shard fan-out. Both primary and boost scores are min-max normalized into [0, 1] before blending, and the final score is renormalized to [0, 1].
  3. The user's original offset and limit are applied after the re-sort.

A boost is one or more conditions, blended into a single rescore. Every condition is one of: filter, property value, time decay, or numeric decay.

Score is 1 if the result matches the filter, 0 if not. Non-matching documents stay in the result set but rank lower than matching ones. Supported filter operators: Equal, NotEqual, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, And, Or, Not. (Like, IsNull, geo operators, and ref-path filters are not supported in boost conditions.)

Python
# Promote articles in the "research" category without filtering others out.response = articles.query.near_text(    query="transformer architectures",    limit=5,    boost=Boost.filter(        Filter.by_property("category").equal("research"),        weight=0.5,    ),    return_properties=["title", "category"],)for o in response.objects:    print(o.properties["category"], "-", o.properties["title"])

Continuous score proportional to a numeric property's value (likes, downloads, popularity, ...). The raw value is optionally modified, then min-max normalized to [0, 1] across the result set.

The name argument is required, only numeric properties (int, number) are supported.

Modifier Effect When to use
NONE (default) score = value Values in a narrow range.
LOG1P score = log(1 + value) Long-tail dampening (e.g. download counts from 5 to 5_000_000).
SQRT score = sqrt(value) Milder long-tail dampening.
Python
# Bias toward articles with more `likes`. LOG1P dampens the long tail so a# single 5-million-likes outlier doesn't dominate.response = articles.query.near_text(    query="transformer architectures",    limit=5,    boost=Boost.numeric_property(        "likes",        modifier=Boost.Modifier.LOG1P,        weight=0.7,    ),    return_properties=["title", "likes"],)for o in response.objects:    print(o.properties["likes"], "-", o.properties["title"])

For "closer to a specific value is better" instead of "higher is better", use numeric decay below.

Continuous [0, 1] score that decays with distance from an origin time. The canonical use case is "boost more recent documents".

Parameter Required Notes
property Yes Name of a date property.
origin No "now" (default), a datetime, or an ISO string.
scale Yes Distance at which the score equals decay. Accepts a timedelta or duration string ("7d", "6h", "30m").
offset No Distance below which the score is exactly 1. Default 0.
curve No EXPONENTIAL (default), GAUSSIAN, or LINEAR. See Curves below.
decay No Score at scale distance. Default 0.5. Range (0, 1].
Python
# Score decays exponentially over time. "30d scale" + decay=0.5 means an# article that's 30 days old gets half the score of one published "now".response = articles.query.near_text(    query="transformer architectures",    limit=5,    boost=Boost.time_decay(        "published",        origin="now",        scale=timedelta(days=30),        curve=Boost.Curve.EXPONENTIAL,        decay=0.5,        weight=0.6,    ),    return_properties=["title", "published"],)

Like time decay but for numeric (int, number) properties. Use this when "closer to X is better": prices near a target, distances near a coordinate, ages near a band. Same scale / offset / decay / curve semantics as time decay, with all values expressed as numbers.

scale must be > 0 and decay (if set) must be in (0, 1], same as time decay.

Python
# Score peaks at a target price and falls off symmetrically. Gauss gives a# bell-shaped falloff: items within `offset` of $49.99 score 1.0, items at# $59.99 (one scale away) score `decay`.response = articles.query.near_text(    query="transformer architectures",    limit=5,    boost=Boost.numeric_decay(        "price",        origin=49.99,        scale=10.0,        curve=Boost.Curve.GAUSSIAN,        decay=0.5,        weight=0.5,    ),    return_properties=["title", "price"],)

The three decay curves shape how score falls off with distance. At distance == 0 the score is always 1. At distance == scale the score is always exactly decay. Past scale they behave differently:

Curve Shape When to use
EXPONENTIAL (default) Heavy tail: score halves geometrically every scale past the origin. "Recency matters, but don't aggressively flatten older items to zero."
GAUSSIAN Bell curve: sharp falloff past scale. "Items close to the origin are great, items far away are nearly worthless."
LINEAR Straight line: score reaches zero at a finite distance past scale. "Predictable falloff with a clear cutoff."

Only these three values are accepted. Anything else is rejected at request time.

A boost must carry at least one and at most 20 conditions. Use Boost.blend(...) to combine multiple conditions into one rescore. Each condition can carry its own weight (default 1.0). The outer weight (default 0.5) controls how much the combined boost affects the final score.

final_score = (1 − weight) · primary_norm + weight · boost_norm
  • weight: the outer blending weight, in [0, 1]. Defaults to 0.5.
  • weight: 0 is a no-op: the boost short-circuits and primary results are returned unchanged.
  • Per-condition weight: a float defaulting to 1.0. Use it to balance multiple boosts ("recency twice as important as popularity").
  • Negative per-condition weight: demotes matching documents. They stay in the result set but rank lower than non-matching ones.
Python
# Combine two soft signals: recency (weight 2) + popularity (weight 1).# The outer weight=0.4 controls how much the blended rank affects the# final score; the inner weights are *per-condition* and balance each# other.response = articles.query.near_text(    query="transformer architectures",    limit=5,    boost=Boost.blend(        [            Boost.time_decay("published", origin="now", scale=timedelta(days=30), weight=2.0),            Boost.numeric_property("likes", modifier=Boost.Modifier.LOG1P, weight=1.0),        ],        weight=0.4,        depth=200,  # rescore the top 200 vector matches    ),    return_properties=["title", "likes", "published"],)

A condition with weight: -1.0 (or -2.0, etc.) reverses the effect: documents that match the condition rank below non-matching ones instead of above them. They are not removed. This is useful for deprioritizing (for example, surfacing drafts last without filtering them out).

Python
# A negative per-condition weight pushes matching documents DOWN — they# stay in the result set but lose ground against everything else. Use# this to deprioritize drafts without filtering them out entirely.response = articles.query.bm25(    query="transformer",    limit=5,    boost=Boost.blend(        Boost.filter(Filter.by_property("draft").equal(True), weight=-2.0),        weight=0.5,    ),    return_properties=["title", "draft"],)# The draft article is still in results, just no longer first.all_titles = [o.properties["title"] for o in response.objects]assert any("Draft" in t for t in all_titles)assert response.objects[0].properties["draft"] is False

depth controls the candidate pool. The primary search fetches depth results before the boost rescorer runs. After rescoring, the user's offset and limit are applied.

Property Value
Default 100
Operator override QUERY_BOOST_DEFAULT_DEPTH env var
Hard cap QUERY_MAXIMUM_RESULTS (cluster-wide limit)
Lower bound At least offset + limit, so boost always sees enough to fill the page
Accepted range ≥ 0, where 0 means "use the default"
  • Rerank: second-stage reranking with an external model.
  • Hybrid search: the BM25 / vector alpha blend.
  • Filters: hard filters (remove non-matching docs).
  • BM25: keyword search.

Have a question or feedback? Here's how to reach us.

Suggest an edit

Propose a replacement for this page. The site team reviews it before applying any changes.

Export
Documentation menu