Indexation de contenus multi-langue sur Rails3 avec Sphinx et Globalize3

Ruby On Rails
Par mick
16 novembre 2011
sphinx

Sphinx est un serveur de recherche full text permettant d’indexer et de rechercher dans des données stockées soit dans des bases de données SQL, no SQL ou alors dans un système de fichiers.

Il peut facilement s’intégrer à une application Ruby On Rails via la gem Thinking Sphinx. On définit alors dans les modèles tous les attributs qui doivent être indexés. Cela fonctionne parfaitement lorsque notre application utilise une seule et unique locale.

Prenons l’exemple d’une application dans laquelle nous avons défini un modèle Actuality :

class Actuality < ActiveRecord::Base

  validates :title, :presence => true
  validates :body, :presence => true

  define_index do
    indexes :title
    indexes :summary
    indexes :body

    set_property :delta => true
  end
end

Que se passe-t’il donc lorsque l’application développée est internationalisée et que les traductions des contenus stockés en base doivent être indexés par locale ?

Avant d’arriver au résultat final, jetons un coup d’oeil rapide sur la gestion de la traduction des contenus.

Nous utilisons pour cela la gem Globalize3 qui permet de stocker les traductions de certains attributs d’un modèle dans une table à part.

gem 'globalize3' # à placer dans le Gemfile

Ensuite, il faut indiquer au modèle Actuality à qui nous allons traduire un certain nombre de ces attributs

class Actuality < ActiveRecord::Base

  translates :title, :body

  validates :title, :presence => true
  validates :body, :presence => true

  define_index do
    indexes :title
    indexes :body

    set_property :delta => true
  end
end

Pour finir, il faut modifier la structure de la base de données pour ajouter la table contenant les attributs traduits

class AddTranlationsToActualities < ActiveRecord::Migration
  def self.up
    Actuality.create_translation_table! :title => :string, :body => :text
  end

  def self.down
    Actuality.drop_translation_table!
  end
end

Maintenant que les attributs title et body d’Actuality sont traduits via Globalize3, nous pouvons définir les index associés à chaque locale en précisant que les attributs qui doivent être indexés sont ceux de la table translations associée à notre modèle et que nous utilisons un filtre de sélection différent pour chaque locale :

class Actuality < ActiveRecord::Base

  translates :title, :body

  validates :title, :presence => true
  validates :body, :presence => true

  define_index('actuality_fr') do
    indexes translations.title, :as => :title
    indexes translations.body, :as => :body

    where "actuality_translations.locale='fr'"

    set_property :delta => true
  end

  define_index('actuality_de') do
    indexes translations.title, :as => :title
    indexes translations.body, :as => :body

    where "actuality_translations.locale='de'"

    set_property :delta => true
  end
end

Désormais comment utiliser les nouveaux index définis ? Nous pouvons tout simplement indiquer à la méthode search sur quel index rechercher.

Actuality.search "*#{q}*" , :index => "actuality_fr"
Actuality.search "*#{q}*" , :index => "actuality_de"

En conclusion, il est possible très simplement dans Rails3 de créer un moteur de recherche basé sur Sphinx et recherchant des contenus en fonction de la locale de l’utilisateur.

Auteur : Michaël Mithouard

Ajouter un commentaire

Articles similaires