SolrEventListener est une interface qui définit un ensemble de rappels pour plusieurs événements du cycle de vie :
void postCommit()void postSoftCommit()void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher)
Dans cet exemple, je ne suis pas intéressé par les deux premiers rappels car les invocations correspondantes se produiront, comme leur nom l’indique, après les événements de commit dur et doux. Le méthode intéressante est newSearcher(...), qui permet d’enregistrer un écouteur d’événements personnalisé associé à deux événements :
firstSearchernewSearcher
Dans Solr, le IndexSearcher qui sert les requêtes à un moment donné est appelé le currentSearcher. Au démarrage, il n’y a pas de currentSearcher car le premier est créé ; nous sommes donc dans l’événement “firstSearcher”, ce qui est exactement ce que je recherchais.
Lorsqu’un autre (nouveau) searcher est ouvert, il est préparé (c’est-à-dire automatiquement réchauffé) pendant que l’actuel continue de servir les requêtes entrantes. Lorsque le nouveau searcher est prêt, il devient le currentSearcher, il traitera toutes les nouvelles requêtes de recherche, et l’ancien searcher sera fermé (dès que toutes les requêtes qu’il traitait sont terminées). Ce scénario est celui où le rappel “newSearcher” est invoqué.
Comme vous pouvez le voir, la méthode de rappel pour ces deux événements est la même ; il n’y a pas de méthode “firstSearcher” et “newSearcher”. La différence réside dans les arguments d’entrée : pour les événements “firstSearcher”, il n’y a pas de currentSearcher, donc le deuxième argument est nul ; ce n’est évidemment pas le cas pour les rappels “newSearcher”, où les deux premiers arguments contiennent une référence valide au searcher.
En revenant à mon scénario, tout ce dont j’ai besoin :
- déclarer cet écouteur dans
solrconfig.xml - une implémentation concrète de
SolrEventListener
Dans solrconfig.xml, au sein de la section <updateHandler>, je peux déclarer mon écouteur :
${solr.solr.home}/sample/data.xml</str>
L’écouteur sera initialisé avec un seul paramètre, le fichier contenant les données d’exemple. En utilisant l’attribut “event”, je peux informer Solr du type d’événement qui m’intéresse (par exemple firstSearcher).
La classe d’implémentation est assez simple : elle étend SolrEventListener :
public class SolrStartupListener implements SolrEventListener {
...
@Override
public void init(final NamedList args) {
this.datafile = (String) args.get("datafile");
}
...
LocalSolrQueryRequest request = null;
try {
// 1. Create the arguments map for the update request
final NamedList args = new SimpleOrderedMap();
args.add(
UpdateParams.ASSUME_CONTENT_TYPE,
"text/xml");
addEventParms(currentSearcher, args);
// 2. Create a new Solr (update) request
request = new LocalSolrQueryRequest(
newSearcher.getCore(),
args);
// 3. Fill the request with the (datafile) input stream
final List streams = new ArrayList();
streams.add(new ContentStreamBase() {
@Override
public InputStream getStream() throws IOException {
return new FileInputStream(datafile);
}
});
request.setContentStreams(streams);
// 4. Creates a new Solr response
final SolrQueryResponse response =
new SolrQueryResponse();
// 5. And finally call invoke the update handler
SolrRequestInfo.setRequestInfo(
new SolrRequestInfo(request, response))
newSearcher
.getCore()
.getRequestHandler("/update")
.handleRequest(request, response);
} finally {
request.close();
}
}
}
Voilà : si vous démarrez Solr, vous verrez les données d’exemple chargées. En plus d’éviter beaucoup de tâches répétitives, cela peut être utile lorsque vous utilisez un SolrCore comme stockage NoSQL, par exemple si vous stockez des vocabulaires SKOS pour les synonymes, les traductions et les recherches plus larges / plus étroites.