Indexes: Boosting



Assign a boost factor to an index-field

Applying a boost value to an index-field allows you to prioritize matching documents based on an index-field.


The index:

public class Orders_ByCountries_BoostByField : AbstractIndexCreationTask<Order>
{
    public class IndexEntry
    {
        // Index-field 'ShipToCountry' will be boosted in the map definition below
        public string ShipToCountry { get; set; }
        public string CompanyCountry { get; set; }
    }
    
    public Orders_ByCountries_BoostByField()
    {
        Map = orders => from order in orders
            let company = LoadDocument<Company>(order.Company)
            
            // Note: with current server version,
            // use 'select new' instead of 'select new IndexEntry' for compilation
            select new 
            {
                // Boost index-field 'ShipToCountry':
                // * Use method 'Boost', pass a numeric value to boost by 
                // * Documents that match the query criteria for this field will rank higher
                ShipToCountry = order.ShipTo.Country.Boost(10), 
                CompanyCountry = company.Address.Country
            };
    }
}
public class Orders_ByCountries_BoostByField_JS : AbstractJavaScriptIndexCreationTask
{
    public Orders_ByCountries_BoostByField_JS()
    {
        Maps = new HashSet<string>()
        {
            @"map('orders', function(order) {
                let company = load(order.Company, 'Companies')
                return {
                    ShipToCountry: boost(order.ShipTo.Country, 10),
                    CompanyCountry: company.Address.Country
                };
            })"
        };
    }
}
The query:

List<Order> orders = session
     // Query the index    
    .Query<Orders_ByCountries_BoostByField.IndexEntry, Orders_ByCountries_BoostByField>()
    .Where(x => x.ShipToCountry == "Poland" || x.CompanyCountry == "Portugal")
    .OfType<Order>()
    .ToList();

// Because index-field 'ShipToCountry' was boosted (inside the index definition),
// then documents containing 'Poland' in their 'ShipTo.Country' field will get a higher score than
// documents containing a company that is located in 'Portugal'.
List<Order> orders = await asyncSession
     // Query the index    
    .Query<Orders_ByCountries_BoostByField.IndexEntry, Orders_ByCountries_BoostByField>()
    .Where(x => x.ShipToCountry == "Poland" || x.CompanyCountry == "Portugal")
    .OfType<Order>()
    .ToListAsync();

// Because index-field 'ShipToCountry' was boosted (inside the index definition),
// then documents containing 'Poland' in their 'ShipTo.Country' field will get a higher score than
// documents containing a company that is located in 'Portugal'.
List<Order> orders = session.Advanced
     // Query the index 
    .DocumentQuery<Orders_ByCountries_BoostByField.IndexEntry, Orders_ByCountries_BoostByField>()
    .WhereEquals(x => x.ShipToCountry, "Poland")
    .OrElse()
    .WhereEquals(x => x.CompanyCountry, "Portugal")
    .OfType<Order>()
    .ToList();

// Because index-field 'ShipToCountry' was boosted (inside the index definition),
// then documents containing 'Poland' in their 'ShipTo.Country' field will get a higher score than
// documents containing a company that is located in 'Portugal'.
from index "Orders/ByCountries/BoostByField"
where ShipToCountry == "poland" or CompanyCountry == "portugal"

Assign a boost factor to the index-entry

Applying a boost value to the whole index-entry allows you to prioritize matching documents by content from the document.


The index:

public class Orders_ByCountries_BoostByIndexEntry : AbstractIndexCreationTask<Order>
{
    public class IndexEntry
    {
        public string ShipToCountry { get; set; }
        public string CompanyCountry { get; set; }
    }
    
    public Orders_ByCountries_BoostByIndexEntry()
    {
        Map = orders => from order in orders
            let company = LoadDocument<Company>(order.Company)
            
            select new IndexEntry()
            {
                ShipToCountry = order.ShipTo.Country,
                CompanyCountry = company.Address.Country
            }
            // Boost the whole index-entry:
            // * Use method 'Boost'
            // * Pass a document-field that will set the boost level dynamically per document indexed.  
            // * The boost level will vary from one document to another based on the value of this field.
           .Boost((float) order.Freight);
    }
}
public class Orders_ByCountries_BoostByIndexEntry_JS : AbstractJavaScriptIndexCreationTask
{
    public Orders_ByCountries_BoostByIndexEntry_JS()
    {
        Maps = new HashSet<string>()
        {
            @"map('orders', function(order) {
                let company = load(order.Company, 'Companies')
                return boost({
                    ShipToCountry: order.ShipTo.Country,
                    CompanyCountry: company.Address.Country
                }, order.Freight)
            })"
        };
    }
}
The query:

List<Order> orders = session
     // Query the index  
    .Query<Orders_ByCountries_BoostByIndexEntry.IndexEntry, Orders_ByCountries_BoostByIndexEntry>()
    .Where(x => x.ShipToCountry == "Poland" || x.CompanyCountry == "Portugal")
    .OfType<Order>()
    .ToList();

// The resulting score per matching document is affected by the value of the document-field 'Freight'. 
// Documents with a higher 'Freight' value will rank higher.
List<Order> orders = await asyncSession
     // Query the index  
    .Query<Orders_ByCountries_BoostByIndexEntry.IndexEntry, Orders_ByCountries_BoostByIndexEntry>()
    .Where(x => x.ShipToCountry == "Poland" || x.CompanyCountry == "Portugal")
    .OfType<Order>()
    .ToListAsync();

// The resulting score per matching document is affected by the value of the document-field 'Freight'. 
// Documents with a higher 'Freight' value will rank higher.
List<Order> orders = session.Advanced
     // Query the index  
    .DocumentQuery<Orders_ByCountries_BoostByIndexEntry.IndexEntry, Orders_ByCountries_BoostByIndexEntry>()
    .WhereEquals(x => x.ShipToCountry, "Poland")
    .OrElse()
    .WhereEquals(x => x.CompanyCountry, "Portugal")
    .OfType<Order>()
    .ToList();

// The resulting score per matching document is affected by the value of the document-field 'Freight'. 
// Documents with a higher 'Freight' value will rank higher.
from index "Orders/ByCountries/BoostByIndexEntry"
where ShipToCountry == "poland" or CompanyCountry == "portugal"

Automatic score-based ordering

  • By default, whenever boosting is involved, either via a dynamic query or when querying an index that has a boosting factor in its definition, the results will be automatically ordered by the score.

  • This behavior can be modified using the OrderByScoreAutomaticallyWhenBoostingIsInvolved
    configuration key.

  • Refer to section Get resulting score to learn how to retrieve the calculated score of each result.

Corax vs Lucene: boosting differences

  • Boosting features available:

    • When using Corax as the underlying indexing engine, you can only assign a boost factor to the index-entry.
      Applying a boost factor to an index-field is Not supported.

    • When using Lucene, you can assign a boost factor to both the index-field and the whole index-entry.

  • Algorithm used:
    Corax ranks search results using the BM25 algorithm.
    Other search engines, e.g. Lucene, may use a different ranking algorithm and return different search results.