Développement avancé avec eZ Find (partie 1 : La gestion des datatypes entre eZ Find & Solr)
- Publié le 09 mai 2010
- 7 commentaire(s)
- Catégorie : Technologies Web
Après 2 billets un peu "rapides" sur eZ Find et la gestion des datatypes, ainsi que l'utilisation des facettes pour construire un nuage de tags, voici le premier billet d'une série de tutoriels à propos d'eZ Find, qui décrivent plus en détail son fonctionnement et son utilisation avancée dans divers contextes. Cette série de tutoriels introduit quelques nouveautés de la version 2.2, sera traduite progressivement sur le share.ez.no, et servira de base pour une conférence de la eZ Conference 2010, ainsi qu'aux Recontres Mondiales du Logiciel Libre 2010
Cet article décrit comment eZ Find transforme et adapte les contenus eZ Publish, et leurs datatypes respectifs pour les indexer dans Solr. La compréhension de ces mécanismes bas niveaux d'eZ Find sont des prérequis indispensables lors des phases de développement et de debug, ne serait ce que pour savoir ou chercher et lire les portions de codes permettant de comprendre le rôle exact d'un settings, d'un paramètre ou d'un filtre.
Etape 1 : Prérequis avant de démarrer
Cet article n'a pas vocation à expliquer à nouveau comment installer et indexer son contenu avec eZ Find. La documentation décrit avec précision les opérations à effectuer. Cependant voici quelques astuces permettant de développer dans de bonnes conditions :
Relancer l'indexation du contenu après une modification
Il est parfois laborieux de relancer une indexation complète juste pour tester l'impact d'une modification mineure. Alors il existe pour cela quelques paramètres cachés dans le script /bin/php/updatesearchindexsolr.php, qui permettent de désigner un noeud parent de départ, ainsi q'une limite (attention les 3 paramètres combinés sont nécessaires) :
php extension/ezfind/bin/php/updatesearchindexsolr.php --siteaccess=monsiteaccess --topNodeID=2546 --offset=0 --limit=10
Vérifier ce que Solr a réellement indexé
Pour savoir si vos contenus et vos attributs sont correctement indexés, il suffit d'effectuer une recherche dans l'interface Web d'administration de Solr : http://localhost:8983/solr/admin/. Cette interface est également utile pour vérifier comment les champs Solr ont été nommés, par exemple sur la version d'eZ Find 2.2, on peut observer 2 champs qui semblent des doublons concernent les titres des articles : attr_title_s et attr_title_t. La suite du billet détaille le comment et le pourquoi de ce comportement.
Debug direct avec Solr
En laissant une console active, pour pourrez observer les messages envoyés vers Solr de la forme :
INFO: [] webapp=/solr path=/select params={ ... MESSAGE ... } status=400 QTime=5
Ce message peut être copier / coller à partir de la console, vers la fin de l'URL dans l'interfaçe d'administration de Solr : http://localhost:8983/solr/select/?MESSAGE. On obtient ainsi une sortie exacte de ce que Solr envois à eZ Find avant transformation. Cette manipulation est utile lors des phases de Debug, par exemple en manipulant directement le message pour obtenir exactement le résultat attendu.
Etape 2 : Comment eZ Find pousse le contenu eZ Publish vers Solr
Voici le parcours d'exécution du code lors de l'ajout / modification d'un contenu eZ Publish :
-
Exécution de la méthode registerSearchObject, de la classe eZContentOperationCollection
Si DelayedIndexing activé (voir détail ci dessous) : ajout d'objectID à la table 'ezpending_actions' pour un traitement ultérieur - Si DelayedIndexing désactivé, fetch de l'objet et transmission de l'objet à la méthode eZSearch::addObject( $object, $needCommit )
- Si eZ Find installé et activé, appel de la méthode eZSolr::addObject( $contentObject, $commit = true )
- Au final, une fois les contenus préparés, appel de la méthode addDocs de la classe /extension/ezfind/classes/ezsolrbase.php, qui POST ensuite les données via HTTP à l'aide de cURL
eZ Find, un plug-in de recherche
eZ Find est construit comme un plug-in de recherche, c'est à dire que le module /content/search a été nativement construit pour être déporté sous forme de plug-in. Ainsi dans l'extension /ezfind/settings/site.ini.append.php on trouve la déclaration du plug-in :
[SearchSettings] SearchEngine=ezsolr
C'est ensuite la méthode getEngine() (kernel/classes/ezsearch.php) qui s'occupe d'affecter la bonne classe PHP pour interfacer le plug-in de recherche, à savoir : /search/plugins/ezsolr/ezsolr.php
eZ Find et le mécanisme natif du DelayedIndexing
Lors des différentes opérations de mises à jours de contenus, la méthode addObject de la classe eZSolr sera invoqué. Ce mode de fonctionnement en plug-in permet également d'hériter des autres mécanismes natifs de la recherche eZ Publish, comme par exemple le DelayedIndexing, qui permet de déporter l'indexation (complète ou par classes) vers une tache planifiée : indexcontent.php :
[SearchSettings] DelayedIndexing=disabled|enabled|classbased DelayedIndexingClassList[] DelayedIndexingClassList[]=mycontentclass
A noter : Cette technique est relativement efficace pour optimiser les temps de réponses Back Office, ou les imports de contenus régulier. Cependant, le DelayedIndexing souffre de quelques limites, puisqu'il est générique (et non optimisé spécifiquement pour eZ Find) et qu'il se contente donc de boucler sur la table 'ezpending_actions' afin d'indexer les objets un par un sans se préoccuper des autres finesses de Solr, comme par exemple l'ajout massif de contenus à indexer, suivi d'un unique 'commit'.
Etape 3 : Le fonctionnement de la méthode addObject
La méthode addObject (/search/plugins/ezsolr/ezsolr.php) reçoit :
- un unique objet de contenu en paramètre
- un paramètre optionnel indiquant s'il faut 'commiter' ou non le contenu ajouté (une très bonne façon d'optimiser les indexations massives de contenus)
Cette méthode agit de la façon suivante, dans les grandes lignes :
- Vérification s'il faut indexer ou non le contenu, en fonction des classes exclues (settings : [IndexExclude])
- Récupération des méta données de l'objet, et création des noms et valeurs des champs pour Solr
- Récupération des méta données des noeuds, et création des noms et valeurs des champs pour Solr
- Récupération des données des attributs de l'objet, dans chacune des langues, et création des noms et valeurs des champs pour Solr
- Insertion dans l'index de Solr de l'ensemble des données collectées, en mono ou multicore selon les settings
- Commit final, en fonction du paramètre optionnel de la méthode addObject
A noter : Depuis eZ Find 2.2, il est possible d'utiliser des 'cores' spécifiques à chaque langues (/extension/ezfind/java/solr.multicore), ce qui permet de dédier des index et des fichiers de configurations spécifiques à chaque langue (spellings.txt, synonmys.txt, stopwords.txt, etc.)
Etape 4 : Les nommage des champs côté Solr
Il est nécessaire de revenir sur la façon dont eZ Find nomme les champs transmis à Solr. Les principales techniques d'exploitations avancées d'eZ Find pour eZ Publish nécessitent de bien comprendre la sémantique et le mécanisme de nommage des champs.
C'est la classe /ezfind/classes/ezfsolrdocumentfieldbase.php, ou d'éventuelles classes héritées pour certains datatypes complexes (voir ma contribution ezfsolrdocumentfieldobjectrelation par exemple) qui a vocation à créer les noms des champs pour Solr, en respectant une sémantique très précise. On obtient ainsi la sémantique suivante :
Le nom des attributs :
- Nom Solr : attr_[contentattributename]_[contentattributetype], exemple : 'attr_title_s'. Il faut noter l'absence de l'identifiant de la classe, ce qui ouvre des perspectives d'exploitation des attributs Solr pour filtrer plusieurs classes sur des attributs homonymes (l'objet d'un prochain billet).
-
Mapping dans un Fetch eZ Find (filtre par exemple) : [contentclassname]/[contentattributename]/[contentsubattributename], par exemple 'article/title'.
Le nom de la classe 'article' est utilisé comme un filtre supplémentaire lors de la construction de la requête - Le 'title' est tranformé en 'attr_title_s', le _s étant déduit de settings eZ Find (voir ci-dessous)
Le nom des métadonnées :
- Nom Solr : meta_[metadataname]_[metadatatype], exemple : meta_class_identifier_s
- Mapping dans un Fetch eZ Find (tri par exemple) : usage interne, par exemple pour un tri par 'class_identifier'
Le nom des sous-attributs (inexploité par défaut) :
- Nom Solr : subattr_[contentattributename]-[contentsubattributename]_[contentsubattributetype], example : subattr_relatedimage-alttext_s
Nativement, les sous attributs sont peu ou pas exploités. C'est par contre un formidable outil pour étendre le fonctionnement d'eZ Find et indexer des champs supplémentaire. Voir par exemple ma contribution : ezfsolrdocumentfieldobjectrelation, qui indexe tous les attributs des objets en relations, en les stockant dans des sous attributs, ce qui permet ensuite d'effectuer toutes les opérations nécessaires sur ces sous attributs (recherche, filtre, facettes), selon la syntaxe 'myclass/myattribute/mysubattribute'. Les prochains billets détailleront comment exploiter ce mécanisme pour bien d'autres usages.
Etape 5 : La gestion des types de champs côté eZ Find
Dans les noms de champs Solr, la dernière information désigne le type de champs, et donc comment Solr va devoir considérer l'information (entre un string, un texte, une date, un tableau, etc.)
Coté eZ Find, cette définition se fait comme toujours dans les settings. Depuis eZ Find 2.2, il est maintenant possible de définir un type de champs spécifique à chaque contexte d'utilisation :
- DatatypeMap[] : le setting global, s'appliquant à tous les contextes par défaut
- DatatypeMapSort[] : settings spécifique pour les tris
- DatatypeMapFacet[] : settings spécifique pour les facettes
- DatatypeMapFilter[] : settings spécifique pour les filtres
Par exemple, par défaut, dans la version actuelle d'eZ Find 2.2, les attributs de type 'textline' sont définis différemment pour les tris :
- DatatypeMap[ezstring]=text
- DatatypeMapSort[ezstring]=string
L'impact au niveau de Solr, c'est que tous les attributs de type 'textline' auront systématiquement 2 champs de correspondance :
- attr_title_t (utilisé pour la recherche, les facettes et les filtres)
- attr_title_s (utilisé pour les tris)
A noter : il est conseillé d'utiliser également le type 'string' pour les facettes, afin de considérer le caractère espace comme un caractère lambda, et ainsi obtenir des facettes de type 'ma facette', plutôt que 'ma' et 'facette'.
Etape 6 : La gestion des types de champs côté Solr
Solr possède un fichier de configuration permettant à eZ Find de lui spécifier que le '_s' signifie un string, le '_t' un texte, etc. Il s'agit du fichier /ezfind/java/solr/conf/schema.xml
Ce fichier de configuration contient la définition d'un certain nombre de noms de champs en dur (pour les meta-données par exemple), mais définie également les correspondances pour tous les noms de champs dynamiques (nos fameux attributs de classes eZ Publish) :
<dynamicField name="*_i" type="int" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_f" type="float" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_d" type="double" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_si" type="sint" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_sf" type="sfloat" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_sd" type="sdouble" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_s" type="string" indexed="true" stored="true" multiValued="true" termVectors="true"/> <dynamicField name="*_sl" type="slong" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_l" type="long" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_t" type="text" indexed="true" stored="true" multiValued="true" termVectors="true"/> <dynamicField name="*_b" type="boolean" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_dt" type="date" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_random" type="random" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_k" type="keyword" indexed="true" stored="true" multiValued="true"/> <dynamicField name="*_lk" type="lckeyword" indexed="true" stored="true" multiValued="true"/> <!-- some trie-coded dynamic fields for faster range queries --> <dynamicField name="*_ti" type="tint" indexed="true" stored="true"/> <dynamicField name="*_tl" type="tlong" indexed="true" stored="true"/> <dynamicField name="*_tf" type="tfloat" indexed="true" stored="true"/> <dynamicField name="*_td" type="tdouble" indexed="true" stored="true"/> <dynamicField name="*_tdt" type="tdate" indexed="true" stored="true"/> <!-- geopoint for geospatial/location searches, boosting, ... --> <dynamicField name="*_gpt" type="geopoint" indexed="true" stored="true"/>
Ce fichier permet aussi de définir des comportements plus complexes sur certains datatypes eZ Publish, comme par exemple les mots clés (keyword). On y trouve par exemple 2 types de champs différents pour la gestion des keywords ('keyword' pour un respect de la casse et 'lckeyword' pour une casse en lowercase), qui peuvent etre exploité indifféremment au niveau d'eZ Find (DatatypeMap).
<fieldtype name="lckeyword" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="solr.PatternTokenizerFactory" pattern=", *" /> <filter class="solr.TrimFilterFactory" /> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.PatternTokenizerFactory" pattern=", *" /> <filter class="solr.TrimFilterFactory" /> <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.RemoveDuplicatesTokenFilterFactory"/> </analyzer> </fieldtype>
La définition des keywords est riche d'enseignement sur la configuration de Solr. On peut observer le fonctionnement des appels des filtres Solr, et comment sont traités les séparations de mots par des virgules (PatternTokenizerFactory), la gestion de la casse (LowerCaseFilterFactory), ou encore la suppression des doublons (RemoveDuplicatesTokenFilterFactory), etc.
Que boire avec ce billet ?
Domaine Richard Leroy - Les Noëls de Montbenault - Blanc Sec 2006
| Région : | Loire |
| Appellation : | Anjou |
| Domaine : | Domaine Richard Leroy |
| Couleur : | |
| Stock : | 1 |
| Notation : | |
| Prix : | 16 € |
| Commentaire(s) : | 2 Commentaire(s) |
Sujet intéressant
Merci Gilles pour ce premier tuto ! Très utile. Va nous permettre de mieux appréhender le fonctionnement d'eZ Find
Ce qui manquait...
C'est ce qui manquait ! On ne doit pas juste savoir comment utiliser mais aussi comment ça marche^^
Merci !
Bravo
Oui, bravo pour le défrichage...
Nécessaire.
Merci pour les encouragements
Merci pour les encouragements, j'en ai besoin pour la rédaction des prochains billets ![]()
Très interessant ! (+ une question :) )
Merci Gilles, pour ce contenu très enrichissant.
Or est ce que tu as une idée sur la façon avec la quelle ezfind / solr, gère le sort_by sur un attribue de type relation objet multiple ?
Merci et A+
Sort_by et relation d'objets multiple
Pour cela, il faut tester ma contribution :
http://projects.ez.no/ezfsolrdocumentfieldobjectrelation
C'est fait .....
ca y est c'est cool comme tutos c 'est mis en place dans un de mes projets ....
