Prime Impressioni su Sphinx

Per la prima volta ho avuto modo di testare funzionamento di Sphinx, uno dei più popolari motori di ricerca full-text in circolazione. L’ho preferito a Lucene per evitare il disagio di Java, e a Ferret per la maggiore affidabilità che mi sembrava dare dal punto di vista del supporto e della stabilità.

Installazione

L’installazione è stata incredibilmente semplice e rapida con homebrew:

brew install sphinx

In realtà mi sono reso presto conto che la ricetta homebrew non prevedeva il supporto per libstemmer (vedremo dopo a cosa serve), quindi ho modificato leggermente la ricetta in questo modo (sudo brew edit sphinx):

 1 require 'formula'
 2
 3 class Sphinx < Formula 4 url 'http://sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz'
 5 homepage 'http://www.sphinxsearch.com' 
6 md5 '7b9b618cb9b378f949bb1b91ddcc4f54'
 7 head 'http://sphinxsearch.googlecode.com/svn/trunk/'
 8
 9 fails_with_llvm "fails with: ld: rel32 out of range in _GetPrivateProfileString from /usr/lib/libodbc.a(SQLGetPrivateProfileString.o)"
 10
 11 def install
 12 system "curl -O http://snowball.tartarus.org/dist/libstemmer_c.tgz"
 13 system "tar zxvf libstemmer_c.tgz"
 14
 15 args = ["--prefix=#{prefix}", "--disable-debug", "--disable-dependency-tracking", "--with-libstemmer"] 
16 # configure script won't auto-select PostgreSQL 
17 args << "--with-pgsql" if `/usr/bin/which pg_config`.size > 0
 18 args << "--without-mysql" if `/usr/bin/which mysql`.size <= 0
 19
 20 system "./configure", *args 
21 system "make install"
 22 end
 23
 24 def caveats 
25 <<-EOS.undent
 26 Sphinx depends on either MySQL or PostreSQL as a datasource.
 27 
28 You can install these with Homebrew with:
 29 brew install mysql 
30 For MySQL server.
 31 
32 brew install mysql-connector-c
 33 For MySQL client libraries only. 
34 
35 brew install postgresql
 36 For PostgreSQL server. 
37 
38 We don't install these for you when you install this formula, as
 39 we don't know which datasource you intend to use.
 40 EOS 
41 end
 42 end

Configurazione

A questo punto, il peggio è passato. Thinking Sphinx è una gemma ottimamente documentata e seguita dal suo sviluppatore, e ti permette di impostare degli indici di ricerca per i tuoi modelli Rails direttamente al loro interno, grazie ad un semplice DSL di questo tipo:

 1 class User < ActiveRecord::Base 
2   devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
 3 
4 define_index do 
5 indexes first_name 
6 indexes last_name, :sortable => true 
7 indexes email 
8 indexes company 
9 indexes company_role 
10 indexes city 
11 indexes website 
12 indexes notes 
13 set_property :enable_star => true 
14 set_property :min_infix_len => 1 
15 end 
16 
17 end

Avviare Sphinx

Una volta impostati gli indici (per maggiori info su come funziona Sphinx rifatevi a questa pagina, per esempio), basta semplicemente far partire un rake task per convertire il DSL in file di configurazione Sphinx: thinking_sphinx:configure. Potete poi far partire il server Sphinx con thinking_sphinx:start. Giuro che è stato veramente così semplice.

Thinking Sphinx dispone di una serie di rake task aggiuntivi per coprire tutti i vostri bisogni:

rake thinking_sphinx:configure      # Generate the Sphinx configuration file using Thinking Sphinx's settings
rake thinking_sphinx:index          # Index data for Sphinx using Thinking Sphinx's settings
rake thinking_sphinx:rebuild        # Stop Sphinx (if it's running), rebuild the indexes, and start Sphinx
rake thinking_sphinx:reindex        # Reindex Sphinx without regenerating the configuration file
rake thinking_sphinx:restart        # Restart Sphinx
rake thinking_sphinx:running_start  # Stop if running, then start a Sphinx searchd daemon using Thinking Sphinx's settings
rake thinking_sphinx:start          # Start a Sphinx searchd daemon using Thinking Sphinx's settings
rake thinking_sphinx:stop           # Stop Sphinx using  Thinking Sphinx's settings
rake thinking_sphinx:version        # Output the current Thinking Sphinx version

Per ricercare facendo uso di Sphinx, rifatevi all’ottima guida, ma fondamentalmente si parla di fare cose come:

 1 User.search(params[:search], :star => true, :order => :last_name).page(params[:page]).per(1

E come forse vi state chiedendo sì, è già compatibile con will_paginate e Kaminari (dalla versione ~> 2.0.3).

Word stemming

Se avete installato Sphinx con il flag --with-libstemmer da me suggerito qualche riga più in alto, allora avrete anche la possibilità di configurare il word stemming italiano. Questo significa che Sphinx sarà in grado di gestire correttamente le forme singolari/plurali delle ricerche, fornendo risultati più rilevanti.

Conclusioni

Quello che abbiamo visto è la base. Sphinx è incredibilmente potente e permette, ad esempio:

  • La ricerca anche sulle relazioni delle entità;
  • Ordinare i risultati per peso raggruppandoli in slot temporali (utile per ricerche real-time);
  • Ricercare mediante più sintassi (da quella per operatori logici, a quella con wildcards);
  • Effettuare ricerche geospaziali;

L’unico svantaggio di Sphinx rispetto ad altri motori di ricerca full-text è che gli indici devono essere totalmente rigenerati quando anche solo un’elemento della tabella cambia. In realtà anche questo aspetto è stato pressochè risolto mediante delta indexes, praticamente trasparenti all’utente.

Insomma. Sphinx mi ha convinto.