Apache Solr

Configuration

Prsentation

Solr est très configurable. Globalement deux fichiers XML contenus dans "example/solr/conf" sont paramétrables :

Le premier concerne la configuration au niveau système de Solr. Il est par exemple possible de modifier la quantité de mémoire RAM attribuée à Solr ou bien encore de spécifier une valeur au LRU Cache pour les requêtes.
Mais nous nous intéresserons pas à cette partie dans ce site web car la configuration de base est suffisante. Pour plus d'informations, consulter la page du wiki dédié à ce sujet : http://wiki.apache.org/solr/SolrConfigXml.

Schema

Le fichier schema.xml est le fichier permettant de décrire le format des documents manipulés par l'index
La page du Wiki qui traite du schema est : http://wiki.apache.org/solr/SchemaXml.

Ce fichier va en fait regrouper les types des champs des documents indexés, ainsi que leur comportements :

Par ailleurs, les champs eux-mêmes sont spécifiés dans ce fichier schema.xml.
C'est dans ce fichier qu'est spécifié le champ représentant l'identifiant unique d'un document, ainsi que l'ensemble des champs dans lesquels par défaut la recherche est effectée.
Lorsque dans une requête, on ne préfixe pas la valeur recherchée par le champ, la recherche s'effectuera dans ce ou ces champs spécifiés.

Exemple : définition du type text

Voici ci-dessous un extrait du fichier schema.xml, correspondant à la définition du type Text. Ainsi un champ qui sera défini avec le type Text aura les propriétés suivantes :

<fieldType name="text" class="solr.TextField" positionIncrementGap="100">      
	<analyzer type="index">
		<tokenizer class="solr.WhitespaceTokenizerFactory"/> 
		<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
	</analyzer>
	<analyzer type="query">
		<tokenizer class="solr.WhitespaceTokenizerFactory"/>
		<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
		<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
	</analyzer>
</fieldType>
				

On retrouve bien dans cette définition du type Text, les deux modes d'analyse différents : à l'indexation (index) et à la requête (query).
Ici le tokenizer utilisé coupe les mots selon les espaces (WhitespaceTokenizer).
Il est important que le Tokenizer soit le même à l'indexation et lors d'une requête, sinon ce ne sera pas possible de rechercher dans les documents que l'on a indexés.
Un filtre StopFilter est appliqué dans le but de supprimer toutes les articles (le, la, les, un, etc.). Le fichier "stopwords.txt" permet de regrouper tous ces mots-clés.
On constate qu'un second filtre (Synonyms) est appliqué uniquement pour la partie requête. En effet, ce filtre permet de vérifier si des mots comportent des synonymes, pour pouvoir matcher un plus grand nombre de termes. Le fichier "synonyms.txt" contient l'ensemble des termes associés à leurs synonymes.

Voici un exemple de contenu des deux fichiers texte évoqués ci-dessus :
stopwords.txt :

#Standard english
#stop words

an
and
as
at
be
but
by
for
if
in



synonyms.txt :
# Some synonym groups

GB,gib,gigabyte,gigabytes
MB,mib,megabyte,megabytes
Television, Televisions, TV, TVs

spider, arachnid


Dans le fichier des synonymes, on précise les termes synoymes entre eux, sur la même ligne et séparés par des virgules. Dans cet exemple, le terme "arachnid" est synonyme avec "spider".
Lors d'une requête, l'utilisation de l'un ou de l'autre terme devra renvoyer les mêmes résultats.

Définition des champs

Une fois la description des types définie, on peut procéder à la spécification des champs eux-mêmes. On définit alors le modèle des documents que l'on indexera. L'exemple ci-dessous correspond aux champs donnés en exemple avec le héro Spider-Man :

	<field name="id"     type="string"     indexed="true"     stored="true"/>
	<field name="name"     type="text"     indexed="true"     stored="true"/>
	<field name="supername"   type="string"     indexed="true"   stored="true"/>
	<field name="powers"     type="text"     indexed="true"     stored="true"     multiValued="true"/>
	<field name="story"     type="text"     indexed="true"     stored="true"/>

	<uniqueKey>id</uniqueKey>
	<defaultSearchField>name</defaultSearchField>
					

Les champs "name", "powers" et "story" sont du type Text, que l'on a défini plus haut.
Le champ "powers" peut apparaître plusieurs fois, car sa valeur "multiValued" est à vrai.
Lorsque pour un champ, indexed=true, c'est un champ sur lequel on peut effectuer des recherches. Lorsque stored=true c'est un champ qui pourra être retourné lors des requêtes (paramètre "fl").
La clé spécifiée correspond ici au champ "id", et le champ de recherche par défaut est "name".

Analyse

Prenons le cas d'un champ de type Text pour effectuer une analyse lors de l'indexation et d'une requête. Choisissons le champ "powers" :

A l'indexation, supposons que le champ "powers" ait comme valeur "spider sense". Tout d'abord, le tokenizer est appliqué afin de séparer là où il y a des espaces. On obtient donc deux termes, "spider" puis "sense".
On applique ensuite le filtre sur les articles. Etant donné qu'il n'y en a pas, il n'y a pas de différence avec l'étape précédente, et l'analyse s'arrête là pour l'indexation.

A la recherche, supposons la requête "An arachnid sense". Tout d'abord, on applique le tokenizer selon les espaces. On obtient donc trois termes différents, "An", "arachnid", et "sense".
Ensuite, on applique le filtre des synonymes, et on trouve que "arachnid" est synonymes avec "spider". Ces deux termes sont alors conservés.
Enfin, le filtre sur les articles est appliqué en ignorant la casse. Ainsi, le "An" disparaît.
Au final, la requête match, puisqu'on a bien "spider" et "sense" des deux côtés.