TP1 - Tokenisation et indexation

Le but du TP est de manipuler les expressions rationnelles pour découper les textes en tokens. Nous aborderons l'indexation de documents et la recherche de motifs.

Précisons que sur les machines de l'université, python (version 2.6) ne connait pas la librairie NLTK. Il faut faire :
export PYTHONPATH=/usr/lib/python2.5/site-packages


Exercice 1 - Tokenisation

Le but de l'exercice est d'écrire en Python un programme qui découpe un texte en tokens à l'aide d'expressions rationnelles.
  1. Utilisez les librairies codecs et nltk de Python pour ouvrir le fichier texte, et afficher tous ses tokens.
    Dans un premier temps, on définit un token comme suit:
    • soit une séquence de lettres (attention aux accents!).
    • soit un chiffre
    • soit un symbole de ponctuation
  2. Modifiez votre script pour que votre expression rationnelle reconnaisse aussi comme tokens, les nombres (entiers et décimaux) et les prix du type 15,3€.
  3. Modifiez votre script pour que votre expression rationnelle reconnaisse aussi les dates en chiffres comme tokens. Par exemple, 01/12/2009; 2010-01-11; etc.
  4. Dessinez sur papier un automate à états finis correspondant à votre expression rationnelle.


Exercice 2 - Indexation

Le but de l'exercice est d'indexer une collection de textes par tokens. La collection se trouve dans ce fichier zip à décompresser. La liste des textes se trouve dans le fichier collection.lst.
  1. Écrivez un script Python qui construit l'index de la collection et le sauvegarde dans un fichier. Il prendra comme paramètre le nom du fichier contenant la liste des textes de la collection. L'index doit comporter les informations suivantes pour chaque token : l'ensemble des documents dans lequel il apparaît.
    Indication : utilisez un dictionnaire Python et le module pickle pour la sauvegarde (fonction dump()).
  2. Nous souhaitons maintenant implémenter un petit moteur de recherche simple. Une requête est une suite de mots qui doivent appartenir aux documents que l'on cherche. Pour cela, on va écrire un nouveau script python qui va, dans un premier temps, charger l'index (cf. la fonction load() du module pickle) puis traiter les différentes requêtes entrées par l'utilisateur.
    • Écrivez une fonction qui prend comme paramètre une requête (string) et un index d'une collection, et qui renvoie la liste des documents de la collection qui contiennent tous les mots de la requête.
    • Faites en sorte que votre script demande à l'utilisateur de rentrer sa requête au clavier (méthode raw_input()). Le script doit être capable de gérer plusieurs requêtes consécutives indéfiniment.
    • Modifiez le script pour ajouter une option aux requêtes afin qu'il soit aussi possible d'obtenir tous les documents contenant au moins un mot de la requête.
Correction :
Construction de l'index :
import nltk
import codecs
import pickle
import sys

def getWords(filename):
  f = codecs.open(filename,'r','utf-8')
  text= f.read().lower()
  l = nltk.regexp_tokenize(text,"\w+")
  f.close()
  return l

def buildIndex(filename):
  pos = filename.rfind('/')
  prefix = ''
  if pos != -1:
    prefix = filename[:pos]+'/'
  index = {}
  f = open(filename,'r')
  for text in f:      
     text = text[:-1]
     for w in getWords(prefix+text):
        index[w] = index.get(w,set([]))
        index[w].add(text)       
  f.close()   
  return index

if len(sys.argv) != 2:
  print >> sys.stderr, "Usage: python "+sys.argv[0]+" <collection filename>"
  sys.exit()

index = buildIndex(sys.argv[1])
pickle.dump(index,open('index.pckl','w'))


Moteur de recherche simple:
import pickle
import nltk
import sys

def computeAndQuery(queryWords,index):
  result = index.get(queryWords[0],set([]))
  for w in queryWords[1:]:
    result = result.intersection(index.get(w,set([])))
  return result

def computeOrQuery(queryWords,index):
  result = index.get(queryWords[0],set([]))
  for w in queryWords[1:]:
    result = result.union(index.get(w,set([])))
  return result

def computeQuery(query,index):  
  words = nltk.regexp_tokenize(query,"\w+")
  if len(words) == 0:
    return set([])
  if not query.startswith('~'):
    return computeAndQuery(words,index)
  return computeOrQuery(words,index)

index = pickle.load(open/span>('index.pckl'))
while True:
   query = raw_input('Enter a query:')
   print 'RESULT:'
   print computeQuery(query,index)