5

I have few records in Solr index.

  1. Bachelor of Nursing
  2. Bachelor of Nursing (Honours)

My requirement is that when I want to search Bachelor of Nursing then Bachelor of Nursing should display first and then Bachelor of Nursing (Honours) because Bachelor of Nursing have the exact match.

I have created below query for Solr

(((name_t_en:"Bachelor of Nursing")^3.0
OR (name_t_en:"*Bachelor*")^2.5 OR (name_t_en:"*Nursing*")^2.5 OR (keywords_t_en:"*Bachelor*")^2.0 OR (keywords_t_en:"*Nursing*")^2.0)  
)

but I am not getting result in proper way which I want.

While I am getting results, I am using below code in Visual Studio:

var namePredicate = PredicateBuilder.True<ContentPageSearchModel>();
var contentPredicate = PredicateBuilder.True<ContentPageSearchModel>();
var NamePredicate = PredicateBuilder.True<ContentPageSearchModel>();
var ExactNamePredicate = PredicateBuilder.True<ContentPageSearchModel>();
ExactNamePredicate = ExactNamePredicate.Or(item => item.Name == text).Boost(3.0f);
foreach (var word in terms)
{
    NamePredicate = NamePredicate.And(item => item.Name.Contains(word).Boost(2.5f));
    contentPredicate = contentPredicate.Or(item => item.Keywords.Contains(word).Boost(2.0f));
}
namePredicate = ExactNamePredicate.Or(NamePredicate).Or(contentPredicate);
5

Something like this has worked for me. Beyond the boosting, the important part is to have the exact match Or the loose match. exactPredicate.Or(loosePredicate); That will build the proper SOLR query.

{
    var parentPredicate = PredicateBuilder.True<ContentPageSearchModel>();
    var exactPredicate = PredicateBuilder.False<ContentPageSearchModel>();
    var loosePredicate = PredicateBuilder.False<ContentPageSearchModel>();


    exactPredicates = exactPredicates.Or(i => i.Title.Contains(query)).Boost(40); 

    // you can use the wildcard search or Contains. 
    foreach (var word in query.QueryText.Split(' '))
    {
        if (word.Length > 2)
            loosePredicate = loosePredicate.Or(i => i.Title.MatchWildcard("*" + word + "*").Boost(-100f));
    }

    // don't use both of these
    foreach (var word in query.QueryText.Split(' '))
    {
        if (word.Length > 2)
            loosePredicate = loosePredicate.Or(i => i.Title.Contains(word));
    }

    parentPredicate = exactPredicate.Or(loosePredicate);

}
  • Thanks, Chris. I am not sure why it is not working for me. – Swati Gupta Sep 1 at 17:36
  • What does the solr query look like? – Chris Auer Sep 1 at 20:15
  • You can find the SOLR query in the search.log file in the logs folder – Chris Auer Sep 3 at 2:17
1

I have implemented the same functionality with the following code in sitecore 9 update 2

 if (sortBy !="date")
            {
                string termFreq = GetTermFrequency("suggestiontitle_t", searchText);
                var query = context.GetQueryable<SearchResultModel>()
                     .Where(i => i.NoIndex == false && (i.PageTitle.Contains(searchText).Boost(5.0f) || i.SearchDescription.Contains(searchText).Boost(4.0f) || i.KeyWords.Contains(searchText).Boost(3.0f) || i.SContent.Contains(searchText).Boost(2.0f))).OrderByDescending(q =>q[termFreq]);
                totalCount = query.Count();
                Results = query?.Skip((page - 1) * count).Take(count).ToList();
            }

 private static string GetTermFrequency(string fieldName, string searchText)
    {
        return string.Format("termfreq({0},'{1}')", fieldName, searchText);
    }
  • I need to boost exact match first – Swati Gupta Aug 31 at 2:21
  • it is a workaround, this problem should be solved on Solr side (best practice) – x3mxray Aug 31 at 4:20
1

I have this working through the below code. Basically I'm doing the following:

  1. Splitting the search term into words and getting the entire length
  2. Building one predicate for entire search term together and doing a boost by (length * length)
  3. Building predicates for each of the word and then doing an Or with the above predicate
var tokens = request.SearchTerm.Split(' ');
var length = tokens.Length;

float allWordsBoost = (float)length * length;
predicate = predicate.And(item => item.SearchTerms.Contains(request.SearchTerm).Boost(allWordsBoost));

var termsPredicate = PredicateBuilder.True<ContentPageSearchModel>();

var eachTermPredicate = PredicateBuilder.True<ContentPageSearchModel>();


for (int i = 0; i < length; i++)
{
   float b = (float)length - i;
   var word = tokens[i];
   eachTermPredicate = eachTermPredicate.Or(Item => 
        Item.SearchTerms.Contains(word).Boost(b));
}

termsPredicate = termsPredicate.And(eachTermPredicate);

predicate = predicate.Or(termsPredicate);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.