Integriamo ElasticSearch e MongoDB

ElasticSearchQuando gli indici interni al database MongoDB non bastano, meglio affidarsi ad un prodotto specifico per implementare la ricerca. In questo post parliamo dell’integrazione tra MongoDB ed ElasticSearch come base per un servizio su Ruby on Rails

Sto lavorando ad un nuovo progetto per un cliente che ha la necessità di gestire qualche terabyte di archivi email: si tratta di uno storico di circa 10 anni di Mailing List per il quale si rende necessario sostituire il motore web di ricerca di MailMan con qualcosa di più scalabile e performante: la scelta è caduta su MongoDB ed ElasticSearch e vi racconto cosa ho imparato.

Il primo problema da affrontare è la dimensione dello storico che, essendo notevole, necessita di un sistema che scali orizzontalmente quando c’è la necessità di aumentare lo spazio: in questo caso il collaudato MongoDB è una sicurezza. La possibilità di attivare contemporaneamente replica e sharding permette di avere una sorta di “Raid 10” a livello di Database.

Veniamo ad ElastisSearch: francamente è la prima volta che utilizzo in produzione questo componente, per cui si sta rivelando una scoperta continua.

Per chi non lo conoscesse, ElasticSearch è un motore di ricerca in Java che si basa si Apache Lucene. Le funzionalità sono simili ad Apache Solr, ma, a differenza di questo, ha la possibilità di scalare orizzontalmente con più facilità.

La teoria di funzionamento di ElasticSearch è semplice: una volta installato, il demone resta in ascolto su una porta (di default la 9200) e comunica verso l’esterno con delle REST API attraverso le quali è possibile gestire gli indici, inviare i dati da indicizzare ed effettuare le ricerche.

Ecco le cinque cose che ho imparato in fase di implementazione dell’infrastruttura di staging con MongoDB ed ElasticSearch:

  1. l’integrazione di ElasticSearch con MongoDB: si trovano moltissimi manuali su come utilizzare il “river” per far parlare i due sistemi. Sostanzialmente il river tiene monitorato il file di log di MongoDB per aggiornare gli indici di ElasticSearch. Questa soluzione ha due problemi: il file di log viene generato dal sistema di replica di MongoDB ed, in una infrastruttura in cui è attiva sia la replica che lo sharding, si hanno X file di replica tanti quanti sono i nodi che compongono lo sharding per cui il river di ElasticSearch ha una visione parziale dei nuovi dati; inoltre è poco efficiente (lento). La soluzione è stata quella di utilizzare una gemma specifica a livello di webservice Ruby on Rails (mongoid-elasticsearch) che si occupa di aggiornare gli indici di ElasticSearch ad ogni modifica del database MongoDB.
  2. Cosa dare in pasto ad ElasticSearch: ovviamente è inutile far indicizzare il contenuto binario. In qualsiasi caso, a prescindere, ho scoperto che ElasticSearch è molto suscettibile alla codifica, per cui gradisce solo dati in formato UTF-8. Per forzare la codifica in UTF-8 in Rails ho usato Marshal.dump($dato).force_encoding("ISO-8859-1").encode("UTF-8")
  3. Ricerca e filtri di ElasticSearch: le query analizzano il risultato per assegnare un punteggio, mentre i filtri non lo fanno, pertanto quest’ultimi sono molto più veloci.
  4. La sintassi per query complesse è davvero prolissa: si tratta di codice json, anche se la gemma “maschera” in stile ruby.
  5. i filtri per “term” e per “terms”, gradiscono solo il minuscolo

Spero che questi pochi appunti di viaggio possano tornarvi utili per le Vostre implementazioni di ElasticSearch.

Leave a Reply

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

venti − 4 =