Documente Academic
Documente Profesional
Documente Cultură
Potrivită pentru orice aplicaţie care necesită indexare după text şi posibilităţi de
căutare, Lucene este recunoscută pentru facilităţile de căutare folosind atât motoarele de
căutare de pe Internet cât şi pentru căutarea locală. Librăria Lucene permite doar
indexarea şi căutarea şi nu conţine opţiuni de crawling (căutarea automată de pagini web)
sau funcţionalităţi de parsare HTML. Proiectul Apache denumit Nutch2 se bazează pe
Lucene şi oferă aceste funţionalităţi, iar proiectul Apache cu numele Solr3 este un server
care pune la dispoziţie facilităţi de căutare bazate pe Lucene.
Sub-proiecte Lucene
1
http://lucene.apache.org/java/docs/index.html
2
http://en.wikipedia.org/wiki/Nutch
3
http://en.wikipedia.org/wiki/Solr
1
• Lucy: este o bibliotecă independentă scrisă în C, derivată din Lucene, cu
interfeţe scrise în limbajele Perl şi Ruby;
În Figura 1 este prezentat modul de în care funcţiile Lucene pot fi integrate într-o
aplicaţie care necesită operaţii de căutare şi indexare. Putem observa modul în care
aplicaţia interacţionează cu module Lucene, care sunt responsabile cu indexarea
documentelor şi căutarea folosind indexul creat:
2
Concepte Lucene
3
indecşilor inverşi deoarece, pentru un termen dat pot fi afişate documentele care conţin
termenul, ceea ce e invers ordinii naturale în care documentele afişează termenii.
Un index Lucene poate fi compus din mai mulţi sub-indecşi, numiţi segmente,
fiecare din aceştia fiind un index independent şi în care se pot face căutări separate.
Indecşii evoluează prin crearea de noi segmente din documente nou adăugate sau în urma
unirii unor segmente existente.
4
• Vectorii de termeni sunt construiţi pentru fiecare câmp din fiecare document
(numite uneori şi vectorii documentului). Un vector de termeni este format din
textul termenilor şi frecvenţa fiecăruia.
Interogări Lucene
Interogările pe baza cărora se fac căutările sunt create folosind o listă iniţială de
cuvinte. Este important pentru succesul căutărilor ca interogările să fie construite cât mai
bine în funcţie de cuvintele care vor fi folosite în căutare. Dacă interogările sunt prea
generale atunci vom obţine foarte multe documente, iar relevanţa documentelor rezultate
va fi scăzută. În schimb, dacă interogările sunt prea specifice, atunci numărul
documentelor întoarse va fi mic, însă va creşte posibilitatea obţinerii documentelor
relevante.
Aşa cum am precizat anterior, interogările sunt de fapt expresii regulate scrise
folosind o anumită sintaxă, şi de aceea este firesc să poată fi folosite în cadrul lor şi
5
simbolurile „?” sau „*” cu acelaşi înteles pe care îl au în toate limbajele de programare
care suportă folosirea de expresii regulate. Astfel, „?” înlocuieşte orice caracter şi „*”
specifică faptul că pot fi oricâte caractere, inclusiv 0.
• NOT – exclude din listă documentele care conţin termenul ce urmează după
operator, fiind echivalentul operatorului de diferenţă de mulţimi. Este
important de ştiut faptul ca acest operator nu poate fi folosit de unul singur
într-o interogare, fiind obligatorie prezenţa cel puţin a încă unui termen în
afară de cel care urmează lui NOT. De exemplu, o interogare de tipul NOT
„Alan Mathison Turing” nu va întoarce nici un rezultat;
6
rezultatele vor conţine unul dintre cuvintele „povestire” sau „istorisire” şi unul dintre
numele Doyle sau Conan Doyle.
De multe ori însă rezultatele unei interogări nu sunt suficiente sau relevante, de
aceea au fost căutate metode de a le îmbunătăţi. Mai jos sunt prezentate câteva strategii
folosite de grupul UAIC în construirea sistemelor de întrebare răspuns participante la
competiţiile CLEF20074 şi CLEF20085:
4
CLEF2007: http://www.clef-campaign.org/2007.html
5
CLEF2008: http://www.clef-campaign.org/2008.html
7
De aceea, pentru a restrânge numărul de secvenţe de text întoarse de o căutare trebuie
adăugate verbele care marchează o definiţie: a fi, a defini, a reprezenta, a arăta. De
asemenea, ca la cazul anterior adăugarea optională a condiţiilor ca în titlu să avem
cuvintele care apar în întrebare va duce la creşterea şanselor găsirii răspunsului corect în
secvenţele cu relevanţă mare.
Scorul Lucene
8
Formula generală de calculare a scorului de bază Lucene este dată mai jos:
Acest scor este calculat pentru fiecare document în parte, iar documentele care au
această valoare peste 0, vor fi documentele care s-au potrivit căutării în index. În faza
următoare se identifică documentul cu scorul cel mai mare. În caz că acest scor este peste
valoarea 1 se normalizează toate scorurile în funcţie de această valoare, astfel încât să
avem toate scorurile documentelor care s-au potrivit cel mult 1.
În tabela de mai jos sunt explicate elementele care apar în formula de calculare a
scorului Lucene.
Element Descriere
9
Clasele de bază Lucene
• Field – Clasa Field reprezintă o secţiune a clasei Document. Obiectul de tip Field
va conţine un nume pentru secţiune şi datele curente.
• Query – Clasa Query este o clasă abstractă ce conţine criteriul de căutare creat de
clasa QueryParser.
10
Indexarea unui Document
Primul pas constă în instalarea aplicaţiei Lucene. Acest lucru se face foarte simplu
urmând instrucţiunile de pe pagina de start6.
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import java.util.Date;
6
http://lucene.apache.org/
11
}
Mai întâi se creează un obiect de tip Document, care va fi asociat fiecărui articol
pe care vrem să-l indexăm. După care trebuie completate cîmpurile articolului din cadrul
clasei Document. Numele considerate sunt la întâmplare şi funcţionează precum cheile
dintr-un HashMap. În cazul nostru am considerat cîmpurile “author”, “title”, “topic”,
“url”, “date” şi “article”, şi le-am completat cu valorile corespunzătoare articolului pe
care vrem să-l indexăm. Perechile (câmp, valoare) reprezintă termenii documentului
current. Singura condiţie este ca numele folosite să fie de tip String. Metoda de adăugare
add a unui Document va lua un obiect de tip Field pe care-l vom construi folosind una din
metodele statice din clasa Field. Există patru metode disponibile pentru a adăuga obiecte
de tip Field la un Document.
12
precum sunt cele de tip dată. De fapt, Field.Keyword poate considera un obiect de
tip Date ca intrare.
Indexarea Multicriterială
Ce este important de ştiut este faptul că atunci când vom folosi indexul în
procesul de căutare, va trebui să specificăm care din aceste câmpuri este folosit implicit
13
în procesul de căutare. Vom vedea în continuare cum se specifică acest câmpul şi modul
în care putem căuta după mai multe câmpuri în acelaşi timp.
Vom crea mai întâi un StandardAnalyzer şi apoi pe baza acestuia vom creea un
IndexWriter. În constructor vom specifica directorul unde va fi creat indexul. Valoarea
booleană de la sfârşitul constructorului îi va spune lui IndexWriter fie că va trebui să
creeze un nou index, fie că va trebui să adauge la un index existent. Când se adaugă un
nou document la un index existent va trebui să specificăm false. Apoi, vom adăuga
obiectul Document la index. La sfârşit, se optimizează şi se închide indexul. Dacă se vor
adăuga mai multe obiecte Document, va trebui ca de fiecare dată să optimizăm şi să
închidem indexul, până când toate obiectele Document vor fi adăugate la index.
Mai jos este metoda care pune la un loc toţi aceşti paşi.
14
title, topic,
url, dateWritten);
indexDocument(document);
}
Căutarea în Index
15
Cu toate că sunt implicate o mulţime de clase, operaţia de căutare este relativ
simplă. Primul lucru pe care trebuie să-l realizăm este de a creea un obiect IndexSearcher
care foloseşte directorul în care articolele au fost indexate. După aceea se creează un
obiect StandardAnalyzer. Obiectul StandardAnalyzer este trimis constructorului unui
QueryParser împreună cu numele câmpului implicit folosit în căutare. Acesta va fi
câmpul ce va fi folosit implicit dacă utilizatorul nu va specifica un câmp în criteriul de
căutare. În cazul nostru câmpul după care se face căutarea implicită este article. Apoi se
parsează criteriul curent de căutare introdus de utilizator, obţinând un obiect de tip Query.
În continuare se execută obiectul de tip Query folosind obiectul de tip IndexSearcher.
Acesta va întoarce un obiect Hits, care este o colecţie a tuturor articolelor ce verifică
criteriul de căutare specificat.
Extragerea obiectelor Document din obiectul Hits se face folosind metoda doc() a
obiectului Hits.
Clasa Document are o metodă get() care poate fi utilizată pentru a extrage
informaţiile ce au fost scrise în index. De exemplu, pentru a obţine autorul dintr-un obiect
de tip Document ar trebui să apelăm metoda doc.get("author"). Deoarece am adăugat
chiar articolul ca un câmp Field.UnStored, încercarea de a-l accesa folosind metoda get
ne va întoarce null. Oricum, deoarece am adăugat URL-ul unui articol la index, vom
putea să-l identificăm şi să-l afişăm utilizatorului în lista cu rezultatele. Va trebui ca de
fiecare dată să închidem IndexSearcher după ce am terminat extragerea tuturor obiectelor
de tip Document. Încercările de a extrage un Document după închiderea acestuia va
genera o eroare:
16
Specificarea criteriilor de căutare
cu semnificaţia: se caută Henry în câmpul author, iar în câmpul article se caută relativity
şi "quantum physics" (reamintim că implicit căutarea se face după câmpul article folosit
în constructorul QueryParser). După cum observăm putem face simultan căutarea în
două câmpuri ale indexului creat: author şi article.
Exemplul 3: să căutăm articolele care conţin Kepler la cel mult 5 cuvinte de Galileo:
"Galileo Kepler"~5
După cum am văzut dacă nu specificăm un câmp atunci căutarea s-a făcut după câmpul
article. De asemenea, am putut să facem căutări după orice câmp din Document atâta
timp cât acesta a fost adăugat ca Field.UnIndexed.
17
Concluzii
Lucene este un motor de căutare care, deşi utilizeată tehnici complexe de indexare
şi regăsire, este extrem de uşor de folosit. O facilitatea importantă a motorului Lucene
vine din faptul că putem adăuga oricâte câmpuri la index pe care le putem folosi mai apoi
în procesul de căutare.
Bibliografie
• Paul, T. 2004. The Lucene Search Engine: Adding search to your applications.
http://www.javaranch.com/journal/2004/04/Lucene.html
Links
18