La recherche Full Text avec Solr

Configurer un moteur de recherche performant à l'aide d'Apache Lucene/Solr et Apache Tomcat
Solr


précédentsommairesuivant

V. Maintenance des données d'un index

Les données d'index Solr peuvent être mises à jour avec un document au format CSVUpdating a Solr Index with CSV ou XMLUpdating a Solr Index with XML. D'après le fichier solrconfig.xml d'exemple, les formats javabin et JSONUpdating a Solr Index with JSON sont aussi disponibles mais la documentation à ce sujet est moins abondante et je n'ai pas vérifié moi-même. Quel que soit son format, le document doit être soumis à Solr via la méthode HTTP POST. Dans les paragraphes suivants, nous allons voir comment le document doit être structuré et de quelle manière nous pouvons l'envoyer à Solr.

Le format XML a ma préférence sur le format CSV car il est plus facile à relire que ce dernier, surtout dans le cas des champs multivalués. Avec un document CSV, les choses se compliquent dès que le texte à indexer contient le caractère de séparation de champ ou un saut de ligne (ce qui est une situation plutôt courante).

V-A. Configuration nécessaire

Afin de pouvoir envoyer des mises à jour de l'index au noyau, il nous faut configurer le noyau avec le requestHandler que nous utiliserons :

Tous les formats (solrconfig.xml)
Sélectionnez
<requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
<requestHandler name="/update/javabin" class="solr.BinaryUpdateRequestHandler" />
<requestHandler name="/update/csv" class="solr.CSVRequestHandler" startup="lazy" />
<requestHandler name="/update/json" class="solr.JsonUpdateRequestHandler" startup="lazy" />

Dans la mesure où il est peu raisonnable de développer et de maintenir plusieurs manières de mettre un index à jour, vous n'aurez probablement besoin que d'un seul requestHandler "update". Ainsi, vous pouvez déclarer uniquement le handler de base "/update" et choisir sa classe Java en fonction de vos besoins :

Format XML (solrconfig.xml)
Sélectionnez
<requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
Format javabin (solrconfig.xml)
Sélectionnez
<requestHandler name="/update" class="solr.BinaryUpdateRequestHandler" />
Format CSV (solrconfig.xml)
Sélectionnez
<requestHandler name="/update" class="solr.CSVRequestHandler" startup="lazy" />
Format JSON (solrconfig.xml)
Sélectionnez
<requestHandler name="/update" class="solr.JsonUpdateRequestHandler" startup="lazy" />

V-B. Ajout et modification de données

Le document XML est construit de la manière suivante :

 
Sélectionnez
<add>
    <doc>
        <field name=""></field>
        <field name=""></field>
        <field name=""></field>
    </doc>
    <doc>
        <field name=""></field>
        <field name=""></field>
        <field name=""></field>
    </doc>
</add>

Des exemples plus complets sont distribués avec Solr (6).

Chaque nœud <doc> correspond à un document de l'index. Il contient l'ensemble des champs définis dans le fichier schema.xml pour ce noyau.

Les champs définis avec l'attribut required="true" dans le schéma doivent obligatoirement figurer pour chaque nœud <doc>. Un même champ peut apparaître plusieurs fois dans le même nœud <doc> s'il s'agit d'un champ multivalué, c'est-à-dire défini avec l'attribut multivalued="true" dans le schéma. Les autres champs ne peuvent apparaître qu'une seule fois pour chaque nœud <doc>.

Comme nous l'avons vu dans le chapitre précédent, la contrainte d'unicité d'un index est le champ défini comme <uniqueKey> dans le schéma. Pour Solr, il n'y a pas de distinction entre les opérations "create" et "update" des documents : lorsque le requestHandler de mise à jour est appelé pour une certaine uniqueKey, Solr s'occupe de créer le document correspondant s'il n'existait pas encore, ou de le modifier s'il existait déjà.

Voici les attributs optionnels pour chaque nœud XML du document de mise à jour :

Tableau 19 : Attributs optionnels du document de mise à jour selon son type
Nœud Attribut Valeurs Description
add overwrite true | false Remplacer les documents ayant la même uniqueKey
Défaut à "false"
add commitWithin millisecondes Valider le document après ce délai
doc boost float Augmenter la pertinence de ce document complet pour la recherche (si omitNorms="false" dans le schéma)
Défaut à "1.0"
field boost float Augmenter la pertinence de ce champ pour la recherche (si omitNorms="false" dans le schéma)
Défaut à "1.0"

Lors de la configuration des champs de l'index par l'intermédiaire du fichier schema.xml, les champs déclarés comme "dest" de <copyField/> ne doivent pas figurer dans les mises à jour. Par exemple, pour le schéma donné dans cet article, nous pouvons résumer la liste des champs par le tableau suivant :

Tableau 20 : Les champs à inclure dans le document de mise à jour
Champ schema:copyField schema:field[required] Présence dans doc. de màj
uuid non défini oui oui, obligatoire
productNameEnDisplay source non oui, facultatif
productNameFrDisplay source non oui, facultatif
productNameEnAutoComplete dest non non
productNameFrAutoComplete dest non non
productNameEnSearch dest non non
productNameFrSearch dest non non
manufacturerNameDisplay source non oui, facultatif
manufacturerNameAutoComplete dest non non
manufacturerNameEnSearch dest non non
manufacturerNameFrSearch dest non non
allEnSearch dest non non
allFrSearch dest non non

Cela pourrait donner le document XML suivant :

 
Sélectionnez
<add>
    <doc>
        <field name="uuid"></field>
        <field name="productNameEnDisplay"></field>
        <field name="productNameFrDisplay"></field>
        <field name="manufacturerNameDisplay"></field>
    </doc>
</add>
Les champs suivants de l'index sont remplis par l'intermédiaire de copyField :
  • productNameEnAutoComplete
  • productNameFrAutoComplete
  • productNameEnSearch
  • productNameFrSearch
  • manufacturerNameAutoComplete
  • manufacturerNameEnSearch
  • manufacturerNameFrSearch
  • allEnSearch
  • allFrSearch

V-C. Suppression de données

La suppression de documents d'un index se fait au moyen d'un document delete contenant une combinaison de nœuds id et query :

Supprimer tous les documents de l'index
Sélectionnez
<delete>
    <query>*:*</query>
</delete>
Supprimer l'ID 05991
Sélectionnez
<delete>
    <id>05991</id>
</delete>
Supprimer les ID 05991 et 06000 ainsi que les bureaux Bridgewater et Osaka
Sélectionnez
<delete>
    <id>05991</id>
    <id>06000</id>
    <query>office:Bridgewater</query>
    <query>office:Osaka</query>
</delete>

La syntaxe du nœud query pour la suppression de données est la même que pour la recherche avec un searchHandler. Nous aborderons cela plus loin dans l'article.

Le nom du nœud id est figé, il ne peut pas prendre le nom d'un champ du schéma. Solr s'attend à trouver le contenu de ce nœud dans le champ défini comme uniqueKey dans le schéma. Pour le schéma présenté dans cet article, les deux requêtes suivantes sont équivalentes :

 
Sélectionnez
<delete>
    <id>aaaa</id>
</delete>
 
Sélectionnez
<delete>
    <query>uuid:aaaa</query>
</delete>

V-D. Validation de mises à jour

La validation des mises à jour se fait par les commandes suivantes :

Valider les modifications
Sélectionnez
<commit/>
Valider les modifications et optimiser l'index
Sélectionnez
<optimize/>

Voici les attributs optionnels du document de mise à jour :

Tableau 21 : Attributs optionnels des commandes de validation des mises à jour
Nœud Attribut Valeurs Description
commit et optimize waitFlush true | false Bloquer jusqu'à ce que les modifications de l'index soient écrites sur le disque
Défaut à "true"
commit et optimize waitSearcher true | false Bloquer jusqu'à ce qu'un nouveau chercheur soit ouvert et enregistré comme le chercheur principal, rendant ainsi les modifications visibles
Défaut à "true"
commit expungeDeletes true | false Ignorer les suppressions
Défaut à "false"
optimize maxSegments int Optimiser jusqu'à ce nombre de segments individuels
Défaut à "1"

V-E. Annulation de mises à jour

La commande rollback permet d'annuler toutes les commandes add et delete depuis la dernière commande commit ou optimize :

 
Sélectionnez
<rollback/>

V-F. Soumettre le document de maintenance

L'envoi d'un document de maintenance à Solr se fait via la méthode HTTP POST au requestHandler "update" de notre noyau, par exemple :
http://localhost:8080/solr/CORENAME/update

V-G. Exemple

Préparons un XML à envoyer :

add1.xml
Sélectionnez
<add>
    <doc>
        <field name="uuid">f2446de21f011a769ec62b4c4ecb96d2</field>
        <field name="productNameEnDisplay">Solr, the enterprise search server</field>
        <field name="productNameFrDisplay">Solr, le serveur de recherche pour entreprises</field>
        <field name="manufacturerNameDisplay">Apache Software Foundation</field>
    </doc>
</add>

Envoyons ce XML à l'aide de cURL :

Envoi avec cURL
Sélectionnez
curl http://localhost:8080/solr/CORENAME/update -H "Content-Type: text/xml" --data-binary "<delete><query>*:*</query></delete>"
curl http://localhost:8080/solr/CORENAME/update -H "Content-Type: text/xml" --data-binary "INSERER_ICI_TOUT_LE_XML"
curl http://localhost:8080/solr/CORENAME/update -H "Content-Type: text/xml" --data-binary "<optimize waitSearcher='false'/>"

cURL est le logiciel habituellement utilisé pour cette démonstration mais vous n'êtes pas obligés d'y avoir recours. Vous pouvez utiliser le programme de votre choix, voire développer un petit script ou programme avec le langage de votre préférence.

Le code suivant est un exemple de script PHP pouvant fonctionner avec une installation PHP par défaut (ni le programme cURL ni l'extension php_curl ne sont nécessaires) :

send.php
Sélectionnez
#!/usr/bin/php5
<?php

if(PHP_SAPI != 'cli')
{
    die('error: not sent via CLI'.PHP_EOL);
}

if($argc != 4 or !in_array($argv[2], array('file', 'string')))
{
    die('usage is: '.basename(__FILE__).' CORENAME "file"|"string" FILENAME|CONTENTS'.PHP_EOL);
}

list(, $core_name, $content_type, $content) = $argv;
$url = sprintf('http://localhost:8080/solr/%s/update', $core_name);
$data = $content_type == 'string' ? $content : file_get_contents($content);

$params = array
(
    'http' => array (
        'method' => 'POST'
        , 'header' => 'Content-Type: text/xml'
        , 'content' => $data
        , 'timeout' => 5
    )
);

$context = stream_context_create($params);
$result = file_get_contents($url, FALSE, $context);

var_dump($result);
echo 'done'.PHP_EOL;
Exemple d'utilisation en lignes de commandes (Linux et MacOS) :
Sélectionnez
./send.php produits string "<delete><query>*:*</query></delete>"
./send.php produits file add1.xml
./send.php produits string "<optimize waitSearcher='true'/>"
Exemple d'utilisation en lignes de commandes (Windows) :
Sélectionnez
php.exe send.php produits string "<delete><query>*:*</query></delete>"
php.exe send.php produits file add1.xml
php.exe send.php produits string "<optimize waitSearcher='true'/>"

Pour vérifier que les modifications ont bien été effectuées, vous pouvez charger la page suivante :
http://localhost:8080/solr/admin/cores?core=CORENAME&action=status

core status
Image 8 : Mise à jour réussie

Afin de vérifier plus précisément ce qui a été fait par Solr, notamment que les directives copyField ont réussi, voici une requête simple sur l'index :
http://localhost:8080/solr/produits/select?q=uuid:f2446de21f011a769ec62b4c4ecb96d2

select uuid
Image 9 : Vérifier que les données sont dans l'index
Rappelons les champs envoyés à Solr :
  • uuid
  • productNameEnDisplay
  • productNameFrDisplay
  • manufacturerNameDisplay

La capture d'écran ci-dessus montre que Solr a bel et bien rempli tous les champs de l'index d'après les règles copyField. Comme prévu, certains champs de l'index contiennent plusieurs valeurs.


précédentsommairesuivant
À titre d'exemple, le repository SVN de Solr propose des documents dans différents formatsDocuments de mise à jour d'un index Solr

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2010 Guillaume Rossolini. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.