Search code examples
c#solrpredicatesolr-boost

C# Solr boost not being applied to generated query


I'm using Solr 7.5 with Sitecore 9.2. I have some complex code that generates a search query, which I'm now trying to apply boosting to to prioritize page items over media assets (the relevant lines begin at isAssetPredicate....

    public override Expression<Func<T, bool>> Build()
    {
        string query = _values.FirstOrDefault();
        string queryLower = query.ToLower();

        if (string.IsNullOrEmpty(query)) return null;

        var predicate = PredicateBuilder.False<T>();

        var exactPredicate = PredicateBuilder.False<T>();
        exactPredicate = exactPredicate.Or(x => x.ItemPartNumberLower.Contains(queryLower)).Boost(90);
        exactPredicate = exactPredicate.Or(x => x.TitleLower.Contains(queryLower)).Boost(99);
        exactPredicate = exactPredicate.Or(x => x.Keywords.Contains(queryLower)).Boost(9);
        exactPredicate = exactPredicate.Or(x => x.FileType.Contains(queryLower)).Boost(9);
        exactPredicate = exactPredicate.Or(x => x.AggregatedSearchFields.Contains(queryLower)).Boost(9);

        var fuzzyPredicate = PredicateBuilder.False<T>();
        fuzzyPredicate = fuzzyPredicate.Or(x => x.ItemPartNumberLower.Contains(queryLower)).Boost(90);
        fuzzyPredicate = fuzzyPredicate.Or(x => x.TitleLower.Contains(queryLower)).Boost(99);
        fuzzyPredicate = fuzzyPredicate.Or(x => x.Keywords.Contains(queryLower)).Boost(9);
        fuzzyPredicate = fuzzyPredicate.Or(x => x.FileType.Contains(queryLower)).Boost(9);
        fuzzyPredicate = fuzzyPredicate.Or(x => x.AggregatedSearchFields.Contains(queryLower)).Boost(9);

        // try searching for each term separately rather than exact match
        var queryParts = queryLower.Trim().Split(' ');
        if (queryParts.Length > 1)
        {
            var partsPredicate = PredicateBuilder.True<T>();
            var fuzzyPartsPredicate = PredicateBuilder.False<T>();
            foreach (var part in queryParts)
            {
                if (String.IsNullOrEmpty(part)) continue;

                var subQuery = PredicateBuilder.False<T>();
                subQuery = subQuery.Or(x => x.TitleLower.Contains(part)).Boost(99);
                subQuery = subQuery.Or(x => x.ItemPartNumberLower.Contains(part)).Boost(95);
                subQuery = subQuery.Or(x => x.Keywords.Contains(part)).Boost(80);
                subQuery = subQuery.Or(x => x.FileType.Contains(part)).Boost(1);
                subQuery = subQuery.Or(x => x.AggregatedSearchFields.Contains(part)).Boost(1);

                partsPredicate = partsPredicate.And(subQuery);

                var subQueryFuzzy = PredicateBuilder.False<T>();
                subQueryFuzzy = subQueryFuzzy.Or(x => x.TitleLower.Like(part)).Boost(99);
                subQueryFuzzy = subQueryFuzzy.Or(x => x.ItemPartNumberLower.Like(part)).Boost(95);
                subQueryFuzzy = subQueryFuzzy.Or(x => x.Keywords.Like(part)).Boost(80);
                subQueryFuzzy = subQueryFuzzy.Or(x => x.FileType.Like(part)).Boost(1);
                subQueryFuzzy = subQueryFuzzy.Or(x => x.AggregatedSearchFields.Like(part)).Boost(1);

                fuzzyPartsPredicate = fuzzyPartsPredicate.Or(subQueryFuzzy);
            }
            exactPredicate = exactPredicate.Or(partsPredicate).Boost(1);
            fuzzyPredicate = fuzzyPredicate.Or(fuzzyPartsPredicate).Boost(1);
        }

        var queryPredicate = PredicateBuilder.False<T>();
        queryPredicate = queryPredicate.Or(exactPredicate).Boost(99);
        queryPredicate = queryPredicate.Or(fuzzyPredicate).Boost(1);

        predicate = predicate.Or(queryPredicate);

        if (HasAttribute(FieldType.Title))
        {
            predicate = predicate.Or(GetQueryExpression(FieldType.Title, query));
        }
        if (HasAttribute(FieldType.Description))
        {
            predicate = predicate.Or(GetQueryExpression(FieldType.Description, query));
        }

        if (HasAttribute(FieldType.Body))
        {
            predicate = predicate.Or(GetQueryExpression(FieldType.Body, query));
        }
        else if (QueryFormatter.NeedsFormatting(query))
        {
            predicate = predicate.Or(x => x.Content.MatchWildcard(QueryFormatter.FormatQuery(query)));
        }
        else
        {
            predicate = predicate.Or(x => x.Content.Like(query, SiteSettings.MinimumSimilarity));
        }

        var isAssetPredicate = PredicateBuilder.True<T>().And(x => x.IsAsset.Boost(0.0000001f)).And(predicate).Boost(0.0000001f);
        var isPagePredicate = PredicateBuilder.True<T>().And(x => !x.IsAsset.Boost(9999f)).And(predicate).Boost(9f);

        var finalPredicate = PredicateBuilder.True<T>();
        finalPredicate = finalPredicate.Or(isAssetPredicate.Boost(0.1f)).Boost(0.1f);
        finalPredicate = finalPredicate.Or(isPagePredicate.Boost(9f)).Boost(9f);

        return finalPredicate;
    }     

As you can see I've put boosting in multiple places (I've tried it both within the predicate and outside the predicate separately as well as together) but none of it is getting applied in the query:

?q=(((c_is_asset_b:(True)^0.01 AND (c_item_part_number_lower_s:(*systemkit*) OR c_title_lower_s:(*systemkit*) OR c_keywords_t:(*systemkit*) OR c_file_type_s:(*systemkit*) OR c_aggregated_search_fields_s:(*systemkit*) OR (c_item_part_number_lower_s:(*systemkit*) OR c_title_lower_s:(*systemkit*) OR c_keywords_t:(*systemkit*) OR c_file_type_s:(*systemkit*) OR c_aggregated_search_fields_s:(*systemkit*)) OR (title_t:(systemkit~100000))^2.5 OR (summary_t:(systemkit~100000))^1.5 OR _content:(systemkit~100000))) OR ((-c_is_asset_b:(True)  *:*)^9999 AND (c_item_part_number_lower_s:(*systemkit*) OR c_title_lower_s:(*systemkit*) OR c_keywords_t:(*systemkit*) OR c_file_type_s:(*systemkit*) OR c_aggregated_search_fields_s:(*systemkit*) OR (c_item_part_number_lower_s:(*systemkit*) OR c_title_lower_s:(*systemkit*) OR c_keywords_t:(*systemkit*) OR c_file_type_s:(*systemkit*) OR c_aggregated_search_fields_s:(*systemkit*)) OR (title_t:(systemkit~100000))^2.5 OR (summary_t:(systemkit~100000))^1.5 OR _content:(systemkit~100000)))) AND _val_:("recip(ms(NOW, c_date_tdt), 3.16e-11, 100, 1.8)"))&start=0&rows=100&fq=((((-c_alltemplates_sm:(b906556e0ab94174952026c282933569)  *:*) OR end_date_tdt:[2021-09-13T17:25:05.524Z TO *] OR start_date_tdt:[2021-09-13T17:25:05.524Z TO *]) AND c_searchable_b:(True)) AND _language:(en))&fq=_indexname:(sitecore_web_index)&facet=true&facet.field=c_locations_sm&f.c_locations_sm.facet.mincount=1&facet.field=c_architectures_sm&f.c_architectures_sm.facet.mincount=1&facet.field=c_topics_sm&f.c_topics_sm.facet.mincount=1&facet.field=c_content_type_s&f.c_content_type_s.facet.mincount=1&facet.field=c_file_type_s&f.c_file_type_s.facet.mincount=1&wt=xml

(there is some boosting in the Title and Summary, but not on the Is_Asset field that I'm trying to boost)


Solution

  • It turns out the issue was that boosting does not work on boolean fields. I changed the IsAsset field to a string ("true" or "false") and was then able to implement boosting

    var isAssetPredicate = PredicateBuilder.True<T>().And(predicate).And(x => x.IsAssetStr.Equals("true").Boost(0.001f));
    var isPagePredicate = PredicateBuilder.True<T>().And(predicate).And(x => x.IsAssetStr.Equals("false").Boost(999f));