Imaginons que vous deviez écrire un composant, un gestionnaire de requêtes, ou tout autre morceau de code personnalisé devant être intégré à Solr, ou que vous ayez besoin de mieux comprendre certains aspects internes de Lucene/Solr en suivant précisément ce qui se passe dans le code.
Je sais, les tests unitaires, les tests d’intégration, tout cela pour s’assurer que tout fonctionne comme prévu ; mais ici, je parle de quelque chose de différent : lors du développement, il est (du moins pour moi) très utile d’avoir un environnement productif et de débogage qui permette, avec des itérations de développement courtes, de suivre pas à pas ce qui se passe dans le code, en analysant de près le fonctionnement des choses en coulisses.
Dans mon expérience, j’ai trouvé cela utile dans deux scénarios :
- Je dois écrire un add-on Solr : dans ce cas, je veux avoir un environnement de développement qui permette d’écrire et de déboguer du code le plus rapidement possible.
- Je dois étudier certains aspects internes de Solr : par exemple, si j’ai besoin de vérifier ce qui se passe au moment de la récupération des données quand un champ est à la fois
docValues="true"etstored="true". D’où Solr obtient-il la valeur du champ ?
Voyons comment accomplir cela en quelques minutes.
Étape #1 : Cloner le dépôt GitHub
Clonez le dépôt suivant : https://github.com/SeaseLtd/solr-addon-project-skeleton
Une fois importé dans votre IDE préféré, la structure du projet ressemblera à ceci :
Comme vous pouvez le voir, le projet modèle fournit :
- Un
TokenFilterpersonnalisé qui affiche simplement les tokens produits lors de l’analyse textuelle dans la sortie standard. Notez que c’est juste un exemple (utile si vous souhaitez déboguer un analyseur). J’aurais pu créer unSearchComponent, unTokenizerou tout ce dont j’aurais besoin. - Une configuration Solr d’exemple, avec un ensemble minimal de choses configurées.
- Une couche de test supertype (
BaseIntegrationTest) et un test d’exemple (Tests) qui charge des données, exécute une requête et affiche ensuite les résultats.
Étonnamment, c’est tout ! Il n’y a pas de deuxième étape !
Cas d'utilisation #1 : Implémenter, déboguer et tester un add-on
Comme mentionné précédemment, dans le dépôt d’exemple, nous avons déjà un simple add-on qui consiste en un TokenFilter qui affiche dans la sortie standard chaque token produit dans la chaîne d’analyse. Le filtre a été déclaré dans la configuration Solr comme faisant partie de l’analyseur du type de champ “text” :
...
La classe de test déclenche cet analyseur lorsqu’elle indexe certains documents. Si vous l’exécutez en tant que test JUnit classique, vous verrez la sortie suivante :
startOffset=0,endOffset=6,positionIncrement=1,positionLength=1,type=word => Object
startOffset=7,endOffset=15,positionIncrement=1,positionLength=1,type=word => Oriented
startOffset=16,endOffset=24,positionIncrement=1,positionLength=1,type=word => Software
startOffset=25,endOffset=37,positionIncrement=1,positionLength=1,type=word => Construction
startOffset=0,endOffset=6,positionIncrement=1,positionLength=1,type=word => Design
startOffset=7,endOffset=16,positionIncrement=1,positionLength=1,type=word => Patterns:
startOffset=17,endOffset=25,positionIncrement=1,positionLength=1,type=word => Elements
startOffset=26,endOffset=28,positionIncrement=1,positionLength=1,type=word => of
startOffset=29,endOffset=37,positionIncrement=1,positionLength=1,type=word => Reusable
startOffset=38,endOffset=53,positionIncrement=1,positionLength=1,type=word => Object-Oriented
startOffset=54,endOffset=62,positionIncrement=1,positionLength=1,type=word => Software
DOC 1
id = 1
title = Object Oriented Software Construction
DOC 2
id = 2
title = Design Patterns: Elements of Reusable Object-Oriented Software
Si vous placez un point d’arrêt dans le filtre de token et relancez la classe Tests en mode débogage, le débogueur s’arrêtera bien à cette ligne comme prévu.
Cas d'utilisation #2 : Déboguer les internals de Solr
Dans ce cas, il n’y a pas de code personnalisé, car rappelez-vous, l’objectif est d’examiner certains aspects internes de Solr. Plus précisément, la question à laquelle je dois répondre dans cet exemple est : en supposant que nous ayons un champ
et une requête
q=...&...&fl=myfield
D’où Solr récupère-t-il la valeur du champ [1] ?
La première chose que je dois faire est de modifier quelque chose dans le projet :
schema.xml: ajouter la définition du champ ci-dessus- Classe
Tests: modifier les paramètres de la requête (en ajoutantfl=myfield) et ajouter une valeur pour le champmyfielddans les documents indexés.
Maintenant, une prémisse : puisque l’objectif de cet article de blog n’est pas de répondre réellement à la question ci-dessus, nous allons passer toute la phase d’investigation nécessaire pour comprendre le flux d’exécution de la requête dans son ensemble et détecter l’endroit où nous mettrons le point d’arrêt.
Après quelques investigations, nous comprenons que la classe RetrieveFieldOptimizer [2] joue un rôle fondamental dans ce processus, alors ouvrons-la et mettons un point d’arrêt :
Comme vous pouvez le voir, le nom et l’intention de cette classe sont assez clairs, mais je veux encore voir ce qui se passe à l’exécution : démarrons la classe Tests en mode débogage et, comme prévu
Je peux voir que le champ “myfield” a été collecté dans l’ensemble storedFields, tandis que l’ensemble dvFields (champs DocValues) est vide, même si le champ a le drapeau docValues activé. Cela suggère probablement quelque chose…
En avançant, nous arrivons à la méthode optimize, où nous rencontrons l’optimisation décrite dans SOLR-8344 :
Encore une fois, ceci n’est qu’un exemple et l’objectif ici n’est pas de décrire les découvertes ; cependant, brièvement, cela dit que si tous les champs demandés
- ont les drapeaux
docValuesetstoredactivés - ne sont pas multivalués
alors Solr récupère les valeurs uniquement à partir de docValues.