> Modules non standards > Autres modules non standards > Whoosh
Whoosh
whoosh est une librairie qui permet d'indexer des documents (comme lucene)
- il est en pur python et rapide.
- les index sont assez petits.
- on peut stocker des champs dans les index.
- quasiment tout est remplaçable.
Création de l'index :
- on définit d'abord un schéma qui indique les champs de l'index et comment les gérer :
from whoosh import fields
schema = fields.Schema(myField1 = fields.TEXT, myField2 = fields.NUMERIC)
- puis, on crée l'index en indiquant dans quel directory/répertoire existant le créer :
from whoosh import index
myIndex = index.create_in('myDirectory', schema)
- enfin, on écrit les documents dans l'index en donnant les champs définis dans le schéma (pas forcément tous présents dans un document donné) :
writer = myIndex.writer()
writer.add_document(myField1 = unicode('le contenu de mon champ1'), myField2 = 123)
writer.add_document(myField1 = unicode('un autre contenu'), myField2 = 456)
- à la fin, sauver les modifications : writer.commit() (si on ne veut pas les sauver, faire writer.cancel())
- attention : les champs text doivent être transformés en unicode !
- attention : un seul process peut écrire dans l'index à la fois (il y a un lock en écriture). Par contre, l'index reste accessible en lecture, mais avec la version précédente. Pour lire l'index avec la dernière version, il faut le réouvrir en lecture après le dernier commit !
Définition des champs :
- on peut donner l'objet construit ou seulement la classe : myField1 = fields.TEXT() ou myField1 = fields.TEXT
- myField1 = fields.TEXT(stored = True) : indique qu'il faut indexer le contenu, mais en plus le stocker (défaut = False)
- myField1 = fields.TEXT(phrase = True) : il faut stocker la position des mots pour effectuer des recherches d'expressions (défaut = True)
- principaux types :
- fields.ID() : indexation du contenu sans chercher à le décomposer en mots.
- fields.STORED() : permet juste de stocker le champ, sans l'indexer. On peut donner des valeurs quelquonques, à la simple condition qu'elles soient sérialisables avec pickle.
- fields.NUMERIC(numtype = int, bits = 64) : indexe un champ entier.
- fields.KEYWORD() : pour index des mots séparés par des espaces ou des virgules.
- fields.BOOLEAN() : pour index des booléens.
- fields.DATETIME() : pour indexer des objets datetime.
Recherche :
- il faut d'abord ouvrir l'index en donnant son directory : myIndex = index.open_dir('myDirectory')
- on définit d'abord un objet pour faire la recherche : searcher = myIndex.searcher() ... searcher.close()
- on peut aussi utiliser :
with myIndex.searcher() as searcher:
...
c'est équivalent à :
try:
searcher = myIndex.searcher()
finally:
searcher.close()
- puis, on définit une requête :
from whoosh import query
myQuery = query.And([query.Term('myField1', u'pomme'), query.Term('myField1', u'poire')])
- et enfin, on fait la recherche : results = searcher.search(myQuery)
- attention : par défaut, la recherche ne ramène qu'au plus 10 résultats !
- si on en veut jusqu'à 20 : results = search.search(myQuery, limit = 20)
- si on veut tous les résultats : results = search.search(myQuery, limit = None)
- on peut aussi récupérer les résultats par page :
- results = searcher.search_page(myQuery, 1) : la première page de 10 résultats.
- results = searcher.search_page(myQuery, 3, page_len = 20) : la troisième page de 20 résultats.
Pour faire la recherche, on peut aussi partir d'une query sous forme de chaîne :
Résultats :
- les résultats sont de type classe whoosh.searching.Results, mais se comportent comme une liste de whoosh.searching.Hit
- les hits ont la méthode fields qui renvoie un dictionnaire dont les clefs sont les noms des champs, et les valeurs sont les valeurs du record trouvé.
On peut modifier le schéma après sa création avec le writer (
writer = myIndex.writer()) :
- writer.add_field('myField3', fields.TEXT) : pour rajouter un champ.
- writer.remove_field('myField1') : pour enlever un champ, mais cela ne le détruit pas physiquement de l'index.
- faire writer.commit() pour sauver.
- si on veut vraiment détruire physiquement le champ pour que l'index soit plus petit : writer.commit(optimize= True)
Fusion de segments :
- en fait, quand on rajoute des documents, whoosh rajoute des segments (comme lucene) plutôt que de les rajouter à l'index existant : plus rapide à écrire, par contre, la recherche doit se faire dans les différents segments, ce qui est plus long.
- au commit, whoosh fusionne certains segments.
Pour un champ, on peut récupérer toutes ses valeurs : list(searcher.lexicon('Subj')) (sans le list, ça récupère un generator)
Copyright python-simple.com
programmer en python, tutoriel python, graphes en python, Aymeric Duclert