Частичный поиск по ключевым словам и рейтинг - PullRequest
0 голосов
/ 02 апреля 2019

Используя Django и Postgres, у меня есть модель инвестиционного холдинга, такая как:

class Holding(BaseModel):    
    name = models.CharField(max_length=255, db_index=True)
    symbol = models.CharField(max_length=16, db_index=True)
    fund_codes = ArrayField(models.CharField(max_length=16), blank=True, default=list)
    ...

, которая содержит список из примерно 70 тыс. Долей США / CAN, взаимных фондов.Я хочу создать функцию автозаполнения поиска, которая расставляет приоритеты 1) ранжирование точного совпадения symbol или fund_codes, затем 2) близкие совпадения на symbol, затем 3) полнотекстовый поиск удержания name.

Если у меня есть вектор поиска, который добавляет больший вес к symbol и fund_codes:

from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
from django.db.models import F, Func, Value

vector = SearchVector('name', weight='D') + \
         SearchVector('symbol', weight='A') + \
         SearchVector(Func(F('fund_codes'), Value(' '), function='array_to_string'), weight='A')

Затем, поиск 'MA'

Investment.objects \
    .annotate(document=vector, rank=SearchRank(vector, query)) \
    .filter(document__icontains='MA') \
    .order_by('-rank') \
    .values_list('name', 'fund_codes', 'symbol', 'rank',)

Не дает результатов, которые мне нужны.Мне нужна MA (Mastercard) в качестве верхнего списка, затем MAS (Masco Corp) и т.д. ... Затем списки, содержащие 'MA' в поле name.

Я также посмотрел на переопределение SearchQueryс:

class MySearchQuery(SearchQuery):
    def as_sql(self, compiler, connection):
        params = [self.value]
        if self.config:
            config_sql, config_params = compiler.compile(self.config)
            template = 'to_tsquery({}::regconfig, %s)'.format(config_sql)
            params = config_params + [self.value]
        else:
            template = 'to_tsquery(%s)'
        if self.invert:
            template = '!!({})'.format(template)
        return template, params

Но все равно не получаю нужных мне результатов.Любые предложения о том, как я должен подходить к поисковой функциональности в этом случае использования?Возможно объединить точный поисковый запрос и полнотекстовый поисковый запрос?

1 Ответ

0 голосов
/ 27 мая 2019

Вам нужно передать параметр нормализации. Это даст более высокий рейтинг именам, которые точно совпадают. Необработанный запрос выглядит следующим образом:

SELECT id, name, symbol, func_codes, 
ts_rank_cd(to_tsvector(func_codes), to_tsquery('MA'), 2 ) as rank 
FROM Holding
ORDER BY rank DESC
LIMIT 100;

Обратите внимание, что я передал параметр нормализации https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-RANKING


Как это сделать в Django?

Я считаю, что django еще не поддерживает прохождение нормализации. Я вижу открытый билет на это, но его 2 года. Возможно, никто еще не работал над этим.
https://code.djangoproject.com/ticket/28194

Вы можете использовать необработанный запрос сейчас. Смотрите официальную документацию о том, как: https://docs.djangoproject.com/en/2.2/topics/db/sql/

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