Как стать автором
Обновить

Поиск через sphinx в django 1.6 admin

Время на прочтение3 мин
Количество просмотров12K
Задача: реализовать полнотекстовый поиск в админке django.
Пример модели, по которой будем делать поиск:
class Movie(models.Model):
    title_en = models.CharField(max_length=255, null=True)
    title_ru = models.CharField(max_length=255, null=True)
    year = models.PositiveSmallIntegerField(null=True)


Установка и настройка sphinx


Ставим sphinx через любой пакетный менеджер, у меня под рукой только FreeBSD, поэтому я ставлю из портов.
cd /usr/ports/textproc/sphinxsearch
make install clean

В статье используется версия 0.9.9, с ней точно будет работать пакет django-sphinx, на других версиях не проверял.
Создаем конфиг /usr/local/etc/sphinx.conf
Скрытый текст
# Источник
source movies_src
{
    type = pgsql # или mysql
    sql_host = 127.0.0.1
    sql_user = sphinx
    sql_pass = sphinxpass
    sql_db = dbname
    sql_port = 5432
    sql_query = select id, title_en, title_ru, year from movies_movie # запрос, который выбирает данные для индекса
    sql_attr_uint = year
}

# Настройки индекса
index movies
{
    source = movies_src
    path = /var/data/search/movies
    docinfo = extern
    charset_type = utf-8
    morphology = stem_enru # подключаем русскую и английскую морфологию
}

# Настройки демона
searchd
{
    listen = 9312
    log = /var/log/searchd.log
    query_log = /var/log/searchd.query.log
    read_timeout = 3
    client_timeout = 10
    max_children = 15
    pid_file = /var/run/sphinxsearch/searchd.pid
    max_matches = 1000
    seamless_rotate = 1
    preopen_indexes = 1
    unlink_old = 1
    mva_updates_pool = 1M
    max_packet_size = 8M
}


Создаем лог-файлы и директории из конфига, делаем им chown _sphinx. Если вы тоже используете postgres не забудьте добавить соответствующую строчку в pg_hba.conf, чтобы сфинкс смог подключиться.
Выдаем юзеру права на чтение из нужной нам таблицы. Привожу пример для постгреса, чтобы не гуглить лишний раз:
GRANT CONNECT ON DATABASE mydb TO sphinx;
GRANT USAGE ON SCHEMA public TO sphinx;
GRANT SELECT ON movies_movie TO sphinx;

Запускаем индексатор и ставим его в крон
/usr/local/bin/indexer --config /usr/local/etc/sphinx.conf  --rotate --all >/dev/null 2>&1

Запускаем sphinx
/usr/local/etc/rc.d/sphinxsearch start

Интеграция с django


Ставим пакет django-sphinx
pip install django-sphinx

Добавляем 'djangosphinx' в INSTALLED_APPS
Прописываем настройки в settings.py
SPHINX_API_VERSION = 0x116 # для sphinx 0.9.9+
SPHINX_PORT = 9312
SPHINX_SERVER = '127.0.0.1'

Добавляем в модель Sphinx-менеджер
class Movie(models.Model):
    search = SphinxSearch(
        index='movies',
        weights={
            'title_en': 100,
            'title_ru': 100,
        }
    )

Проверяем что полнотекстовый поиск работает.
>>> Movie.search.query(u'зеленый').order_by('year')[0]
<Movie: The Green Mile (1999) - Зеленая миля>

Поиск через sphinx в админке


У django-sphinx как бы есть свой класс SphinxModelAdmin, который позволяет использовать сфинкс в штатном поиске админки.
Но вот что пишет сам автор про эту фичу:
  • Only shows your max sphinx results (defaults to 1000)
  • Filters currently don't work.
  • This is a huge hack, so it may or may not continue working when Django updates.

Такое нам не подходит, так что придется допиливать.
В django 1.6 у класса ModelAdmin появился метод get_search_results, позволяющий переопределить встроенный механизм поиска.
Документация: docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_search_results
Его и будем использовать.
У меня получился такой класс:
class SphinxModelAdmin(admin.ModelAdmin):
    def get_search_results(self, request, queryset, search_term):
        if search_term:
            sphinx_queryset = self.model.search.query(search_term)
            doc_ids = [doc.pk for doc in sphinx_queryset]
            queryset = queryset.filter(pk__in=doc_ids)
            return queryset, True
        else:
            return super(SphinxModelAdmin, self).get_search_results(
                request, queryset, search_term
            )

Этот способ не теряет фильтры и сортировки админки, мы просто сужаем область поиска до документов, найденных в сфинксе.

Использовать так:
class MovieAdmin(SphinxModelAdmin):
    pass

Проверяем что поиск правильно работает.

Внешний вид — django-grappelli

Минусы данного решения:
Django 1.6 на момент написания топика находится в бете.

Ссылочки:
sphinxsearch.com
github.com/dcramer/django-sphinx
vostryakov.ru/blog/28-sphinx-11-django-postgresql
docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_search_results
Теги:
Хабы:
Всего голосов 17: ↑17 и ↓0+17
Комментарии12

Публикации

Истории

Работа

Python разработчик
115 вакансий

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань