Вес/приоритет полнотекстового поиска PostgreSQL в поисковых системах

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

Вопрос:

Я использую полнотекстовый поиск в PostgreSQL через Django.

Я хочу связать веса с поисковыми системами. Я знаю, что можно связать разные веса с разными полями, но я хочу иметь разный вес в поисковых системах.

Пример:

 from core.models import SkillName
vector = SearchVector(
    "name",
)
search = SearchQuery("Java") | SearchQuery("Spring")
search_result = (
    SkillName.objects.all()
        .annotate(search=vector)
        .filter(search=search)
        .annotate(rank=SearchRank(vector, search))
        .order_by("-rank")
)
for s in search_result.distinct():
    print(f"{s} rank: {s.rank}")
 

И теперь я хочу, чтобы «Java» была более важной, чем «Весна», и соответственно получала рейтинг.
Я думаю, я мог бы выполнить 2 разных поиска и умножить ранги на коэффициенты, но есть ли лучший способ ?

Действительно ли так странно хотеть связать разные приоритеты с поисковыми системами ?

Сгенерированный SQL для справки, я, честно говоря, не думаю, что это возможно в Django прямо сейчас, в любом случае, и нам может понадобиться помощь гуру PostgreSQL.

 SELECT DISTINCT "core_skillname"."id",
                "core_skillname"."name",
                to_tsvector(COALESCE("core_skillname"."name", '')) AS "search",
                ts_rank(to_tsvector(COALESCE("core_skillname"."name", '')), (plainto_tsquery('Java') || plainto_tsquery('Spring'))) AS "rank"
FROM "core_skillname"
WHERE to_tsvector(COALESCE("core_skillname"."name", '')) @@ (plainto_tsquery('Java') || plainto_tsquery('Spring'))
ORDER BY "rank" DESC;```
 

Ответ №1:

Для применения рангов с весами не требуется двух запросов, достаточно двух вложенных выражений в одном запросе.

 SELECT DISTINCT "core_skillname"."id",
                "core_skillname"."name",
                to_tsvector(COALESCE("core_skillname"."name", '')) AS "search",
                ts_rank(to_tsvector(COALESCE("core_skillname"."name", '')), plainto_tsquery('Spring'))  
                ts_rank(to_tsvector(COALESCE("core_skillname"."name", '')), plainto_tsquery('Java')) * 1.5 AS "rank"
FROM "core_skillname"
WHERE to_tsvector(COALESCE("core_skillname"."name", '')) @@ (plainto_tsquery('Java') || plainto_tsquery('Spring'))
ORDER BY "rank" DESC;
 

Поскольку так легко поцарапать свой собственный зуд, зачем изобретать для этого какой-то другой механизм? Когда веса являются частью таблицы, а не частью запроса, вы действительно не могли бы сделать это таким образом, поэтому его собственный механизм имеет больше смысла.