Vous êtes sur la page 1sur 4

Plugin de moteur de recherche multi-modèles

Nous vous proposons un plugin pour intégrer un moteur de recherche interne multi-modèles à une application
CakePHP. Ses caractéristiques sont les suivantes :

 Utilise les index Full-Text de MySQL.


 Facile à installer : il suffit de télécharger les fichiers et de créer une seule table, quel que soit le nombre
de Modèles à indexer.
 Non-intrusif : inutile de créer d’index Full-Text sur les tables existantes.
 Plusieurs mode de recherche : langage naturel, langage naturel avec extension de requête, et recherche
booléenne.
1. Installation
1.1. Fichiers
Le code source du plugin Search est hebergé sur Github.com :

http://github.com/kalt/search/tree/master
Deux méthodes pour installer les fichiers : soit en cliquant sur ‘download’ puis en extrayant le répertoire ‘search’
vers le répertoire ‘plugins’ de l’application, soit en exécutant la commande suivante (pour les familiers de Git) :

git clone git://github.com/kalt/search.git

1.2. DB table
Nous devons créer une table dans la base de données selon le schéma inclu
ici :search/config/sql/search.sql
2. Mise en place
2.1. Modèles
Nous allons lier les modèles que nous voulons indexer au comportement SearchableBehavior, en donnant la liste
des champs à indexer.

class Article extends AppModel


{
var $actsAs = array('Search.Searchable' => array(
'fields' => array('title', 'body')
));
}

C’est la seule chose à faire. Dès qu’un enregistrement sera ajouté ou mis à jour, les champs ‘title’ et ‘body’
seront inclus dans l’index de recherche.

2.2. Formulaire de recherche


Créons maintenant un petit formulaire de recherche. La plupart du temps, la meilleure place pour ce genre de
fonction est dans le layout commun à toutes les pages du site : le moteur de recherche est ainsi disponible sur le
site entier.

Le formulaire doit obligatoirement contenir un champ texte nommé ‘q’ (« q » pour « query »).

echo $form->create('Search', array('url' => array(


'plugin' => 'search',
'controller' => 'searches',
'action' => 'index'
)));
 
echo $form->input('q', array('label' => 'Mots clés :'));
 
echo $form->end("Rechercher");

2.3. Pages de résultats


Nous allons maitenant créer la vue qui va afficher les résultats paginés de la recherche :
{app}/views/plugins/search/searches/index.ctp
Les variables disponibles dans cette vue sont :

 $q : les termes recherchés.


 $data : les enregistrements paginés correspondants à la recherche.
Exemple :

<?php $paginator->options(array('url' => $this->passedArgs)); ?>


 
<h1>Résultats de la recherche</h1>
 
<p>Votre recherche : <?php echo $q; ?></p>
 
<div id="paginator-counter">
<?php echo $paginator->counter(array('format' => "Page %page% sur %pages%, %current% documents sur
%count%")); ?>
</div>
 
<?php foreach($data as $row):
$model_name = key($row);
 
switch($model_name)
{
case 'Article':
$link = $html->link($row['Article']['title'], array(
'plugin' => null,
'controller' => 'articles',
'action' => 'view',
$row['Article']['id']
));
$description = $row['Article']['body'];
break;
 
case 'Video':
$link = $html->link($row['Video']['title'], array(
'plugin' => null,
'controller' => 'videos',
'action' => 'play',
$row['Video']['id']
));
$description = $row['Video']['description'];
break;
} ?>
<div class="ressource">
<h2><?php echo $link; ?></h2>
<p align="justify"><?php echo $description; ?></p>
</div>
<?php endforeach; ?>
 
<div class="paging">
<?php echo $paginator->prev('<< '.__('Previous', true));?>
| <?php echo $paginator->numbers();?>
<?php echo $paginator->next(__('Next', true).' >>');?>
</div>

3. Options
3.1. Modes de recherche
Deux types de recherche sont disponibles :

 boolean (défaut) : MySQL effectue une recherche booléenne, c’est-à-dire que tous les termes de la
recherche doivent être présents dans les résultats.
 natural : MySQL effectue une recherche en langage naturel et retourne les résultats par ordre
décroissant de pertinence.
Plus d’informations sur la recherche en texte intégral sont disponibles sur la documentation de MySQL.
Pour changer de mode, il suffit d’ajouter la ligne suivante dans{app}/config/bootstrap.php
Configure::write('Search.mode', 'natural');

3.2. Extension de requête


Il s’agit d’une option du mode de recherche en langage naturel. Plus d’infos ici : recherche en texte intégral avec
extension de requête.
Cette option est par défaut à null : la recherche avec extension de requête sera activée si l’expression
recherchée ne contient qu’un seul mot.
Pour changer cette option, il suffit d’ajouter cette ligne dans {app}/config/bootstrap.php
Configure::write('Search.withQueryExpansion', true/false);

Si false, la recherche avec extension ne sera jamais utilisée, quelle que soit l’expression cherchée. Si true,
la recherche avec extension sera toujours utilisée.
3.3. Caractères autorisés dans l’expression recherchée
De base, les caractères acceptés sont les lettres et les chiffres. Par défaut, nous avons ajouté l’espace, les lettres
accentuées, la cédille et le « o-e collés ».

Il est possible de remplacer cette liste de caractères autorisés en ajoutant cette ligne
dans{app}/config/bootstrap.php
Configure::write('Search.allowedChars', array(' '));

Ici par exemple, nous autorisons l’espace ‘ ‘. Au final donc, tous les signes qui ne sont ni des lettres, ni des
chiffres, ni un espace, seront supprimés de l’expression à chercher.

4. Réécriture de l’URL
Par défaut, l’URL des résultats de recherche est : /search/searches/mots+cles
Nous pouvons changer cette URL en créant une nouvelle route dans{app}/config/routes.php
Router::connect(
'/recherche/*',
array('plugin' => 'search', 'controller' => 'searches', 'action' => 'index')
);

L’URL deviendra alors /recherche/mots+cles.


5. Indexer des données existantes
Dans le cas où nous souhaiterions installer le plugin dans une application existante dont les tables à indexer
contiennent déjà des données, il nous suffit d’ajouter les 3 actions suivantes
dans {app}/app_controller.php
/**
* Construit l'index des données existantes d'un modèle
*/
function admin_build_search_index()
{
$this->autoRender = false;
 
$model =& $this->{$this->modelClass};
 
if(!isset($model->Behaviors->Searchable))
{
echo "Erreur : le modèle {$model->alias} n'est pas lié au SearchableBehavior.";
exit;
}
 
$data = $model->find('all');
 
foreach($data as $row)
{
$model->set($row);
 
$model->Behaviors->Searchable->Search->saveIndex(
$model->alias,
$model->id,
$model->buildIndex()
);
}
 
echo "L'index des données du modèle {$model->alias} a été créé.";
}
 
/**
* Supprime l'index des données d'un modèle
*/
function admin_delete_search_index()
{
$this->autoRender = false;
 
$model =& $this->{$this->modelClass};
 
if(!isset($model->Behaviors->Searchable))
{
echo "Erreur : le modèle {$model->alias} n'est pas lié au SearchableBehavior.";
exit;
}
 
$model->Behaviors->Searchable->Search->deleteAll(array(
'model' => $model->alias
));
 
echo "L'index des données du modèle {$model->alias} a été supprimé.";
}
 
/**
* Reconstruit l'index des données existantes d'un modèle
*/
function admin_rebuild_search_index()
{
$this->admin_delete_search_index();
$this->admin_build_search_index();
}

Ceci fait, nous accèdons à une URL du style/admin/{uncontroleur}/buildsearch_index pour


construire l’index des données existantes du modèle de ce contrôleur. Attention, cela peut prendre un certain
temps, en fonction du volume de données à indexer.
Toutes les suggestions d’amélioration et les critiques sont les bienvenues dans les commentaires.

Vous aimerez peut-être aussi