23. March 2013 · 4 comments · Categories: MySql, Php · Tags: , ,

In questo articolo vedremo come utilizzare SphinxSearch,
per la creazione di un motore di ricerca fulltext ad alte performances per la nostra applicazione.

La versione di Sphinx oggetto di questo articolo è la 2.0.6.

  1. Che cos’è ed a cosa serve Sphinx?
  2. Installazione di Sphinx
    1. Installazione su Linux
    2. Installazione su Windows
  3. Configurazione
  4. Configurazione indice RealTime
  5. Creazione Indice (no realtime)
  6. Avviare Sphinx
  7. Effettuare query a Sphinx
  8. Il client PHP di Sphinx
    1. Effettuare una query
    2. Ricerca per range (da X a Y) e date
    3. Ricerca NOT senza termini
    4. Estendere sphinxapi.php
  9. Creazione Indice RealTime
  10. Strategie di aggiornamento indice
    1. Aggiornamento RealTime
    2. Aggiornamento indice normale manualmente o con cron
  11. Ricerche con charset utf8
  12. Collegamenti utili

Che cos’è ed a cosa serve Sphinx?

Sphinx Search è una piattaforma di ricerca open source, che da la possibilità di creare
indici di ricerca partendo da varie sorgenti, tra le quali database MySql, dando la capacità alla
nostra applicazione di restituire risultati di una ricerca in maniera estremamente veloce anche su un
set di dati di parecchi milioni di records.

I componenti che compongono Sphinx sono

  • Indexer
  • Indexes
  • Deamon

Download ed installazione di Sphinx

Sphinx è scaricabile gratuitamente dalla pagina ufficiale di download Sphinx Search,
ed è disponibile per vari sistemi operativi, tra cui Linux e Windows, che vedremo qui di seguito.

  • Installazione su Linux

    1. Portiamoci su /usr/local e scarichiamo dalla pagina di download la release Linux di Sphinx (es. sphinx-2.0.6-release.tar.gz) ed estraiamone il contenuto.

      E’ possibile usare il comando wget url-file.tar.gz per eseguire il download da console.

                $ tar xzvf sphinx-2.0.6-release.tar.gz
                $ mv sphinx-2.0.6-release sphinx
                $ cd sphinx
              

      A questo punto dovreste avere la directory /usr/local/sphinx con i files dell’applicazione.

    2. Far girare il seguente comando per configurare l’installazione con mysql

                $ ./configure --with-mysql --prefix=/usr/local/sphinx
              

      quindi il seguente comando per compilare i binari

                $ make
              

      ed il seguente comando per installare i binari in una directory a nostra scelta.

      Di default il valore è /usr/local/bin/, ma questo sarà sovrascritto dal path specificato
      nella configurazione (ovvero /usr/local/sphinx)

                $ make install
              

      Per conoscere le altre opzioni di configurazione disponibili visitare questa pagina

      Qui di seguito una lista dei possibili problemi riscontrabili durante l’installazione:

      • Il comando ./configure potrebbe non andare a buon fine a causa di questo errore
                  checking whether to compile debug version... no
                  checking for gcc... no
                  checking for cc... no
                  checking for cl.exe... no
                  configure: error: in `/usr/local/sphinx':
                  configure: error: no acceptable C compiler found in $PATH
                  See `config.log' for more details.
                

        In tal caso sarà necessario installare gcc (apt-get install gcc) e successivamente procedere a lanciare ./configure.

      • In caso di utilizzo con mysql si potrebbe incappare in questo problema
                  ******************************************************************************
                  ERROR: cannot find MySQL include files.
        
                  Check that you do have MySQL include files installed.
                  The package name is typically 'mysql-devel'.
        
                  If include files are installed on your system, but you are still getting
                  this message, you should do one of the following:
        
                  1) either specify includes location explicitly, using --with-mysql-includes;
                  2) or specify MySQL installation root location explicitly, using --with-mysql;
                  3) or make sure that the path to 'mysql_config' program is listed in
                     your PATH environment variable.
        
                  To disable MySQL support, use --without-mysql option.
                  ******************************************************************************
                

        In questo caso per risolvere sarà sufficiente indicare il path dell’installazione di mysql
        –with-mysql=/path/to/mysql.

      • make not found.. installare con apt-get install make.
      • Make: problema con g++
        Making all in libstemmer_c
        make[1]: Entering directory `/usr/local/sphinx/libstemmer_c'
        make[1]: Nothing to be done for `all'.
        make[1]: Leaving directory `/usr/local/sphinx/libstemmer_c'
        Making all in src
        make[1]: Entering directory `/usr/local/sphinx/src'
        /bin/sh svnxrev.sh ..
        make  all-am
        make[2]: Entering directory `/usr/local/sphinx/src'
        source='sphinx.cpp' object='sphinx.o' libtool=no \
                DEPDIR=.deps depmode=none /bin/bash ../config/depcomp \
                g++ -DHAVE_CONFIG_H -I. -I../config  -DSYSCONFDIR="\"/usr/local/sphinx/etc\"" -DDATADIR="\"/usr/local/sphinx/var/data\"" -I/usr/local/include -I/opt/tokutek/mysql/include -fPIC -g -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing -DMY_PTHREAD_FASTMUTEX=1    -Wall -g -D_FILE_OFFSET_BITS=64 -O3 -DNDEBUG -c -o sphinx.o sphinx.cpp
        ../config/depcomp: line 512: exec: g++: not found
        make[2]: *** [sphinx.o] Error 127
        make[2]: Leaving directory `/usr/local/sphinx/src'
        make[1]: *** [all] Error 2
        make[1]: Leaving directory `/usr/local/sphinx/src'
        make: *** [all-recursive] Error 1
        

        Procedere ad installare g++ con apt-get install g++ e rilanciare make.

  • Installazione su Windows

    L’installazione su windows è più semplice che quella su Linux.

    1. Scarichiamo la versione di Sphinx in base alle nostre necessità, ad esempio sphinx-2.0.6-release-win64-id64-full.zip,
      ed estraiamo il suo contenuto.

      Se si usa xampp per comodità è possibile estrarre i files all’interno del percorso C:\xampp\sphinx .


Configurazione

Per far funzionare Sphinx è necessario modificare alcuni parametri nel file di configurazione,
nella directory di installazione sono presenti un paio di files di configurazione, uno completo ed uno
ridotto, che dovrebbero chiamarsi rispettivamente sphinx.conf.in e sphinx-min.conf.in.

Apriamo il file sphinx-min.conf.in e salviamolo con il nome di conf.min ( faremo riferimento a questo file
più avanti in questo articolo ), in modo tale da mantenere l’originale per futuri riferimenti.

Applicheremo le seguenti modifiche:

  1. Sostituiamo il testo @CONFDIR@ con il nostro path di installazione, se siamo su Linux /usr/local/sphinx,
    su Windows C:\xampp\sphinx se avete seguito le indicazioni del punto precedente.

  2. Voce source: sotto questa voce sono presenti le proprietà di configurazione per la connessione alla sorgente dati, nel nostro caso
    database mysql

    • Configuriamo la connessione a mysql modificando i seguenti parametri
      sql_host, sql_user, sql_pass, sql_db, sql_port.

    • modifichiamo il parametro sql_query che conterrà la query sql
      utile per l’estrazione dei dati con i quali sarà creato l’indice di ricerca. Da notare che il valore delle date deve essere salvato come unix timestamp (es. UNIX_TIMESTAMP(my_datetime_field) )

    • Tutti i campi specificati nella select sql saranno ricercabili usando l’indice di Sphinx in modalità fulltext,
      però se si vogliono effettuare ordinamenti,
      ricerche per range ( da x a y ) ed utilizzare operatori logici quali <, >, ! ecc..
      sarà necessario specificare come ATTRIBUTO ogni campo per il quale
      si vuole abilitare questa funzionalità
      .

      Inserendo campi come attributi l’indice sarà più oneroso in termini di memoria utilizzata sia di RAM che disco,
      ed inoltre la creazione dell’indice sarà più lenta.

      I tipi di attributo supportati da Sphinx sono sql_attr_timestamp, sql_attr_bool, sql_attr_float, sql_attr_uint, sql_field_string.
      Una nota degna di attenzione riguarda il fatto che, inserendo come attributo uno dei campi di tipo testuale presenti nella query
      SELECT specificata in sql_query, questo non sarà più disponibile nella ricerca nella modalità extended (che vedremo più avanti).
      Per evitare questo specificheremo questi campi come attributi sql_field_string: questo ci permette di mantenere il campo come sql field
      ed in contemporanea come attributo, quindi ricercabile, ordinabile ecc..

  3. Voce index: sotto questa voce sono presenti le proprietà di configurazione dell’indice di ricerca che Sphinx Search andrà
    a creare.

    • Specificare un identificativo sorgente valido (default ‘src1′), un path valido,
      ad esempio per Windows C:\xampp\sphinx\data\main o per Linux /usr/local/sphinx/data/main, dove la parte finale “main”
      è il prefisso dei files che creerà Sphinx Search all’interno della directory “data”.

    • Modifichiamo la proprietà charset_type in utf8

    • Se non presente, aggiungiamo min_word_len = 1 : indica che nell’indice saranno ricercabili parole complete fino ad un solo carattere.
      Aumentando questo valore, le parole di lunghezza minore non saranno indicizzate.

    • Se non presente, aggiungiamo morphology = none :
      indica quale tipo di pre-processore utilizzare per trasformare una parola nella sua forma base.
      Questa trasformazione dipende dalla lingua utilizzata, sono disponibili in Sphinx lo stemmer per l’inglese ed il russo.
      Lasciamo questa voce disattivata, per ulteriori info è disponibile la pagina nella
      documentazione ufficiale

    • Inoltre, per abilitare le wildcard (*) searches, utili ad esempio per funzionalità tipo autocomplete, è necessario specificare le seguenti voci

      min_prefix_len = 3

      enable_star = 1

      La proprietà min_prefix_len indica a quale lunghezza saranno indicizzate le sotto-parole a partire da una parola completa trovata
      nella sorgente dei dati. Ad esempio se la parola è Rinaudo e min_prefix_len è 3, le parole indicizzate saranno:

      • Rin
      • Rina
      • Rinau
      • Rinaud
      • Rinaudo

      In caso di modifica di questo valore, per renderlo funzionale sarà necessario reindicizzare, vedi documentazione ufficiale.

      La proprietà enable_star indica solo se attivare o disattivare le wildcard search, per rendere attiva una eventuale modifica sarà
      necessario solamente riavviare il search daemon.

  4. Voce indexer: sotto questa voce sono presenti le proprietà di configurazione dell’indexer,
    il programma che si occupa di creare l’indice

    • L’unica voce da configurare in questo caso è mem_limit alla quale possiamo attribuire un valore di 1024M.

  5. Voce searchd: sotto questa voce sono presenti le proprietà di configurazione del daemon di Sphinx Search.

    • Inseriamo la voce di configurazione compat_sphinxql_magics = 0, questo per evitare un warning dovuto ad un bug
      nella versione corrente di Sphinx Search (2.0.6)

    • Impostiamo max_matches = 10000. Questa proprietà indica i valori massimi che saranno restituiti come resultset.
      Al crescere di questo valore crescerà lo spazio utilizzato nella memoria RAM. Un valore di 10 mila dovrebbe essere sufficiente,
      fermo restando che, in caso di paginazione con 10 records per pagina, non otterremo risultati oltre la pagina 1000.
      E’ importante inoltre ricordarsi di impostare lo stesso valore anche nel codice ( come vedremo negli esempio di utilizzo delle API PHP ).
      Per ulteriori info riguardanti questa proprietà vedere la documentazione ufficiale


Creazione Indice

Il programma che si occupa della creazione dell’indice è indexer, che potete trovare all’interno della directory /bin,
che si trova nell’installazione di Sphinx. Sarà necessario passare ad indexer il parametro –config con il path del nostro file di configurazione,
che avevamo chiamato conf.min.

Al fine di effettuare delle prove e non attendere eccessivamente per la creazione dell’indice,
il consiglio è di non includere nell’indice più di 1 milione di records ( o anche molti meno ).

Su Linux, portiamoci all’interno di /usr/local/sphinx/bin ed eseguiamo:

    $ indexer --config /usr/local/sphinx/conf.min --all
  

Su Windows, portiamoci all’interno di C:\xampp\sphinx\bin ed eseguiamo:

    indexer.exe --config C:\xampp\sphinx\conf.min --all
  

Il secondo parametro –all indica di reindicizzare tutti gli indici listati nel file di configurazione (nel nostro caso solo uno),
in caso non si volesse reindicizzare tutto basterà specificare il nome dell’indice da ricostruire.

In caso di poche migliaia di record l’indice sarà creato in pochissimi secondi,
se l’indice sarà composto da vari milioni di documenti sarà necessario aspettare
anche alcune ore, dipendentemente anche dal tipo di hardware e dal numero di attributi specificato
nel file di configurazione.

Gli errori più comuni in questo passaggio sono relativi all’insufficienza di memoria su disco e di memoria RAM,
ricordiamo che per creare un indice è necessario avere su disco almeno 3 volte la quantità di memoria occupata, per fare un esempio,
se il nostro indice occuperà 10GB per crearlo dovremo avere su disco almeno 30GB.


Avviare Sphinx

Il programma che si occupa di inizializzare il demone di Sphinx si chiama searchd.
Come per indexer, sarà necessario passare il parametro –config con il path del nostro file di configurazione.

Su Linux, portiamoci all’interno di /usr/local/sphinx/bin ed eseguiamo:

    $ searchd --config /usr/local/sphinx/conf.min
  

Su Windows, portiamoci all’interno di C:\xampp\sphinx\bin ed eseguiamo:

    searchd.exe --config C:\xampp\sphinx\conf.min
  

Configurazione indice RealTime

Il RealTime Index è un particolare tipo di indice che può essere acceduto utilizzando il protocollo di MySql. La porta utilizzata di default è la 9306 (secondo parametro listen nella configurazione di searchd).

La configurazione dell’indice RT deve essere definita nel file di configurazione, ed è del tutto simile alla configurazione del normale indice di sphinx, ad eccezione del fatto che non è necessario specificare
una source (in ogni caso non sarà presa in considerazione). Inoltre il type deve essere rt.

Gli attributi disponibili per l’indice RT sono rt_attr_bigint, rt_attr_float, rt_attr_timestamp, rt_attr_string, inoltre sarà necessario elencare TUTTI i campi per cui si vuole effettuare la ricerca fulltext come rt_field.

Sarà inoltre necessario impostare la proprietà dict = keywords per attivare le wildcard (*) searches ( cosa non necessaria con l’indice normale ).

  index realtime
  {
    type = rt
    
    path = C:\xampp\sphinx\realtime\rt
    
    rt_mem_limit		= 512M

    # full-text field declaration
    # multi-value, mandatory
    rt_field = fulltext_field1
    rt_field = fulltext_field2
    rt_field = fulltext_field3
    rt_field = fulltext_field4
    rt_field = fulltext_field5
    rt_field = fulltext_field6
    rt_field = fulltext_field7

    # RT indexes currently support the following attribute types:
    # uint, bigint, float, timestamp, string
    #
    # rt_attr_bigint		= guid
    # rt_attr_float		= gpa
    # rt_attr_timestamp	= ts_added
    # rt_attr_string		= author

    rt_attr_timestamp	= datetime_field
    rt_attr_string = fulltext_field3
    rt_attr_string = fulltext_field4
    rt_attr_string = fulltext_field1
    
    dict = keywords
    min_word_len = 1
    morphology = none
    min_prefix_len = 3
    enable_star = 1
  }
  

Per accedere all’indice realtime configurato, avviare il demone di Sphinx come spiegato nel passaggio precedente,
quindi connettiamoci usando il protocollo mysql alla porta 9306.

    $ mysql -P 9306
  

Quindi eseguiamo la seguente query ( che restituirà un set vuoto fino a quando non andremo ad aggiungere i dati nell’indice RT ).

    mysql> select * from realtime;
  

Per inserire dei dati di prova nell’indice direttamente da linea di comando possiamo utilizzare una normale query INSERT INTO,
specificando come primo valore un id univoco, quindi i valori per ogni rt_fields specificato nella configurazione e quindi i valori
per ogni attributo. Una INSERT valida per la configurazione di esempio di qui sopra sarebbe:

    INSERT INTO realtime VALUES (
      'inserireIdUnivocoQui', 
      
      'valore_per_fulltext_field1', 
      'valore_per_fulltext_field2', 
      'valore_per_fulltext_field3', 
      'valore_per_fulltext_field4', 
      'valore_per_fulltext_field5', 
      'valore_per_fulltext_field6', 
      'valore_per_fulltext_field7',
      
      'valore_per_datetime_field',
      'valore_per_fulltext_field3',
      'valore_per_fulltext_field4',
      'valore_per_fulltext_field1'
    );
  

Effettuare query nell’indice di Sphinx è possibile utilizzando l’applicazione search da linea di comando o tramite api php
( sphinxapi.php, che potete trovare nella directory /api all’interno dell’installazione di Sphinx ).

Se si usa search (search.exe su windows) è importante specificare il MATCH MODE che si vuole utilizzare ( oltre che il file di configurazione ).
Di seguito le opzioni disponibili per il comando search:

    Usage: search [OPTIONS] <word1 [word2 [word3 [...]]]>

    Options are:
    <strong>-c, --config <file>     use given config file instead of defaults</strong>
    -i, --index <index>     search given index only (default: all indexes)
    -a, --any               match any query word (default: match all words)
    -b, --boolean           match in boolean mode
    -p, --phrase            match exact phrase
    -e, --extended          match in extended mode
    -f, --filter <attr> <v> only match if attribute attr value is v
    -s, --sortby <CLAUSE>   sort matches by 'CLAUSE' in sort_extended mode
    -S, --sortexpr <EXPR>   sort matches by 'EXPR' DESC in sort_expr mode
    -o, --offset <offset>   print matches starting from this offset (default: 0)
    -l, --limit <count>     print this many matches (default: 20)
    -q, --noinfo            don't print document info from SQL database
    -g, --group <attr>      group by attribute named attr
    -gs,--groupsort <expr>  sort groups by <expr>
    --sort=date             sort by date, descending
    --rsort=date            sort by date, ascending
    --sort=ts               sort by time segments
    --stdin                 read query from stdin
  

Esistono diverse modalità di ricerca ( vedere la documentazione ufficiale ),
in questo articolo vedremo il tipo SPH_MATCH_EXTENDED/2, con il quale è possibile effettuare query anche complesse).

I seguenti operatori e modificatori sono utilizzabile nella modalità di ricerca estesa:

  • Operatore OR

            hello | world
          
  • Operatore NOT

            hello -world
            hello !world
          
  • Ricerca per campo

            @title hello @body world
          
  • Ricerca con limit modifier, restituisce il record solo se ‘hello’ esiste nel campo ‘body’ entro le 50 parole

            @body[50] hello
          
  • Ricerca con campi multipli

            @(title,body) hello world
          
  • Ricerca su tutti i campi

            @* hello
          
  • Ricerca frase esatta

            "hello world"
          
  • Ricerca di prossimità, restituisce il record solo se le parole ‘hello’ e ‘world’ sono presente con un limite massimo di 10 parole di distanza

            "hello world"~10
          
  • Ricerca quorum, restituisce il record solo se questo contiene almeno /X parole presenti nella frase

            "the world is a wonderful place"/3
          
  • Ricerca strict o before, restituisce il record solo se questo contiene le parole indicate nel corretto ordine

            aaa << bbb << ccc
          
  • Ricerca exact form, restituisce il record solo se questo contiene le parole esatte precedute dall’uguale, per le restanti saranno applicate le regole dello stemmer usato, se attivo,
    vedi questa discussione per ulteriori informazioni.

            raining =cats and =dogs
          
  • Ricerca field-start e field-end, restituisce il record solo se questo inizia e/o finisce con la/e parole definite

            ^hello world$
          

Per ulteriori informazioni vedere la documentazione ufficiale.


Il client PHP di Sphinx

Il client PHP di Sphinx, come detto nel punto precedente, si trova all’interno della directory /api nell’installazione di sphinx.
Ecco un veloce esempio di utilizzo:

&lt;?php
require ( "sphinxapi.php" );  //included in distro
$cl = new SphinxClient();
$cl->SetServer  ( “127.0.0.1”, 9312 ); 
$res = $cl->Query ( “iphone", “shop_items" );
//some error processing
var_dump($res)
?&gt;

Questo può essere usato così com’è o eventualmente essere esteso per aggiungere nuove funzionalità.

Vediamo qui di seguito come effettuare ricerche usando il client sphinx, alcune richieste potranno essere effettuate usando la sintassi estesa,
per altre sarà necessario usare i metodi del client che utilizzano gli attributi con cui abbiamo costruito l’indice.

  • Effettuare una query

    Con il seguente codice è possibile effettuare query all’indice di Sphinx Search:

          $sphinx->addQuery($query, $index);
          $result = $sphinx->RunQueries();
        

    La variabile $query conterrà una stringa che potrà essere solo un termine o un valore più complesso creato usando la sintassi estesa.

    La variabile $index è una stringa che indica il nome dell’indice in cui effettuare la ricerca.

    La variabile $result conterrà il risultato della ricerca, che sarà un array, contenente oltre che il set di documenti, anche il numero dei documenti totali trovati ed altre informazioni.

  • Range numeri interi

          $sphinx->setFilterRange($field, $value, $valueEnd, $exclude);
        

    Range numeri in virgola

          $sphinx->SetFilterFloatRange($field, $value, $valueEnd, $exclude);
        

    I metodi di sopra sono usati per effettuare rispettivamente query range di numeri interi e float, ovvero estraggono tutti quei documenti che hanno come attributo $field un valore compreso
    tra $value e $valueEnd. Il quarto parametro, $exclude, è un boolean che indica se escludere i documenti nel range piuttosto che includerli.

    Il metodo setFilterRange è utilizzato per cercare documenti per data: come specificato alla voce configurazione, le date saranno salvate nell’indice
    come UNIX_TIMESTAMP, quindi come numero intero, in modo tale da poter essere filtrate con setFilterRange. Specificare il campo di tipo data come attributo di tipo sql_attr_timestamp
    nella configurazione della sorgente.

    Come ricercare documenti appartenenti ad un dato giorno.

    Nel caso si volesse utilizzare datepicker o simili, è da tenere in considerazione che il valore che si vuole passare per la ricerca è un giorno dove
    non specificheremo l’orario ( es. estrai tutti i record del 26 Marzo 2012 ), ma nell’indice, in caso di campo datetime avremo lo UNIX_TIMESTAMP, è necessario quindi implementare uno strato che ci dia la possibilità
    di effettuare tali ricerche.

    Nel seguente esempio utilizzeremo l’oggetto Datetime, disponibile dalla versione PHP >= 5.2.

          $exclude = false;
          
          // $value => 2012/03/26
          $dateTime = new \DateTime($value);
          $value = $dateTime->getTimestamp();
          
          $dateTime = $dateTime->modify("+1439 minutes, +59 seconds"); // aggiunta di 59 minuti e 59 secondi
          $valueEnd = $dateTime->getTimestamp();
          
          // Il range sarà effettuato dalla data 2012/03/26 00:00:00 e 2012/03/26 23:59:59
          $sphinx->setFilterRange($field, $value, $valueEnd, $exclude);
        
  • Ricerca NOT senza termini

    Come visto nella sezione Effettuare query a Sphinx, è possibile effettuare query con l’operatore NOT.
    Come per altri indici, non è possibile però utilizzare NOT senza specificare un termine per la ricerca, es.

          // Questa query NON è corretta
          !world
          
          // Questa query è corretta
          hello !world
        

    Per risolvere questo problema la soluzione è utilizzare una parola chiave all’interno del nostro indice, ad esempio ‘alldocuments‘, ed indicizzare questo termine insieme
    ai valori dei campi di tipo testo che abbiamo definito come attributi, es.

          SELECT [...] CONCAT('alldocuments', ' ', fulltext_field1) fulltext_field1, CONCAT('alldocuments', ' ', fulltext_field2) fulltext_field2 [...]
        

    In questo modo, nel codice, potremo effettuare la query NOT utilizzando la sintassi estesa:

          // Questa query è corretta
          alldocuments !world
          
          // o seguendo le nomenclature degli attributi nella configurazione di esempio 
          @fulltext_field1 alldocuments !search_value
        
  • Estendere sphinxapi.php

    Al fine di aggiungere nuove funzionalità, estenderemo il client Sphinx all’interno di una libreria Zend Framework chiamata ‘Application’,
    chiameremo quindi la nuova classe client Application_Sphinx_Client ( all’interno di un progetto Zend Framework 1.11.x salvata in library/Application/Sphinx/Client.php ).

        <?php 
    
        require_once('sphinxapi.php');
    
        /**
         * Sphinx client con alcuni metodi aggiuntivi 
         * 
         * @author Sergio Rinaudo
         */
        class Application_Sphinx_Client 
            extends SphinxClient 
        {
            // code here...
        }
        

    Un metodo utile che potremo implementare è ad esempio search a cui passeremo un array di parametri (campi, valori, campi per sort, campi per group, limit e offset ).

        /**
         * Effettua una ricerca nell'indice
         * 
         * @param array $params
         * @return array
         */
        public function search($params = array(), $index = '*') 
        {
          // code here...
        }
        

    Lasciamo al lettore l’implementazione di questo metodo :)


Creazione Indice RealTime

La creazione dell’indice realtime avviene inserendo i dati manualmente usando il linguaggio Sphinxql. Siccome l’indice RT utilizza lo stesso protocollo MySql, per collegarci ad esso possiamo utilizzare PDO:

    $engine = 'mysql';
    $host = 'localhost';
    $database = '';
    $user = '';
    $pass = '';
    $port = '9306';
    $dns = $engine.':dbname='.$database.";host=".$host.";port=".$port;
    $pdo = new PDO($dns, $user, $pass);
  

Lascio al lettore l’implementazione del codice per l’inserimento dei dati nell’indice, che non sarà altro che una query “”INSERT INTO realtime VALUES ()”, come da documentazione ufficiale.


Strategie di aggiornamento indice

  • Aggiornamento indice Real Time

    In caso di utilizzo dell’indice realtime, le query inviate al database mysql devono essere replicate all’indice di sphinx con sphinxql,
    gli aggiornamenti saranno subito disponibili nell’indice senza la necessità di riavviare il demone di Sphinx.

    E’ bene inviare molteplici INSERT raggruppate in una singola transazione per evitare spreco di risorse.

    E’ inoltre da tenere in considerazione che un alto volume di query DELETE e REPLACE porta ad una frammentazione che può impattare negativamente le performances di ricerca,
    per ripristinare le performances sarà quindi necessario ricreare l’indice di ricerca.

    Al momento attuale non esiste un comando per ottimizzare l’indice realtime, tuttavia sarà presente nella prossima release di sphinx che sarà disponibile all’incirca per metà febbraio.

    Binary Logging

    Il bynary logging è un meccanismo di recupero dati. Usando l’RT index, tutte le transazioni sono scritte da searchd nel binlog file, in modo tale da poter essere recuperate nel caso
    di arresto non pulito del servizio. Il bynary logging è attivato settando l’opzione binlog_path = C:\xampp\sphinx\log ( modificare il percorso se necessario.. ) nella configurazione
    di searchd

  • Aggiornamento indice normale manualmente o con cron

    L’aggiornamento del normale indice di Sphinx Search è possibile utilizzando l’applicazione indexer da linea di comando.

    E’ possibile passare ad indexer l’opzione –rotate per inviare al demone di sphinx attivo il segnale di riavvio,
    aggiornando l’indice in RAM.

    L’aggiornamento dell’indice main può essere un lavoro lento su una sorgente da molti milioni di records e anche dipendentemente dagli attributi definiti nella configurazione,
    quindi è da farsi non più di una volta ogni 24 ore, nelle ore non di picco.

    Per includere nell’indice eliminazioni/aggiornamenti ed inserimenti bisogna configurare la gestione dell’indice delta, ed effettuare le query su entrambi gli indici main+delta:

          $res = $cl->Query ( "test", "main delta" );
        

    Gestione Kill List

    Per Kill List si intendono quei dati che sono stati aggiornati o eliminati e devono quindi essere
    quindi aggiornati o eliminati dall’indice, senza la necessità di effettuare la reindicizzazione.

    Vediamo un esempio. Assumiamo di avere due indici, ‘main’ e ‘delta’. Assumiamo che i documenti 2, 3, e 5 sono stati eliminati dall’ultima reindicizzazione di ‘main’, e i documenti 7 e 11 sono stati aggiornati
    ( ovvero il loro contenuto testuale è stato modificato ). Assumiamo che la keyword ‘test’ era presente in tutti questi documenti nell’ultima indicizzazione di ‘main’; questa keyword è sempre presente nel documento 7 dopo aver effettuato la reindicizzazione del ‘delta’; ma non esiste più nel documento 11. Reindicizzando l’indice delta e cercando in entrambi nel corretto ordine ( come nell’esempio sopra ):

          $res = $cl->Query ( "test", "main delta" );
        

    Come primo fattore, dobbiamo gestire le eliminazioni dei records. Il resultset NON dovrà restituire i records 2,3 e 5. Secondo dobbiamo essere certi di non avere risultati “fantasma”, in quanto,
    finchè non facciamo qualcosa, il documento 11 contiene ancora la parola chiave “test”.

    Le kill list ( o k-list per abbreviare) sono quel qualcosa. Kill-list abbinati al ‘delta’ fanno in modo che i risultati eliminati ed aggiornati non risultino in tutti gli indici precedenti a delta, nel nostro caso solo ‘main’. Quindi, per avere il risultato corretto, dobbiamo inserire tutti gli id dei documenti aggiornati ed eliminati al suo interno.

          sql_query_killlist = \
            SELECT id FROM my_table WHERE updated_ts>=@last_reindex UNION \
            SELECT id FROM my_table WHERE deleted_ts>=@last_reindex
        

    Il valore di @last_reindex può essere recuperato creando una tabella di appoggio che conterrà questo dato e sarà aggiornata ad ogni reindicizzazione di ‘main’.

          CREATE TABLE IF NOT EXISTS `sph_last_update` (
            `counter_id` int(11) NOT NULL,
            `last_update` datetime DEFAULT NULL,
            PRIMARY KEY (`counter_id`)
          ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
        

    L’aggiornamento di questo dato avverrà tramite una query ‘pre’ inserita nella configurazione del ‘main’ index.

          sql_query_pre = REPLACE INTO sph_last_update SELECT 1, NOW()
        

Utilizzando Sphinx è possibile effettuare ricerche anche con caratteri multibyte, specificando nella configurazione dell’indice la proprietà charset_type = utf-8, nella configurazione della sorgente la
proprietà sql_query_pre = SET NAMES utf8 ed avendo come sorgente dati un database MySql che utilizzi il charset UTF8 per lo schema, per le tabelle e per i campi testuali, vedi questo articolo.



Se avete commenti sull’argomento potete lasciarli nell’apposito spazio, risponderò nn appena possibile!

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...

4 Comments

  1. Ciao! Ottima guida ma volevo chiederti, sono io che non l’ho visto oppure il procedimento di installazione del Driver Php di Sphinx l’hai omesso.. Per intenderci la compilazione della libsphinxclient e del driver.

    Grazie! MI interessava sapere la tua esperienza su questa parte

    • Ciao Gian,
      usa direttamente la classe contenuta nel file sphinxapi.php ( /api/sphinxapi.php ),
      contiene tutto quello che ti serve per connetterti al server Sphinx, non è necessario installare nessun modulo per php.

      Fammi sapere.

  2. Ciao,
    Articolo molto ben fatto. Grazie.

    Io ho un database mysql su server webhost (hostgator).
    Quali sono le possibilità per usare l’indicizzazione sphinx su questo database ?

    • Ciao Paolo,
      se hai accesso da shell ssh e le opportune autorizzazioni puoi usare SphinxSearch senza problemi.
      Per il resto seguendo questa guida non dovresti incontrare nessun problema,
      fammi sapere!

      Ciao

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>