Sort by relevancy and then by other field

Vote:
 

I have an issue with sorting in Find. I have a requirement that products in the search results should be sorted by relevancy and then by bought count. I am calculating bought count in a separate scheduled job and updating the field on the product content, so it is available for Find.

When I apply OrderBy on the bought count property, then relevancy is completely ignored. I found this thread: https://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=80937 where a custom extension method was used to force search by relevancy: https://gist.github.com/lindstromhenrik/9779858. I have tried it by ordering by score first and then by my bought count field:

search = search
    .OrderByScore()
    .ThenByDescending(x => x.BoughtCount);

Now relevancy sorting works, but sorting by bought count doesn't work anymore. If I understand correctly the reason is that sorting by score is too granular for my case. Is there a way to have 

Is there a way to fix this? It would be good if I could access the score, then I could create my own sorting "score".

#181481
Aug 22, 2017 9:50
Vote:
 

Hello

We are experienceing the same kind of issue here is our search request (somewhat simplyfied for this example):

client.Search<Event>().
search.For(query, q => { q.Query = query + "*"; })
search.OrderByScore().ThenBy(x => x.PeriodStart);


And the OrderByScore method is the same as original poster:

public static ITypeSearch<TSource> OrderByScore<TSource>(this ITypeSearch<TSource> search)
        {
            return new Search<TSource, IQuery>(search, context =>
                context.RequestBody.Sort.Add(new Sorting("_score")));
        }

When we apply the .OrderByScore() method only, we get the same sorting as if we don't use it, so the extension method seems to work as intended, however as soon as we add another criteria the relevance goes out the window. Is is hardcoded somewhere that we cannot chain the relevance with any other type of ordering?

We know we can change the ordering using boost matching and unified search, but this seems so trivial and we are not too keen to change into Unified search just for this

#182399
Sep 18, 2017 13:38
Vote:
 

I found out that it is impossible to order this way. I think the reason is that the score has values which almost doesn't repeat.

So for example:

  1. content 1 - score: 0.925
  2. content 2 - score: 0.91
  3. content 3 - score: 0.75
  4. etc.

In this example all scores are different and when all scores are different, you cannot add another sort as there is only one item to sort.

Instead of sorting by score, you should rely on the default sorting (which sorts by score).

#182409
Sep 18, 2017 14:58
Vote:
 

Actually, in our project, we stopped sorting by score. Instead, we made search more explicit by configuring find to use AND instead of OR when searching for multiple keywords. This way we got only most relevant records. Then we ordered those as we needed.

#182410
Sep 18, 2017 15:02
Vote:
 

Ok, thank you! This explains it! Of course it is not possible to sort with several different numbers the orderby cannot group the different items together.

Then, in theory we could make the sort after we picked up the response.

search.GetResult().OrderBy(x => x.PeriodStart)

That might screw up Pagination quite bad though.

One other idead I had was to add a relevance boost for items which is closer to todays date? So Find scores these items higher since the date is closer. However that wasn't possible since the BoostMatching method doesn't like dynamic values for it's boost property: https://world.episerver.com/forum/developer-forum/EPiServer-Search/Thread-Container/2015/6/custom-boost-matching-functionextension/

It works OK with some hardcoded value though:

                search = search.BoostMatching(x => x.PeriodStart.GreaterThan(DateTime.Now.AddHours(24)), 0.9);
                search = search.BoostMatching(x => x.PeriodStart.GreaterThan(DateTime.Now.AddDays(7)), 0.9);
                search = search.BoostMatching(x => x.PeriodStart.GreaterThan(DateTime.Now.AddMonths(1)), 0.9);
                search = search.BoostMatching(x => x.PeriodStart.GreaterThan(DateTime.Now.AddYears(1)), 0.9);

(Note for others, don't use, only testing code here)

Lastly I found AutoBoosting: http://world.episerver.com/documentation/developer-guides/find/NET-Client-API/searching/auto-boosting/

Maybe I can use the Decay feature but in reverse, dropping off the curve for documents in the future so the relevant issues are getting a higher score. But I've yet to find a way to configure the Autoboosting property for decay.

#182421
Sep 18, 2017 17:19