Dans cet article, nous parlerons de la création d’index en utilisant Zend Search Lucene.
Aujourd’hui dans la plupart des sites, les recherches sont alimentées par une base de données. Dans notre exemple, nous utiliserons MySQL.
Imaginez-vous sur mon blog, une personne vient sur mon site et souhaite effectuer une recherche avec n’importe quel mot clé. Pour donner des résultats à cette recherche, théoriquement, je dois chercher dans la table des articles ainsi dans la table des commentaires. L’exécution des requêtes SQL sur 2 tables est acceptable par conte dans le cas d’une application e-commerce, nous avons beaucoup plus de catégories et de produits. Les requêtes de base de données sont plus complexes et plus longues et elles consomment plus de ressources.
Un autre point important est que nous ne pouvons pas obtenir des résultats pertinents en premier, en général, nous ne pouvons également pas classer les résultats de la recherche.
Apache Lucene est performant, aux fonctionnalités complètes et entièrement écrit en Java. Il est utilisé dans la plupart des sites web 2.0. Zend_Search_Lucene est dérivé du projet Apache Lucene.
Dans l’exemple ci dessous nous considérons que l’objet Zend Db est déjà configuré et que la base de données contient quelques articles.
<?php
class SearchController extends Zend_Controller_Action {
private $_tCategories;
public function init(){
// Traitement Zend_Navigation
$this->_tCategories = new Model_DbTable_Categories();
}
public function indexAction()
{
// Récupération des articles
$adapter = $this->_tCategories->getDefaultAdapter();
$select = $adapter->select()
->from(array("c" => "categories"), array("c.id", "c.nom"))
->where("c.slug = 'actualite'")
->join(array("ac" => "articles_categories"), "c.id = ac.idCategorie")
->join(array("a" => "articles"), "ac.idArticle = a.id")
->order("a.datecreation DESC");
$data = $adapter->fetchAll($select);
// Test si je récupére des articles
if(is_array($data) && sizeof($data) > 0)
{
// Création d'un index
$index = Zend_Search_Lucene::create(BASE_PATH . '/decryptages_index');
// Insertion dans l'index de tous les articles récupérés par la requête
foreach ($data as $actu)
{
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::Keyword('slug', $actu["slug"]));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('id', $actu["id"]));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('dateCreation', $actu["dateCreation"]));
$doc->addField(Zend_Search_Lucene_Field::Text('titre', $actu["titre"]));
$doc->addField(Zend_Search_Lucene_Field::UnStored('content', $actu["content"]));
$doc->addField(Zend_Search_Lucene_Field::Text('categorie', $actu["nom"]));
$message .= "Ajout: ". $actu["titre"] ."<br />";
$index->addDocument($doc);
}
$index->commit();
$index->optimize();
}
$this->view->message = $message;
}
Détaillons les les différentes opérations de cette action :
Récupération des articles de la catégorie Actualité.
$adapter = $this->_tCategories->getDefaultAdapter();
$select = $adapter->select()
->from(array("c" => "categories"), array("c.id", "c.nom"))
->where("c.slug = 'actualite'")
->join(array("ac" => "articles_categories"), "c.id = ac.idCategorie")
->join(array("a" => "articles"), "ac.idArticle = a.id")
->order("a.datecreation DESC");
$data = $adapter->fetchAll($select);
Nous testons ensuite que je récupère bien des résultats dans ma requête.
if(is_array($data) && sizeof($data) > 0)
Création de notre index. Il faut spécifier le répertoire ou sera créer l’index. Dans mon cas l’index sera créé dans le répertoire public de mon application.
$index = Zend_Search_Lucene::create(BASE_PATH . '/decryptages_index');
Nous parcourons ensuite nos résultats afin de créer un document par article auquel nous ajoutons des champs et des contenus.
Comme vous pouvez le voir nous avons plusieurs types de champ. Pour comprendre quel champ choisir pour quelle donnée, une brève explication se trouve à la fin de cet article.
L’url étant unique à l’article nous l’indexons comme un type de champ Keyword.
Nous avons besoin de l’id de l’article et du datetime de création de l’article en affichage mais ils ne seront pas utilisés pour la recherche. Nous les stockerons comme type de champ UnIndexed.
Le titre est stockée sous forme de champ de type text.
Le contenu est indexé, mais n’est pas stocké dans l’index parce qu’il occuperait plus d’espace et il créerait un index plus grand sur le disque. Si nous en avons besoin pour la recherche, sans forcément afficher les données, le type de champ UnStored est préféré.
Une fois le document est créé et les champs ajoutés, nous devons ajouter le document à l’index.
foreach ($data as $actu)
{
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::Keyword('slug', $actu["slug"]));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('id', $actu["id"]));
$doc->addField(Zend_Search_Lucene_Field::UnIndexed('dateCreation', $actu["dateCreation"]));
$doc->addField(Zend_Search_Lucene_Field::Text('titre', $actu["titre"]));
$doc->addField(Zend_Search_Lucene_Field::UnStored('content', $actu["content"]));
$doc->addField(Zend_Search_Lucene_Field::Text('categorie', $actu["nom"]));
$message .= "Ajout: ". $actu["titre"] ."<br />";
$index->addDocument($doc);
}
Une fois toutes les données ajoutées à l’index, nous envoyons sauvegardons l’index.
$index->commit();
La commande ci dessous est utilisée pour optimiser l’index.
$index->optimize();
Comprendre les types de champ dans Zend Search Lucene
- Les champs Keyword sont stockés et indexés, ce qui signifie qu’ils peuvent être recherchées ainsi qu’affichées dans les résultats de recherche.
- Les champs UnIndexed ne sont pas recherchés, mais ils sont retournés avec les résultats de la recherche. Les timestamps de la base données, les clés primaires, les chemins de fichiers système, et d’autres identifiants externes sont de bons candidats pour les champs UnIndexed.
- Les champs Binary ne sont pas indexés mais sont stockés pour être récupérés avec les résultats de recherche. Ils peuvent être utilisés pour stocker toutes données encodées comme une chaîne binaire.
- Les champs Text sont stockés, indexés, et mis sous forme de jeton. Les champs de texte sont appropriés pour stocker des informations comme des sujets et des titres qui doivent être consultable aussi bien que retournés avec les résultats de la recherche.
- Les champs UnStored sont mis sous forme de jeton et indexés, mais pas stockés dans l’index. De grandes quantités de texte sont mieux indexées en utilisant ce type de champ. Stocker des données créent un index de taille plus importante sur le disque. Si vous avez besoin d’effectuer une recherche mais pas d’afficher les données, utilisez un champ UnStored. Les champs UnStored sont pratiques lorsque vous utilisez un index Zend Search Lucene en combinaison avec une base de données relationnelle. Vous pouvez indexer de gros champs avec des champs UnStored pour la recherche, et les récupérer à partir de votre base de données relationnelle en utilisant un champ séparé comme identifiant
| Type de champ | Stocké | Indexé | Mis en jeton (Tokenized) | Binaire | |
|---|---|---|---|---|---|
| Keyword | Oui | Oui | Non | Non | |
| UnIndexed | Oui | Non | Non | Non | |
| Binary | Oui | Non | Non | Oui | |
| Text | Oui | Oui | Oui | Non | |
| UnStored | Non | Oui | Oui | Non |
Aucun article en relation.
2 trackbacks
[...] « Zend Search Lucene : Création d’un index à partir de données stockées en base de d… Zend Search Lucene : Indexation en temps réél Par jbunel | Publié : 8 mars [...]
[...] Zend Search Lucene : Création d'un index à partir de données stockées dans une de données MySQL [...]