Выполните полнотекстовый поиск с использованием двух моделей

#python #django #postgresql #full-text-search #django-queryset

#python #django #postgresql #полнотекстовый поиск #django-набор запросов

Вопрос:

У меня есть две модели Item и Owner :

 class Item(models.Model):
    name = models.CharField(max_length=255)
    owner = models.ForeignKey(
        Owner, related_name='owner_items',
        on_delete=models.CASCADE,
    )
    is_featured = models.BooleanField(
        choices=CHOICES, default=BOOL_NO
    )
    # ...
  

Я выполняю полнотекстовый поиск (на основе документов Django) в полях название элемента и описание. Версия PostgreSQL равна 10.

 search_vectors = (
    SearchVector('name', weight='A', config='english')  
    SearchVector('description', weight='B', config='english')
)
terms = [SearchQuery(term) for term in keyword.split()]
search_query = functools.reduce(operator.or_, terms)
search_rank = SearchRank(
    search_vectors, search_query, weights=[0.2, 0.4, 0.6, 1]
)
qs = Item.objects.all().annotate(
    rank=search_rank
).filter(rank__gte=0.2).order_by('-rank')
  

Я хочу также ввести поле Owner , name в уравнение, также немного повысить ранг, если is_featured равно true .

Перед выполнением этого поиска у меня есть Owner экземпляр model.

Комментарии:

1. если мой ответ решил ваш вопрос, примите его!

Ответ №1:

Вы можете добавить поле name из class Owner в search_vector , возможно, с другим weight и тем же config именем (это только гипотеза, потому что вы не указали определение модели владельца или данные).

Способ использовать is_featured в качестве дополнения для вашего rank может заключаться в том, чтобы добавить 1 (вы можете использовать другие значения), если это True так, а затем добавить его к SearchRank результату.

 from django.db import models
from django.db.models import Case, Value, When
from django.contrib.postgres.search import (
    SearchQuery, SearchRank, SearchVector,
)

search_vectors = (
    SearchVector('name', weight='A', config='english')  
    SearchVector('description', weight='B', config='english')  
    SearchVector('owner__name', weight='C', config='english')
)
terms = [SearchQuery(term) for term in keyword.split()]
search_query = functools.reduce(operator.or_, terms)
search_rank = SearchRank(
    search_vectors, search_query, weights=[0.2, 0.4, 0.6, 1]
)
qs = Item.objects.all().annotate(
    featured_boost=Case(
        When(is_featured=True, then=Value(1)),
        default=Value(0),
        output_field=models.IntegerField(),
    )
).annotate(
    rank=search_rank   featured_boost
).filter(rank__gte=0.2).order_by('-rank')