user2195252
user2195252

Reputation: 99

How to create a custom rank based on Full Text Search Function SearchRank in Django?

I want to customize the rank results given by SearchRank by giving more weights to some courses based on the value of a field in the Course Model.

I want use the rank given by SearchRank:

vector=SearchVector('title', weight='A')+SearchVector('full_description', weight='B')
query = SearchQuery(search)
courses=Course.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by('-rank')

and Create a new one:

rank2=[course.rank*2 if course.field1==Value1 else course.rank for course in courses]

And use this new rank to order the courses:

courses.annotate(rank2=rank2).order_by('-rank2')

But this gives me the error:

AttributeError: 'list' object has no attribute 'resolve_expression

I also tried to modify the original rank before reordering again, but it seems to use the initial rank values vs. the new ones:

def adjust_rank(courses):
 courses_temp=courses
 for course in courses_temp:
     if course.field1==Value1:
         course.rank=course.rank*2
 return courses_temp

courses2=adjust_rank(courses).order_by('-rank')

What is the best way to do this ?

In the Postgresql documentation, I can read:

You can write your own ranking functions and/or combine their results with additional factors to fit your specific needs.

But I have no idea on how to do that.

I am using Django 1.11.1 and python 2.7.13

Upvotes: 0

Views: 1426

Answers (1)

Paolo Melchiorre
Paolo Melchiorre

Reputation: 6122

You can do it with one query, using conditional expression:

from django.db.models import Case, When, F
from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector

vector = SearchVector('title', weight='A') + SearchVector('full_description', weight='B')
query = SearchQuery(search)
rank = SearchRank(vector, query)

Course.objects.annotate(
    rank0=rank,
    rank1=Case(When(field1='Value1', then='rank0'), default=0.0),
    rank2=F('rank0') + F('rank1')
).filter(rank0__gte=0.3).order_by(-'rank2')

Upvotes: 3

Related Questions