Recherche en texte intégral avec Solr

1. Vue d'ensemble

Dans cet article, nous explorerons un concept fondamental du moteur de recherche Apache Solr: la recherche en texte intégral.

Apache Solr est un framework open source, conçu pour traiter des millions de documents. Nous allons passer en revue les fonctionnalités de base de celui-ci avec des exemples utilisant la bibliothèque Java - SolrJ.

2. Configuration Maven

Étant donné que Solr est open source, nous pouvons simplement télécharger le binaire et démarrer le serveur séparément de notre application.

Pour communiquer avec le serveur, nous allons définir la dépendance Maven pour le client SolrJ:

 org.apache.solr solr-solrj 6.4.2 

Vous pouvez trouver la dernière dépendance ici.

3. Indexation des données

Pour indexer et rechercher des données, nous devons créer un noyau ; nous allons créer un élément nommé pour indexer nos données.

Avant de faire cela, nous avons besoin que les données soient indexées sur le serveur afin qu'elles puissent être recherchées.

Il existe de nombreuses façons différentes d'indexer les données. Nous pouvons utiliser des gestionnaires d'importation de données pour importer des données directement à partir de bases de données relationnelles, télécharger des données avec Solr Cell à l'aide d'Apache Tika ou télécharger des données XML / XSLT, JSON et CSV à l'aide de gestionnaires d'index.

3.1. Indexation du document Solr

Nous pouvons indexer les données dans un noyau en créant SolrInputDocument . Tout d'abord, nous devons remplir le document avec nos données, puis n'appeler que l'API de SolrJ pour indexer le document:

SolrInputDocument doc = new SolrInputDocument(); doc.addField("id", id); doc.addField("description", description); doc.addField("category", category); doc.addField("price", price); solrClient.add(doc); solrClient.commit();

Notez que l' identifiant doit naturellement être unique pour différents éléments . Avoir un identifiant d'un document déjà indexé mettra à jour ce document.

3.2. Indexation des haricots

SolrJ fournit des API pour l'indexation des beans Java. Pour indexer un bean, nous devons l'annoter avec les annotations @Field :

public class Item { @Field private String id; @Field private String description; @Field private String category; @Field private float price; }

Une fois que nous avons le bean, l'indexation est simple:

solrClient.addBean(item); solrClient.commit();

4. Requêtes Solr

La recherche est la capacité la plus puissante de Solr. Une fois les documents indexés dans notre référentiel, nous pouvons rechercher des mots-clés, des phrases, des plages de dates, etc. Les résultats sont triés par pertinence (score).

4.1. Requêtes de base

Le serveur expose une API pour les opérations de recherche. Nous pouvons appeler / sélectionner ou / interroger les gestionnaires de demandes.

Faisons une recherche simple:

SolrQuery query = new SolrQuery(); query.setQuery("brand1"); query.setStart(0); query.setRows(10); QueryResponse response = solrClient.query(query); List items = response.getBeans(Item.class);

SolrJ utilisera en interne le paramètre de requête principal q dans sa requête au serveur. Le nombre d'enregistrements renvoyés sera de 10, indexés à partir de zéro lorsque le début et les lignes ne sont pas spécifiés.

La requête de recherche ci-dessus recherchera tous les documents contenant le mot complet «marque1» dans l'un de ses champs indexés. Notez que les recherches simples ne sont pas sensibles à la casse.

Regardons un autre exemple. Nous voulons rechercher n'importe quel mot contenant «rand» , qui commence par n'importe quel nombre de caractères et se termine par un seul caractère. Nous pouvons utiliser des caractères génériques * et ? dans notre requête:

query.setQuery("*rand?");

Les requêtes Solr prennent également en charge les opérateurs booléens comme dans SQL:

query.setQuery("brand1 AND (Washing OR Refrigerator)");

Tous les opérateurs booléens doivent être en majuscules; ceux soutenus par l'analyseur de requêtes sont AND , OR, NOT , + et -.

De plus, si nous voulons rechercher sur des champs spécifiques au lieu de tous les champs indexés, nous pouvons les spécifier dans la requête:

query.setQuery("description:Brand* AND category:*Washing*");

4.2. Requêtes d'expressions

Jusqu'à ce point, notre code recherchait des mots-clés dans les champs indexés. Nous pouvons également faire des recherches de phrases sur les champs indexés:

query.setQuery("Washing Machine");

Lorsque nous avons une phrase comme « Washing Machine », l'analyseur de requêtes standard de Solr l'analyse en « Washing OR Machine ». Pour rechercher une phrase entière, nous ne pouvons ajouter l'expression qu'entre guillemets doubles:

query.setQuery("\"Washing Machine\"");

Nous pouvons utiliser la recherche de proximité pour trouver des mots à des distances spécifiques . Si nous voulons trouver les mots séparés d'au moins deux mots, nous pouvons utiliser la requête suivante:

query.setQuery("\"Washing equipment\"~2");

4.3. Requêtes de plage

Les requêtes de plage permettent d'obtenir des documents dont les champs se situent entre des plages spécifiques.

Disons que nous voulons trouver des articles dont le prix varie entre 100 et 300:

query.setQuery("price:[100 TO 300]");

La requête ci-dessus trouvera tous les éléments dont le prix est compris entre 100 et 300 inclus. Nous pouvons utiliser " } " et " { " pour exclure les points de terminaison:

query.setQuery("price:{100 TO 300]");

4.4. Filtrer les requêtes

Les requêtes de filtre peuvent être utilisées pour restreindre le sur-ensemble de résultats pouvant être renvoyés. La requête de filtre n'influence pas le score:

SolrQuery query = new SolrQuery(); query.setQuery("price:[100 TO 300]"); query.addFilterQuery("description:Brand1","category:Home Appliances");

En général, la requête de filtre contiendra des requêtes couramment utilisées. Comme ils sont souvent réutilisables, ils sont mis en cache pour rendre la recherche plus efficace.

5. Recherche à facettes

Faceting helps to arrange search results into group counts. We can facet fields, query or ranges.

5.1. Field Faceting

For example, we want to get the aggregated counts of categories in the search result. We can add category field in our query:

query.addFacetField("category"); QueryResponse response = solrClient.query(query); List facetResults = response.getFacetField("category").getValues();

The facetResults will contain counts of each category in the results.

5.2. Query Faceting

Query faceting is very useful when we want to bring back counts of subqueries:

query.addFacetQuery("Washing OR Refrigerator"); query.addFacetQuery("Brand2"); QueryResponse response = solrClient.query(query); Map facetQueryMap = response.getFacetQuery();

As a result, the facetQueryMap will have counts of facet queries.

5.3. Range Faceting

Range faceting is used to get the range counts in the search results. The following query will return the counts of price ranges between 100 and 251, gapped by 25:

query.addNumericRangeFacet("price", 100, 275, 25); QueryResponse response = solrClient.query(query); List rangeFacets = response.getFacetRanges().get(0).getCounts();

Apart from numeric ranges, Solr also supports date ranges, interval faceting, and pivot faceting.

6. Hit Highlighting

We may want the keywords in our search query to be highlighted in the results. This will be very helpful to get a better picture of the results. Let's index some documents and define keywords to be highlighted:

itemSearchService.index("hm0001", "Brand1 Washing Machine", "Home Appliances", 100f); itemSearchService.index("hm0002", "Brand1 Refrigerator", "Home Appliances", 300f); itemSearchService.index("hm0003", "Brand2 Ceiling Fan", "Home Appliances", 200f); itemSearchService.index("hm0004", "Brand2 Dishwasher", "Washing equipments", 250f); SolrQuery query = new SolrQuery(); query.setQuery("Appliances"); query.setHighlight(true); query.addHighlightField("category"); QueryResponse response = solrClient.query(query); Map
    
     > hitHighlightedMap = response.getHighlighting(); Map
     
       highlightedFieldMap = hitHighlightedMap.get("hm0001"); List highlightedList = highlightedFieldMap.get("category"); String highLightedText = highlightedList.get(0);
     
    

We'll get the highLightedText as “Home Appliances. Please notice that the search keyword Appliances is tagged with . Default highlighting tag used by Solr is , but we can change this by setting the pre and post tags:

query.setHighlightSimplePre(""); query.setHighlightSimplePost("");

7. Search Suggestions

One of the important features that Solr supports are suggestions. If the keywords in the query contain spelling mistakes or if we want to suggest to autocomplete a search keyword, we can use the suggestion feature.

7.1. Spell Checking

The standard search handler does not include spell checking component; it has to be configured manually. There are three ways to do it. You can find the configuration details in the official wiki page. In our example, we'll use IndexBasedSpellChecker, which uses indexed data for keyword spell checking.

Let's search for a keyword with spelling mistake:

query.setQuery("hme"); query.set("spellcheck", "on"); QueryResponse response = solrClient.query(query); SpellCheckResponse spellCheckResponse = response.getSpellCheckResponse(); Suggestion suggestion = spellCheckResponse.getSuggestions().get(0); List alternatives = suggestion.getAlternatives(); String alternative = alternatives.get(0);

Expected alternative for our keyword “hme” should be “home” as our index contains the term “home”. Note that spellcheck has to be activated before executing the search.

7.2. Auto Suggesting Terms

We may want to get the suggestions of incomplete keywords to assist with the search. Solr's suggest component has to be configured manually. You can find the configuration details in its official wiki page.

We have configured a request handler named /suggest to handle suggestions. Let's get suggestions for keyword “Hom”:

SolrQuery query = new SolrQuery(); query.setRequestHandler("/suggest"); query.set("suggest", "true"); query.set("suggest.build", "true"); query.set("suggest.dictionary", "mySuggester"); query.set("suggest.q", "Hom"); QueryResponse response = solrClient.query(query); SuggesterResponse suggesterResponse = response.getSuggesterResponse(); Map
      
        suggestedTerms = suggesterResponse.getSuggestedTerms(); List suggestions = suggestedTerms.get("mySuggester");
      

The list suggestions should contain all words and phrases. Note that we have configured a suggester named mySuggester in our configuration.

8. Conclusion

This article is a quick intro to the search engine's capabilities and features of Solr.

We touched on many features, but these are of course just scratching the surface of what we can do with an advanced and mature search server such as Solr.

The examples used here are available as always, over on GitHub.