django

Установка и интеграция solr с django под Ubuntu 12.04

  • четверг, 12 июня 2014 г. в 03:10:25
http://habrahabr.ru/post/225999/

imageimage

Введение


Как известно, на многих сайтах/веб-приложениях необходимо тем или иным образом реализовать поиск. Все хотят быстрый и качественный поиск. Разработчики помимо всего прочего хотят, чтобы поисковик был прост в установке и использовании. Так как речь идет о django, то перед нами встает ряд ограничений в реализации поиска (при условии, что в сутках 24 часа и дедлайны никто не отменял). Предлагаю вашему вниманию небольшой туториал о том, как поставить и максимально безболезненно интегрировать в django проект такой мощный поисковик, как apache solr. Всех заинтересованных прошу под кат.



Наши грабли


В прошлом у нас был не очень приятный опыт работы с django-sphinx. Сам sphinx отличный поисковик, django-sphinx тоже замечательная библиотека, но после django 1.3 приходится немного танцевать с бубном, чтобы завести весь этот стек. Но даже после того как все это настроено и работает остается ощущение, что все это лежит находится где-то там, отдельно от проекта, со своими индексами по крону и конфигами, не связанными с моделями на проекте. Да, там есть автогенератор конфигов, но завести его под 1.4+ не удалось, да и после каждой генерации пришлось бы править конфиги самого поисковика (searchd). В целом поиск django-sphinx работает, причем быстро и качественно, но поддерживать это не очень удобно, как и интегрировать в проект.

Как мы нашли для себя иголку в haystack


Вот настал черед нового проекта. И снова встал вопрос выбора поисковика. От django-sphinx мы сразу же отказались и стали искать альтернативное решение. Первая библиотека, на которую мы обратили внимание, это django-haystack, что неудивительно, т.к. это самая популярная библиотека для интеграции поисковиков в django. Посмотрев api, на ней и остановились. Нам обещали полную интеграцию с любым из предложенных поисковиков: elasticsearch, solr, whoosh, xapian. После беглого осмотра были приняты следующие решения:

  1. Whoosh исключили из-за отсутствия кучи мелких фич, некоторые из которых были необходимы для проекта. Да и поговаривают, что он по скорости проигрывает остальным вариантам.
  2. Xapian исключили после неудачной попытки интеграции стороннего бекенда.
  3. Осталось 2 варианта — elasticsearch и solr. Оба на java, оба на lucene, фичи практически идентичны. “Подбросив монетку” было решено использовать solr.



Больше граблей


Сразу скажу, что в данной статье описана в основном работа именно с solr, а не с haystack. Информацию по haystack можно найти в официальных доках, она хорошо изложена и дублировать ее здесь я не вижу смысла.

Библиотека выбрана, поисковик выбран. Пора приступать к работе. Первой же ошибкой была установка из официального репа ubuntu 12.04. В официальном репе версия solr 1.4, хотя документация haystack рекомендует версию 3.5+ во избежание оказий. Решили ставить сами. После серии проб и ошибок пришли к решению, которое отлично сработало как на локалках разработчиков, так и на тестовом и боевом серверах. Вот примерная последовательность действий:

  1. Ставим системные пакеты jre и jetty:
    apt-get install openjdk-7-jre-headless jetty
    
  2. Python либы:
    pip install pysolr django-haystack
    
  3. Немного “темной магии” для глобальной установки самого solr’а:
    #!/bin/sh
    #variables
    LIB_DIRECTORY="/opt/solr"
    CONF_DIRECTORY="/etc/solr"
    OLD_CONF_DIRECTORY="$LIB_DIRECTORY/example/solr/conf"
    
    #check if already installed
    if ( [ -d $LIB_DIRECTORY ] && [ -d $CONF_DIRECTORY ] ); then
        echo "solr is already installed"
        exit
    fi
    
    #install if not
    #download and unpack
    wget http://archive.apache.org/dist/lucene/solr/3.6.2/apache-solr-3.6.2.tgz
    tar -xvzf apache-solr-3.6.2.tgz
    
    #install
    mv apache-solr-3.6.2 $LIB_DIRECTORY
    mv $OLD_CONF_DIRECTORY $CONF_DIRECTORY
    ln -s $CONF_DIRECTORY $OLD_CONF_DIRECTORY
    
    #cleanup
    rm apache-solr-3.6.2.tgz
    
    echo "solr installed"
    



Конечно если вы не хотите ставить solr так “глобально”, то можно немного подкрутить скрипт и ставить в любую другую папку — solr работает сразу после разархивации без дополнительных танцев, просто мы хотели видеть конфиги в привычных местах и чтобы очередное “стороннее” приложение было там же, где и остальные.

В общем уже можно запускать и все будет работать:
cd /opt/solr/example/ && java -jar start.jar


Но не можем же мы так все оставить. Как же конфиги, переиндексация и нормальный запуск? Давайте по порядку.

Конфиги


В данном контексте нас интересует 2 конфига:

  1. /etc/solr/schema.xml — сама схема данных и прочая информация для индексации и поиска, связанная непосредственно с нашими данными. Этот конфиг необходимо обновлять каждый раз, когда вы меняете индексы у себя в проекте.
  2. /etc/solr/solrconfig.xml — настройки самого solr’а, т.е. модули, handler’ы и прочие настройки, которые напрямую не касаются данных. Этот конфиг вам может пригодиться, если вам нужны дополнительные фичи solr’а.


После обновления любого из конфигов необходимо ребутать solr, чтобы изменения вступили в силу. (На самом деле необязательно, можно ограничиться RELOAD, что будет явно правильней в боевых условиях. см wiki.apache.org/solr/CoreAdmin)
Для генерации schema.xml haystack поставляет замечательную команду build_solr_schema. Но у нее есть небольшой минус — при ее использовании нужно помнить куда надо класть конфиг, т.к. она либо принтит конфиг в консоль, либо в файл, если он указан. Можно немного поправить дело, если сделать собственную команду, полную копию build_solr_schema, просто указать дефолтное значение имени файла (в нашем случае это /etc/solr/schema.xml). Таким образом мы немного упростили жизнь разработчикам, ведь теперь достаточно только запустить эту команду и конфиг будет обновлен.

Переиндексация


В нашем случае есть 2 варианта как поддерживать актуальность индексов:

  1. “Классический вариант” — полная переиндексация раз в N минут. Единственный плюс такого подхода, который приходит в голову, это его простота. Минусов немного больше: при большой базе это долго, между переиндексациями данные могут стать неактуальными.
  2. “Атомарная переиндексация” — переиндексация каждого объекта по сигналам post_save, post_delete и т.д. Главным плюсом очевидно будет скорость независимо от размера бд. Немаловажно, что при таком подходе весь контроль переиндексации находится “на глазах” в коде проекта, а не в каком-то там кроне или в лучшем случае таске celery. Но и тут не без минусов: неактуальность данных при неправильной реализации и оверхед при вызове сигналов с переиндексацией. Последний устраняется вынесением в асинхронный таск (в нашем случае celery).


Мы выбрали второй вариант (никто не запрещает выбрать оба сразу) и для реализации воспользовались простым миксингом для моделей и парой тасков:

Миксин

class RefreshIndexMixin(object):
    #index - соответствующий индекс модели, например PostIndex или CarIndex
    def update_index(self, index):
        current_app.send_task('project.tasks.update_index', args=[self, index])

    def remove_index(self, index):
        current_app.send_task('project.tasks.remove_index', args=[self, index])


В модели соответственно достаточно вызвать update_index или remove_index в соответствующем сигнале.

Таски

from celery import shared_task


@shared_task
def update_index(obj, index):
    index().update_object(obj)


@shared_task
def remove_index(obj, index):
    index().remove_object(obj)


Нормальный запуск.


Мы повсеместно используем supervisor, поэтому в нашем случае долго думать не пришлось. Вот пример конфига для локалки/тестового сервера:

[program:solr]
command=java -jar start.jar
directory=/opt/solr/example/
stderr_logfile=/var/log/solr.error.log
stdout_logfile=/var/log/solr.log
autorestart=true

Почему именно для локалки/тестового? Потому что solr “из коробки” идет с собственной админкой, где можно посмотреть индексы, настройки и т.д., а так же производить всякие манипуляции с этими данными. На боевом сервере вы скорее всего захотите отказаться от такой фичи, поэтому вот команда запуска только на localhost’е на дефолтном порте:

command=java -Djetty.host=127.0.0.1 -Djetty.port=8983 -jar start.jar


Итог


Что мы имеем в сухом остатке:

  • мощный поисковый движок, который отлично интегрирован с django проектом
  • атомарное индексирование
  • легкое изменение любых настроек в рамках проекта
  • целый ворох дополнительных фич (faceting, more like this и т.д.), которые действительно работают


За то время, что мы используем эту связку, она показала себя отличнейшим образом со всех сторон. Пользователи и заказчик довольны быстрым и адекватным поиском на сайте. Для разработчиков наличие такого java-монстра практически незаметно, т.к. им нужны только индексы, пара команд manage.py и перезагрузка solr’а через supervisor.