Использование Sphinx в сложных задачах поиска

Использование Sphinx в сложных задачах поискаИспользование Sphinx в сложных задачах поиска

Sphinx – это поисковый сервер / движок. Sphinx предназначен для практически всех поисковых задач. Он может искать по тексту по релевантности, умеет искать склоняемые слова («котят» – «котята»), масштабируется горизонтально и имеет удобный интерфейс. Мне недавно пришлось изучить данный комбайн для одной весьма специфической задачи.

Постановка задачи

котят часто продают...

На самом деле, в проекте много сложных для объяснения вещей (не совсем полное техническое задание занимает под 500 страниц 12-м шрифтом), но в сильно упрощённом виде всё выглядит следующим образом:

Имеется Classified система - система с объявлениями различных категорий. У всех объявлений одной категории имеется определённый набор полей различных типов. Набор полей изменяется из административной панели.

Например, для объявлений раздела “Авто - Легковые авто” у нас имеется следующий набор полей:

  • Марка
  • Модель
  • Тип кузова
  • ...

Для объявлений раздела “Недвижимость - Квартиры - Продажа” поля такие:

  • Область
  • Город
  • Район
  • ...

Необходимо реализовать все возможные операции над объявлениями и, самое главное, их поиск.

Почему именно Sphinx?

Без Sphinx тут только костыли...

Я много, много думал и нашел всего 2 варианта хранения значения полей - сериализованные данные (JSON / XML / ...) в общей таблице объявлений или “кучка таблиц”. На первых порах, когда мы затевали этот проект, я не нашел ни одного варианта полноценного поиска по сериализованным данным (возможно, я просто плохо искал) и нам пришлось реализовывать “костыльный” вариант №2 - создавать по таблице значений для каждой категории, но с появлением в Sphinx (с версии 2.2.x) возможности поиска по JSON столбцам решено было перевести поиск на Sphinx.

Кроме того, у Sphinx есть определённые преимущества:

  • Sphinx быстрый и стабильный.
  • Sphinx лёгкий в освоении. Официально рекомендуемым протоколом работы со Sphinx есть SphinxQL - протокол на базе SQL. Полнотекстовый поиск, поиск по JSON и даже манипуляции с RealTime индексами не составляют особого труда тем, кто уже знает SQL.
  • Sphinx масштабируемый. Если в процессе роста проекта, загруженность поискового сервера будет подходить к пиковой - вы спокойно можете поднять поисковый кластер из нескольких машин и распределить нагрузку.
  • Sphinx популярный. Следовательно, в сети полно документации, проект постоянно развивается и его уверенно можно использовать в коммерческих продуктах.
  • Sphinx кроссплатформенный. У нас машины разработчиков работают, в основном, на Windows, а на сервере установлен Debian. Однако подобный “зоопарк” по зубам нашему монстру.

Итак, решено - будем использовать Sphinx. Так с чего же начать?

Установка Sphinx на Debian

В репозиториях Debian версии Sphinx обновляются достаточно редко, поэтому нам придётся устанавливать пакет вручную.

Шаг 1. Качаем отсюдава (http://sphinxsearch.com/downloads/release/). необходимый нам пакет.

Шаг 2. Устанавливаем библиотеки, необходимые для Sphinx:

$ sudo apt-get install mysql-client unixodbc libpq5

Шаг 3. Устанавливаем Sphinx из скачанного .deb пакета:

$ sudo dpkg -i sphinxsearch_2.3.1-beta-0ubuntu11~trusty_amd64.deb

Всё, наш монстр установлен. Теперь, прежде чем его запустить, нам необходимо сконфигурировать поисковые индексы и метод получения исходных данных.

Настройка Sphinx

Все настройи хранятся в файле sphinx.conf.

Исходная таблица

Я сильно упростил таблицу

Получение исходных данных

Конфигурация обычно начинается с секций source. Эти секции описывают данные, которые мы будем тянуть с SQL сервера.

Тут мы описываем тип подключения (mysql), параметры подключения, SQL запросы (самый главный - sql_query - для выборки данных).

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

  1. source src_classified_offers{
  2.     type   		 = mysql
  3.     sql_host   	 = 127.0.0.1
  4.     sql_user   	 = *******
  5.     sql_pass   	 = *******
  6.     sql_db   	 = classified_test
  7.     sql_port   	 = 3306    # optional, default is 3306
  8.     #pre-query
  9.     sql_query_pre   	 = SET NAMES utf8
  10.     # main document fetch query
  11.     sql_query   	 = \
  12.    	 SELECT `id`,`catid`,`vals`, \
  13.    	 `price`,`currency`, \
  14.    	 `name`,`description`, \
  15.    	 UNIX_TIMESTAMP(`published_from`) as published_from_ts \
  16.    	 FROM classified_ads \
  17.    	 WHERE ((`published`=1)AND(`id`>=$start)AND(`id`<=$end))
  18.  
  19.     sql_query_range   	 = SELECT MIN(id),MAX(id) FROM classified_ads
  20.     sql_range_step   	 = 1000
  21.     sql_attr_uint   	 = catid
  22.     sql_attr_json   	 = vals
  23.     sql_attr_float   	 = price
  24.     sql_attr_uint   	 = currency
  25.     sql_attr_timestamp    = published_from_ts    
  26.     sql_ranged_throttle    = 0
  27.     }

Параметры sql_query_range, sql_range_step и sql_ranged_throttle описывают “выборку частями” из нашей таблицы. Поскольку таблица будет большая, теоретически (в процессе выборки большого количества данных) нас может выбить по таймауту. Запросы частями решают данную проблему.

Как видите, в конце секции source, идёт описание типов некоторых полей. Например, sql_attr_json - это значения наших полей. Все неописанные поля добавляются в полнотекстовый индекс.

Выбор типа индекса

Далее нам необходимо создать секцию индекса. В Sphinx есть 2 типа индекса - обычный и realtime. Давайте выберем обычный индекс. Он проще в обслуживании и более производительный (минус - обновляется с запаздыванием).

  1. index classified_offers{
  2.     source   		 = src_classified_offers
  3.     path   		 = /data/sphinx/classified_offers/
  4.     docinfo   		 = extern
  5.     dict   		 = keywords
  6.     mlock   		 = 0
  7.     morphology   	 = stem_enru
  8.     min_word_len   	 = 1
  9.     html_strip   	 = 0
  10.     }

Стоит отметить, что директория path должна существовать на момент запуска демона.

Запуск Sphinx и поиск

Перед стартом сервиса нам необходимо проиндексировать данные. При изменении структуры (добавили столбец в индекс или поменялся тип) необходимо вначале остановить сервис, а затем запускать полное индексирование командой:

  1. $ sudo service sphinxsearch stop
  2. $ indexer --all

Затем запускаем демон:

  1. $ sudo service sphinxsearch start

Если ничего не изменилось - просто вызываем переиндексацию данных без остановки сервиса. Данную команду следует запихнуть в cron для поддержания валидных данных:

  1. $ indexer --all --rotate

Подключение к серверу Sphinx в PHP (мы используем протокол SphinxQL) ничем не отличается от SQL. Вот только порт придётся использовать нестандартный (обычно 9306).

Для поиска по JSON указываем поле через точку. Например:

  1. SELECT values.fuel_type from classified_ads where (values.fuel_type=4);

Для полнотекстового поиска используется ключевое слово MATCH:

  1. SELECT * FROM classified_ads WHERE MATCH('my document');

Вот и всего-то.

Комментарии

15.08.2017 02:24:25
Avatar of ZraigadateZraigadate
cialis generic define
http://cialiswalmart.net - cialis over the counter at walmart
cheapest genuine cialis
<a href="http://cialiswalmart.net">cialis over the counter
</a> - cialis vs cialis cost clever.cgi
cialis for women in mn moderation
16.08.2017 07:31:58
Avatar of AnthozytrambAnthozytramb
cialis treatment
http://cialis-walmart.net - cialis over counter
cialis vs cialis pros and cons
<a href="http://cialis-walmart.net">generic cialis at walmart
</a> - cialis and alcohol display posts from previous
cialis generic canada powered by ip.board
19.08.2017 10:49:00
Avatar of StuarzEvapyStuarzEvapy
viagra pills cheap yabb
http://100mg.viagra-withoutadoctor.net - viagra without a doctor prescription
viagra v viagra which is best for a firmer erection
<a href="http://100mg.viagra-withoutadoctor.net">viagra without a doctor
</a> - viagra drug
erection angle on viagra
Captcha Обновить
Go Top