Thinking Sphinx — теперь очень стандартная библиотека для взаимодействия со Sphinx и прошла долгий путь в реализации различных функций Sphinx. Новая версия, 3.0, представляет собой серьезную переписку и весьма существенный отход, особенно с точки зрения настройки. Кроме того, он включает в себя довольно продвинутый поиск фасетов, встроенный в него. Наконец, эта версия совместима только с Rails 3.1 или выше.
Установка
Установка Sphinx в Linux довольно проста. Загрузка и компиляция из исходного кода является предпочтительным методом установки Sphinx, несмотря на то, что репозитории apt и yum практически обновлены.
Более новые версии Sphinx имеют поддержку нескольких запросов с mysql, и, следовательно, лучше скомпилировать его с включенными заголовками разработки mysql.
$ wget http://sphinxsearch.com/files/sphinx-2.0.7-release.tar.gz $ tar xvzf sphinx-2.0.7-release.tar.gz $ cd sphinx-2.0.7-release/ $ ./configure --with-mysql $ make $ sudo make install
После успешной установки Sphinx вы можете установить Thinking Sphinx как драгоценный камень или связать его в своем приложении.
$ gem install thinking-sphinx -v "~> 3.0.2"
Если ваша база данных — mysql, вам нужно убедиться, что версия gem mysql2 заблокирована на 0.3.12b4 или 0.3.12b5. Более ранние версии gem mysql2 будут вызывать следующее исключение:
undefined method `next_result' for Mysql2
Ошибка возникает из-за того, что в предыдущих версиях gem mysql2 не было поддержки нескольких запросов, и Sphinx теперь имеет это из коробки.
конфигурация
Мышление Sphinx имеет два основных конфигурационных файла. В более ранних версиях первый файл назывался sphinx.yml, но был переименован в think_sphinx.yml.
Второй файл — .sphinx.conf (например, development.sphinx.conf) и используется для взаимодействия Sphinx с базой данных. Каждый раз, когда создается новый индекс, создается новый файл conf, в котором перечислены все запросы Sphinx на основе определенных индексов и сведений о соединении в database.yml.
think_sphinx.yml является расширением этого файла, где вы можете передать дополнительные параметры для улучшения результатов поиска.
Случай использования
Допустим, у нас есть приложение со следующими моделями:
- Продавец — название, рейтинг
- Магазин — название, описание, vendor_id, местонахождение
- Товар — название, артикул, описание, цена, shop_id
со следующими модельными ассоциациями
- Продавец — has_many магазины
- Магазин — принадлежит продавцу, имеет много товаров
- Продукт — принадлежит к магазину
У нас есть следующие варианты использования, которые мы рассмотрим в нашей статье:
- Поиск продавца, магазина, товара индивидуально
- Поиск по всем моделям
- Поиск через ассоциацию
- Определить аспекты для создания фильтров
Основы — определение показателей.
Мышление Sphinx 3.0 использует более четкий подход к определению индексов по сравнению с более ранними версиями.
Чтобы начать определение индекса, сначала необходимо создать каталог с именем «indexes» в папке приложения.
$ mkdir indices
Давайте рассмотрим наш вариант использования и создадим три файла индекса в нашей папке индексов:
- vendor_index.rb
- shop_index.rb
- product_index.rb
Определение индекса файла включает в себя имя класса, по которому нужно искать. Оно должно совпадать с именем класса модели.
Индексы для атрибутов можно определить просто написав:
indexes column_name
Однако есть несколько зарезервированных ключевых слов для Сфинкса (например, статус). Чтобы сделать эти столбцы приемлемыми для Sphinx, вы должны определить их как символ.
indexes :status
В соответствии с нашим вариантом использования давайте напишем наш первый индекс для модели вендора. Это будет индексировать имя поставщика и рейтинг. Мы будем использовать рейтинг в качестве параметра для сортировки результатов поиска по поставщику.
ThinkingSphinx::Index.define :vendor, :with => :active_record do indexes name indexes rating, :sortable => true end
Теперь при поиске товаров и магазинов нам нужно, чтобы название поставщика было общим критерием для каждого поиска. Таким образом, если нам нужно найти продукт под названием «Фигурка Бэтмена» в поставщике «Marvel Toys», мы можем найти его по названию поставщика и найти все продукты, связанные с ним. Вот как это делается:
ThinkingSphinx::Index.define :vendor, :with => :active_record do indexes name, :as => vendor_name indexes rating, :sortable => true end
Внутри других наших индексов ассоциации определяются как:
shop_index.rb ThinkingSphinx::Index.define :shop, :with => :active_record do indexes name, description, location has vendor(:name), :as => :vendor_name end
product_index.rb ThinkingSphinx::Index.define :product, :with => :active_record do indexes name, description indexes price, :sortable => true has shop.vendor.name, :as => :vendor_name end
В обоих вышеуказанных файлах мы вызывали vendor_name
используя ассоциации. Магазин принадлежит продавцу, поэтому мы могли бы сделать прямой звонок от продавца и назвать его vendor_name
, тогда как в продукте мы позвонили через ассоциацию shop
.
Запуск и создание индекса
Как только мы закончим с написанием индексов в наших файлах, нам нужно будет сгенерировать индекс и запустить наш сервер Sphinx.
$ rake ts:index $ rake ts:start
Поиск
После того, как наш Thinking Sphinx запущен и работает, мы можем написать методы контроллера для поиска и отображения результатов.
Запуск поиска по отдельным моделям выглядит следующим образом:
@search_products = Product.search(params[:search], :ranker => :proximity, :match_mode => :any)
Если вы хотите создать поиск в масштабах приложения, вы можете вызвать метод ThinkingSphinx.search
чтобы определить модели для поиска. Вы можете связать это с любым маршрутом и передать поисковый термин в качестве параметра.
def search @search = ThinkingSphinx.search(params[:search], :classes => [ Vendor, Store, Product], :ranker => :bm25, :match_mode => :any, :order => '@weight DESC', :page => params[:page], :per_page => 10) end
Ранжирование использует различные алгоритмы, такие как bm25 и близость, для генерации лучших совпадений в результатах поиска.
Сортировка использует поле заказа и может быть определена для сортировки результатов различными способами. На основе рейтинга, по алфавиту или create_at — это лишь некоторые из способов сортировки.
@weight — это ключевое слово по умолчанию, которое содержит значение рейтинга Sphinx.
Другие вещи
Полевые веса:
Мы можем ранжировать результаты поиска по разным полям в конкретной модели:
@search_products = Product.search(params[:search], :ranker => :proximity, :match_mode => :any, :field_weights => {:description => :15, :name => 10})
Вы также можете записать вес полей внутри ваших индексных файлов, используя правило set_property
например:
:set_property :field_weights => {:description => 15, :name => 10})
Получение выдержек из результатов поиска:
@excerpter = ThinkingSphinx::Excerpter.new 'product_core', params[:search], { :before_match => '<span class="match">', :after_match => '</span>', :chunkseparator => ' … '}
Добавление граней:
Фасетный поиск используется, когда вам нужно отфильтровать по разным классам или параметрам. Определение facet => true
можно сделать, просто задав правило facet => true
для атрибута фасета в файле индекса.
indexes name, :facet => true
Это, а затем просто перестроить индекс.
rake ts:rebuild
В вашем контроллере facet
принимает те же параметры, что и search
, поэтому ваш фасет будет выглядеть так:
@facets = ThinkingSphinx.facets(params[:search], :class_facet => false, :page => params[:page], :per_page => 10)
Если никакие фасеты не определены в какой-либо модели и поиск фасетов записан, он будет возвращаться к фасетам классов, вызывая поиск по отдельным классам моделей. Вы можете отключить его, вызвав false внутри вашего правила фасетов, как показано выше.
Вы можете отобразить побочные эффекты в своем представлении следующим образом:
<% @facets[:class].each do |option, count|%> <%= link_to "#{option} (#{count})", :params => { :facet => option, :page => 1}%> <%end%><br/>
Поиск частичных слов можно выполнить с помощью min_infix_len
внутри вашего min_infix_len
или внутри вашего индексного файла с помощью set_property
. Это означает, что он будет соответствовать как минимум 3 символам, прежде чем объявить его соответствующим. min_infix_len
не рекомендуется хранить в 1, так как это может быть серьезным скачком памяти.
development: mem_limit: 128M min_infix_len: 3 test: mem_limit: 128M min_infix</em>len: 3 production: mem_limit: 128M min_infix_len: 3
Дельта-индексы
Sphinx по умолчанию запускает индексы с нуля каждый раз, когда вы запускаете команду index. Чтобы Sphinx не начинался с нуля, мы можем определить дельта-индексы. Это будет индексировать только те документы, которые были недавно созданы.
set_property :delta => true
Вывод
Мышление Sphinx 3.0 приносит много улучшений и исправлений ошибок из предыдущих версий. Это требует очень чистого подхода, размещая поисковый код вне моделей вашего приложения. Поэтому, когда запросы начинают усложняться, код остается читаемым.
Надеюсь, эта статья вдохновила вас попробовать Thinking Sphinx в своем приложении.