Dev guideRecipesAPI ReferenceChangelog
Dev guideRecipesUser GuidesNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Migrate boosting

Migrate boosting configurations from Optimizely Search & Navigation to Optimizely Graph, including filter boosting, decay functions, and weighted scoring.

Boosting changes the relevance score of search results so that certain content appears higher or lower. You can boost based on business rules, content freshness, popularity, or field importance. Both Search & Navigation and Optimizely Graph support boosting, but they work differently.

Key differences

Search & Navigation provides five boosting features. The following table shows whether each has a Graph equivalent.

Search & Navigation featureGraph equivalentStatus
BoostMatching (filter-based)boost parameter on filter operatorsSupported (different syntax)
Auto-boosting: decaydecay function on DateTime/Date fieldsPartial (different curve model, fewer parameters)
Auto-boosting: hit (popularity) boostNo equivalentNot supported (workaround available)
Unified weights and property boostingboost on individual field predicatesSupported (no Admin UI)
Boosting with attributesNo equivalentNot supported
No equivalentBOOST_ONLY ranking modeGraph only (scores using only boost values, ignoring text relevance)

Migration workflow

BoostMatching (filter-based boosting)

Search & Navigation's BoostMatching boosts results matching specific filter criteria. The following table shows how the BoostMatching settings compare between Search & Navigation and Graph.

Search & NavigationGraphNotes
Filter expression (x => x.InStock.Match(true))where predicate with operator (InStock: { eq: true })
Boost factor (Double, for example 2)boost parameter (Int, for example boost: 2)Graph accepts Int only. Scale fractional values (for example, 1.5 and 3.0 become 15 and 30).
Multiple .BoostMatching() calls_or clause with boost per operator
Combined filters (&)Both conditions in the same object with boost on one operator
Negative boost (factor < 1.0)Not supportedWorkaround: give other conditions a higher boost, or use _not to exclude.

The following is a BoostMatching example in Search & Navigation:

var results = client.Search<Car>()
    .For("Volvo")
    .BoostMatching(x => x.InStock.Match(true), 2)
    .BoostMatching(x => x.SalesMargin.GreaterThan(0.2), 2)
    .BoostMatching(x => x.NewModelComingSoon.Match(true)
                      & x.InStock.Match(true), 5)
    .GetResult();

The following is the same BoostMatching example in Graph:

{
  Car(
    locale: en,
    where: {
      _fulltext: { contains: "Volvo" },
      _or: [
        { InStock: { eq: true, boost: 2 } },
        { SalesMargin: { gt: 0.2, boost: 2 } },
        {
          NewModelComingSoon: { eq: true, boost: 5 },
          InStock: { eq: true }
        }
      ]
    }
  ) {
    items {
      Name
      InStock
      SalesMargin
      _score
    }
  }
}
📘

Note

The boost parameter is applied on individual filter operators (for example, eq, gt, like, contains), not on logical blocks like _and or _or.

Auto-boosting: time decay

Search & Navigation uses Weibull decay, and Graph uses Gaussian decay. These are different mathematical models, so the same parameter values produce different results. After migrating, test your queries and adjust scale and rate in Graph until the ranking meets your expectations.

🚧

Important

In Search & Navigation, decay always uses the document's last modified date (IChangeTrackable.Changed). This is hardcoded. In Graph, you can apply decay on any DateTime or Date field (for example, Changed, StartPublish, Created, or custom fields). To match Search & Navigation behavior, use the Changed field in Graph.

📘

Note

In Search & Navigation, UsingAutoBoost always includes hit boost when statistics are enabled, so hit boost affects your decay results. In Graph, decay is independent, so your migrated decay scores may differ even with the same parameters.

Search & Navigation provides two configuration methods:

  1. UsingAutoBoost() – Applies to all documents in the query.
  2. ForInstancesOf<T>().SetDecayParameters() – Applies per content type.

Graph has no convention system. Each content type needs its own decay configuration directly in the query.

The following table shows how the Auto-boosting settings compare between Search & Navigation and Graph.

Search & NavigationGraphNotes
decayScale/scale (TimeSpan)scale (Int, days only)Must be >= 0. Convert hours and minutes to days.
decayOrigin/origin (DateTime)origin (Date scalar)Formats: YYYY-MM-DD or YYYY-MM-DDThh:mm:ssZ. Default: now().
decayMinimum/minimum (Double, 0.0-1.0)rate (Float)Valid range: [0..1). Defaults differ: Search & Navigation 0.2, Graph 0.5.
decayOffset/offset (TimeSpan)No equivalentGraph decay starts immediately from the origin.
decayShape/shape (Double)No equivalentGraph uses Gaussian decay with a fixed curve shape.

Method 1: UsingAutoBoost() (applies to all documents)

Search & Navigation:

var results = client.Search<BlogPost>()
    .For("Banana")
    .UsingAutoBoost(
        decayScale: TimeSpan.FromDays(14),
        decayOrigin: DateTime.UtcNow,
        decayMinimum: 0.2,
    ).GetResultAsync();

Graph:

{
  BlogPost(
    where: {
      _fulltext: { contains: "Banana" },
      Changed: {
        decay: {
          scale: 14,
          rate: 0.2
        }
      }
    }
  ) {
    items {
      Name
      Changed
      _score
    }
  }
}

Method 2: ForInstancesOf<T>().SetDecayParameters() (per content type):

Search & Navigation:

client.Conventions
    .ForInstancesOf<BlogPost>()
    .SetDecayParameters(new DateDecayParameters(
        scale: TimeSpan.FromDays(60),
        minimum: 0.3,
        origin: new DateTime(2024, 1, 1)
    ));

Graph:

{
  BlogPost(
    where: {
      Changed: { decay: { origin: "2024-01-01", scale: 60, rate: 0.3 } }
    }
  ) {
    items { Name Changed _score }
  }
}
🚧

Important

If you use per-type conventions in Search & Navigation (for example, BlogPost decays over 60 days, NewsPage decays over 7 days), you need separate Graph queries for each content type. Merge the results in your application. You cannot directly compare _score values from different queries, so you may need to adjust scores before sorting.

Auto-boosting: hit (popularity) boost

Search & Navigation's hit boost is automatic. It tracks user clicks on search results and boosts frequently clicked documents in future searches.

Graph does not have this feature. Graph search tracking only logs data and does not use click data in scoring.

As a workaround, you can collect click data from your own tracking system, store click counts in a numeric field on your content model (for example, NumClicks), and use the factor operator to boost by that field.

{
  BlogPost(
    where: {
      _fulltext: { contains: "Banana" },
      NumClicks: {
        gt: 1,
        factor: {
          value: 10.0,
          modifier: SQRT
        }
      }
    }
  ) {
    items {
      Name
      NumClicks
      _score
    }
  }
}

For more details about the factor operator and modifiers, see Graph Boosting documentation.

Unified weights and property boosting

In Search & Navigation, property boosting is used with UnifiedSearch to search across all content types. You can configure weights using the UsingUnifiedWeights() API or the Admin UI at Search & Navigation > Configure > Boosting.

In Graph, to search across all content types, query with Content. Graph has no Admin UI and no weight system. Use the boost parameter directly in each query.

The following table shows how the properties compare between Search & Navigation and Graph.

Search & Navigation propertyGraph equivalent on ContentNotes
SearchTitleboost on NameName: { contains: "...", boost: 4 }
SearchTextNo direct mappingQuery specific content types instead
SearchSummaryNo direct mappingQuery specific content types instead
SearchAttachmentNo direct mappingQuery specific content types instead

The following is a unified weights example in Search & Navigation:

var weights = new UnifiedWeightsValues()
{
    SearchTitle = 4.0,
    SearchText = 3.0,
    SearchSummary = 2.0,
    SearchAttachment = 1.0
};

var result = client.UnifiedSearch(Language.English)
    .For("Beethoven")
    .UsingUnifiedWeights(weights)
    .GetResult();

The following is a unified weights example using Content in Graph. Only Name maps to Search & Navigation's SearchTitle.

{
  Content(
    locale: en,
    where: {
      Name: { contains: "Beethoven", boost: 4 }
    }
  ) {
    items {
      Name
      _score
    }
  }
}

The following is a unified weights example on specific content type in Graph, where you can boost all fields.

{
  ArticlePage(
    locale: en,
    where: {
      _or: [
        { Name: { contains: "Beethoven", boost: 4 } },
        { MainBody: { contains: "Beethoven", boost: 3 } },
        { Summary: { contains: "Beethoven", boost: 2 } },
        { AttachmentText: { contains: "Beethoven", boost: 1 } }
      ]
    }
  ) {
    items {
      Name
      _score
    }
  }
}
📘

Note

Field names (for example, MainBody, Summary, AttachmentText) depend on your content model. Check your Graph schema for the correct field names.

Boost with attributes

Search & Navigation's boosting with attributes is specific to Product Recommendations. It boosts search results based on product attributes and personalization signals.

Graph does not have this feature. If you use this feature, handle the personalization logic in your application layer.