11/13/2010

Lucene et Jython

Au début, je souhaitais seulement tester un peu la technologie LUCENE : vous savez ce projet de la fondation APACHE, qui vous permet d'utiliser la même technologie que les grands moteurs de recherche sur Internet.  Je me suis dis que la meilleure solution était d'utiliser une bibliothèque python... comme pylucene... mais après 1H sur le site à regarder comment j'allais pouvoir faire fonctionner ce machin, je me suis dit : il faut laisser à JAVA ce qui appartient à JAVA... mais je ne voulais pas pour autant quitter le monde des pythoniens... ça tombe bien, d'autres personnes ont déjà fait ce chemin et ont créé un interpréteur python, qui fonctionne au dessus d'une JVM (Java Virtual Machine) et qui permet d'utiliser les bibliothèques JAVA : JYTHON.


Bon, il faut le dire, la documentation LUCENE est pas vraiment des plus explicite et il n'y a pas tant de code qui traine sur Internet... Bon, après une journée à me familiariser avec JYTHON et une autre à me familiariser avec LUCENE, j'ai fini par écrire un "indexer" :

import sys

# Add jars to classpath
jars = ["./lucene-core-3.0.2.jar"]

for jar in jars:
    sys.path.append(jar)

from org.apache.lucene.analysis.standard import *
from org.apache.lucene.index import *
from org.apache.lucene.store import *
from org.apache.lucene.util import *
from org.apache.lucene.document import Document, Field 


from java.io import File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;

import glob
import os

def listdirectory2file(path):
    l = glob.glob(path+"/*")
    for i in l:
        if os.path.isdir(i):
                print "Directory :"+i
                print listdirectory2file(i)
        else:
                print i
                indexfile(i)

def indexfile(filename):
    global writer
    f = open(filename, 'r')
    content = f.read()
    doc = Document () 
    doc.add(Field("name", filename, Field.Store.YES,Field.Index.ANALYZED))
    doc.add(Field("content", content, Field.Store.YES,Field.Index.ANALYZED))
    writer.addDocument(doc)

path = './toindex'
INDEX_DIR = File("index")

analyzer  = StandardAnalyzer(Version.LUCENE_CURRENT)

writer = IndexWriter(FSDirectory.open(INDEX_DIR),analyzer, 1, IndexWriter.MaxFieldLength.LIMITED)

listdirectory2file(path)



#writer.DocCount()
writer.optimize()
writer.close()

et un système de recherche :


import sys

# Add jars to classpath
jars = ["./lucene-core-3.0.2.jar"]

for jar in jars:
    sys.path.append(jar)


from org.apache.lucene.analysis.standard import *
from org.apache.lucene.index import *
from org.apache.lucene.store import *
from org.apache.lucene.util import *
from org.apache.lucene.document import Document, Field 
from org.apache.lucene.search import IndexSearcher, TopScoreDocCollector
from org.apache.lucene.queryParser import QueryParser

from java.io import File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;

querystring = "test"
path = './toindex'
INDEX_DIR = File("index")
hitsPerPage = 10


analyzer  = StandardAnalyzer(Version.LUCENE_CURRENT)
searcher = IndexSearcher(SimpleFSDirectory(INDEX_DIR))
query = QueryParser(Version.LUCENE_CURRENT, "content", analyzer).parse(querystring)

hits = searcher.search(query,hitsPerPage)


for hit in hits.scoreDocs:
    print "====="
    print hit.score, hit.doc, hit.toString()
    doc = searcher.doc(hit.doc)
    print doc.get("name").encode("utf-8")

Bon si vous êtes un peu familier avec le python, ce code ne devrait pas trop vous dérouter. Pour le reste, vous aurez noter la présence du fichier "lucene-core-3.0.2.jar" là où je lance mes commandes :
jython createindex.py
et
jython queryindex.py

Amusez-vous bien et n'hésitez pas à me poser des questions si vous rencontrez des difficultés.