La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Roberto Navigli, Fulvio DAntonio Lucene: Una libreria efficiente per ricerche di testo.

Presentazioni simili


Presentazione sul tema: "Roberto Navigli, Fulvio DAntonio Lucene: Una libreria efficiente per ricerche di testo."— Transcript della presentazione:

1 Roberto Navigli, Fulvio DAntonio Lucene: Una libreria efficiente per ricerche di testo

2 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 2 Lo scenario

3 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 3 Lucene 3.1 E una API (Application Programming Interface) –Estremamente efficiente e scalabile Mette a disposizione le classi fondamentali per costruire un indicizzatore e un motore di ricerca 100% Java, nessuna dipendenza, nessun config file Fa parte del progetto Apache –Disponibile online: Utilizzato da: –Wikipedia, Wikimedia, ecc. –Technorati –Monster.com –TheServerSide –SourceForge –Eclipse –Beagle –Molti progetti commerciali

4 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 4 Ancora su Lucene Utilizzato in: –TREC (Text Retrieval Conference) –Sistemi di Document Retrieval a livello enterprise –Parte di motori web/basi di dati Utilizzato da accademici per grandi progetti: –MIT (AI Lab) –Progetto Know-It-All

5 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 5 Lucene in breve Document nome: my_doc1 term: oggi, ho, assistito, a, una,lezione, su, Lucene my_doc1: Oggi ho assistito a una lezione su Lucene. IndexWriter addDocument() Indice Lucene Documento sorgente optimize() close() IndexSearcher Query Hits (risultati della ricerca) Hits (risultati della ricerca) Hits (risultati della ricerca) search() Lezione & Lucene

6 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 6 Conversione in Testo Normalmente, è necessario convertire le risorse da indicizzare in formato testo se esse sono specificate mediante altri formati (es. Word, PDF, HTML, XML, ecc.) Utilità di conversione: –PDFBox (PDF) –Jakarta POI (DOC, RTF, ecc.) –JTidy (HTML)

7 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 7 Documenti in Lucene In Lucene Un documento è una unità di indicizzazione e ricerca (differente dal documento inteso come file) Un documento è un insieme di campi Ogni campo ha un nome e un valore testuale Decidiamo noi quali informazioni inserire nel documento! Document d = new Document(); d.add(new Field(nome_campo, valore, storeable, indexable)); JAVA Code String Field.Store Field.Index

8 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 8 Campi di un Documento Un campo di un documento specifica: –Il nome del campo (stringa) –Il valore testuale del campo (stringa) –Se il valore del campo deve essere memorizzato nel documento Necessario per recuperare il valore del campo dai documenti che rispondono a una interrogazione –Se il valore del campo deve essere indicizzato Necessario per la ricerca E possibile richiedere lanalisi del testo prima dellindicizzazione (ANALYZED, deprecato il vecchio TOKENIZED) Field f1 = new Field(name, my_doc1, Field.Store.YES, Field.Index.NO); Field f2 = new Field(term, Lucene, Field.Store.YES, Field.Index.NOT_ANALYZED); Field f3 = new Field(term, Oggi ho assistito, Field.Store.YES, Field.Index.ANALYZED); JAVA Code

9 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 9 Esempi di Campi NomeField.StoreField.Index TelefonoYESNOT_ANALYZED URLYESNOT_ANALYZED DataYESNOT_ANALYZED DocumentTypeYESNO DocumentPathNONOT_ANALYZED DocumentTitleYESANALYZED TextYESANALYZED

10 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 10 Creazione dellindice 1.Crea un oggetto di tipo IndexWriter: –Esistono molti tipi diversi di costruttori a seconda delle esigenze. –Uno dei più usati è: 1.Crea i documenti e aggiungili allindice 2.Ottimizza e chiudi lindice (fondamentale!) IndexWriter writer = new IndexWriter(indexDir, analizzatore, bCrea, maxFldLen); JAVA Code writer.optimize() writer.close(); JAVA Code Document d = new Document(); d.add(new Field(term, assistito, Field.Store.NO, Field.Index.ANALYZED)); writer.addDocument(d); JAVA Code

11 La classe Directory Usata per la memorizzazione di indici A livello astratti n oggetto Directory è una lista di file. –Random Access sia in lettura che scrittura –Aggiunta, cancellazione aggionamento di file Lucene implementa diversi tipi di Directory: –RAM-based indices; –Indic memorizzati in database, via JDBC; –Indici su file; 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 11

12 Esempi di directory In memoria RAM: –RAMDirectory dir= new RAMDirectory(); –Utile per creare indici al volo, lindice non è persistente (viene perso una volta che lesecuzione del programma è terminata) Su file –FSDirectory dir = FSDirectory.open(new File("temp")); –Memorizzazione persistente –i dati sono disponibili anche dopo che lesecuzione del programma è terminata 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 12

13 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 13 La classe Analyzer Si occupa dellestrazione di termini a partire da un testo in input –Istanzia un tokenizer, che suddivide il flusso di caratteri in token –Applica dei filtri ai singoli token Può eliminare stopwords (parole frequenti senza contenuto informativo, es. a, the, of, in, etc.) Può effettuare lo stemming (andare, andò -> and; bellissimo, bello, bellina -> bell) Analyzer analizzatore = new StandardAnalyzer(); IndexWriter writer = new IndexWriter(indexDir, analizzatore, bCrea, MaxFieldLength.UNLIMITED); JAVA Code

14 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 14 Analizzatori in Lucene Analizzatori –WhitespaceAnalyzer: estrae i token separati da spazi (non modifica maiuscole/minuscole) –SimpleAnalyzer: tokenizza sulla base di spazi e caratteri speciali; applica il minuscolo ai token –StopAnalyzer: come SimpleAnalyzer ma elimina le stopwords (the, an, a, ecc.) –StandardAnalyzer: è il più completo (Whitespace+Stop+altri trattamenti) –SnowballAnalyzer: effettua anche lo stemming

15 Compatibilità con precedenti versioni di Lucene Lucene è un progetto costantemente mantenuto e sviluppato Occasionalmente, un cambio di versione, può causare incompatibilità allinterno di progetti pre-esistent –Es: il cambio da versione 2.4 a 3.1 di Lucene Per ragioni di backward compatibility alcuni oggetti vanno istanziati specificando un campo di tipo Version –Es: StopAnalyzer analyzer = new StopAnalyzer(Version.LUCENE_30); Utilizzare, laddove non vi siano esigenze particolari, la versione LUCENE_30 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 15

16 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 16 Esempi di analisi The quick brown fox jumped over the lazy dogs XY&Z Corporation –

17 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 17 Analizzatori Personalizzati E possibile creare il proprio analizzatore estendendo la classe Analyzer: class MyAnalyzer extends Analyzer { private Set stopWords = StopFilter.makeStopSet(StopAnalyzer.ENGLISH_STOP_WORDS); public TokenStream tokenStream(String fieldName, Reader reader) { TokenStream ts = new StandardTokenizer(reader); ts = new StandardFilter(ts); ts = new LowerCaseFilter(ts); ts = new StopFilter(ts, stopWords); return ts; } JAVA Code

18 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 18 La classe Document Rappresenta un documento virtuale della collezione –Può essere associato a qualunque oggetto informativo ( , pagina web, file, frammento di testo, ecc.) che si vuole recuperare in fase di ricerca Virtuale perché il file sorgente è irrilevante per Lucene E un insieme di campi –Un campo può rappresentare il contenuto del documento stesso o i meta-dati associati al documento String valore = d.get(name); String[] valori = d.getValues(term); List campi = d.getFields(); Field campo = getField(name); campi = d.getFields(term); d.removeField(name); d.removeFields(term); JAVA Code

19 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 19 Indicizzazione: Ricapitoliamo le Classi Fondamentali IndexWriter –Si occupa del processo di indicizzazione Analyzer –Si occupa dellanalisi dei documenti da indicizzare Document –Rappresenta un singolo documento della collezione Field –Rappresenta un campo del documento della collezione

20 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 20 Cercare in un Indice 1.Apri lindice 2.Crea la query 3.Effettua la ricerca 4.Recupera i documenti IndexSearcher is = new IndexSearcher(indexDir); JAVA Code ScoreDoc[] docs = searcher.search(q, ).scoreDocs; JAVA Code QueryParser parser = new QueryParser(Version.LUCENE_30, term, analizzatore); Query q = parser.parse(lezione); JAVA Code for (ScoreDoc doc:docs) { Document d = is.doc(doc.doc);// ottiene il documento float score =doc.score;// punteggio del documento //... } JAVA Code

21 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 21 Creare un Oggetto di Tipo Query Tanti tipi di query, esempi di due modi differenti: 1.Effettuare il parsing di una query testuale (come in Google) 2.Creare loggetto costruendo lespressione di ricerca istanziando e componendo classi che specializzano la classe Query Si esplicita la query costruendola in modo programmatico Non effettua alcuna analisi del testo della query (al contrario di QueryParser, che utilizza lanalizzatore in input) QueryParser parser = new QueryParser(Version.LUCENE_30, term, analizzatore); Query q = parser.parse(lezione AND Lucene); JAVA Code BooleanQuery q = new BooleanQuery(); q.add(new TermQuery(new Term(term, lezione)), BooleanClause.Occur.MUST); q.add(new TermQuery(new Term(term, Lucene)), BooleanClause.Occur.MUST); JAVA Code

22 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 22 Esempi di Query con QueryParser

23 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 23 Specializzazioni della classe Query Per costruire un oggetto Query componendo in unespressione istanze delle sue sottoclassi, ad es.: TermQuery (cerca un termine) ConstantScoreRangeQuery (cerca in un intervallo) PrefixQuery (termini che iniziano con la stringa specificata) Query q = new TermQuery(new Term(term, lezione)); JAVA Code Query q = new ConstantScoreRangeQuery(mese_pubblicazione, , , true, true); JAVA Code limite sup. includi limite inf. e sup. campo limite inf. campo valore Query q = new PrefixQuery(new Term(term, lez)); JAVA Code campo prefisso

24 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 24 Pesatura dei Risultati di una Ricerca Lucene calcola la rilevanza di un documento rispetto a una query –Usando una combinazione di modello booleano (per filtrare i documenti) e di Vector Space Model (per pesarli) –La pesatura è effettuata tenendo conto dei seguenti fattori: tf(t): term frequency (il numero di termini che fanno match nel documento) idf(t): inverse document frequency (in quanti documenti appare il termine rispetto al totale dei documenti?) lengthNorm(t, d): numero di termini del campo di t che appaiono nel documento coord: numero di termini che fanno match

25 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 25 Ricerca: Ricapitoliamo le Classi Fondamentali IndexSearcher –Ha diversi metodi per la ricerca in un indice Term –Unità di base per costruire uninterrogazione –Costituita da due elementi fondamentali: nome del campo e valore del campo Query –E una classe astratta di cui esistono numerose classi concrete: TermQuery, BooleanQuery, PhraseQuery, RangeQuery, FilteredQuery, ecc. Hits –E un contenitore di risultati (documenti) della ricerca con ranking associato

26 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 26 Operazioni sullIndice: Aggiunta di Documenti Aggiungere documenti allindice: Nota: –Documenti appartenenti allo stesso indice possono contenere campi differenti (questo permette di avere oggetti di tipo diverso indicizzati mediante lo stesso indice) Document d = new Document(); d.add(new Field(id, 06)); d.add(new Field(name, Rome, Field.Store.YES, Field.Index.NOT_ANALYZED)); d.add(new Field(country, Italy, Field.Store.YES, Field.Index.NO)); d.add(new Field(text, Rome is the capital of Italy. Its river, the Tiber, etc..., Field.Store.NO, Field.Index.TOKENIZED)); writer.addDocument(d); JAVA Code Document d = new Document(); d.add(new Field(id, 0039)); d.add(new Field(name, Italy, Field.Store.YES, Field.Index.NOT_ANALYZED)); d.add(new Field(continent, Europe, Field.Store.NO, Field.Index.NOT_ANALYZED)); writer.addDocument(d); JAVA Code

27 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 27 Operazioni sullIndice: Eliminazione di Documenti (1) Mediante la classe IndexReader: –es. eliminare il primo documento –es. eliminare tutti i documenti aventi il campo city valorizzato con Amsterdam –NOTA: per salvare le cancellazioni, è necessario chiudere lIndexReader! IndexReader reader = IndexReader.open(indexDir); reader.deleteDocument(0); JAVA Code reader.deleteDocuments(new Term(city, Amsterdam)); JAVA Code reader.close(); JAVA Code

28 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 28 Operazioni sullIndice: Eliminazione di Documenti (2) Mediante la classe IndexWriter: –es. eliminare i documenti aventi il campo city valorizzato con Amsterdam: –es. eliminare i documenti che rispondono allinterrogazione: E possibile aggiornare un documento (equivale a cancellare e aggiungere): NOTA: IndexReader non può essere utilizzato per cancellare se un IndexWriter è aperto sullo stesso indice writer.deleteDocuments(new Term(city, Amsterdam)); JAVA Code writer.deleteDocuments(query); JAVA Code writer.updateDocument(new Term(city, Amsterdam), newDoc); JAVA Code

29 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 29 Span Query Sono interrogazioni che forniscono informazioni riguardo alla posizione in cui un match ha avuto luogo allinterno di un documento SpanTermQuery permette una interrogazione per termine (building block!) SpanFirstQuery impone una posizione massima delloccorrenza rispetto allinizio di un campo SpanNearQuery specifica span che devono essere uno vicino allaltro SpanNotQuery, SpanOrQuery, SpanRegexQuery, ecc.

30 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 30 SpanTermQuery E lelemento di base di una SpanQuery: SpanTermQuery span = new SpanTermQuery(new Term(term, antonio)); Spans spans = span.getSpans(reader); while(spans.next()) { int docNumber = spans.doc(); Document doc = reader.document(docNumber); int primoToken = spans.start(); int ultimoToken = spans.end();// e il primo token che segue il match // fa qualcosa con il documento } JAVA Code

31 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 31 SpanFirstQuery Richiede che il match avvenga a distanza al più dist dal primo token del campo specificato SpanTermQuery span = new SpanTermQuery(new Term(term, antonio)); SpanFirstQuery first = new SpanFirstQuery(span, dist); Spans spans = first.getSpans(reader); while(spans.next()) { int docNumber = spans.doc(); Document doc = reader.document(docNumber); int primoToken = spans.start(); int ultimoToken = spans.end();// e il primo token che segue il match // fa qualcosa con il documento } JAVA Code

32 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 32 SpanTermQuery span1 = new SpanTermQuery(new Term(term, antonio)); SpanTermQuery span2 = new SpanTermQuery(new Term(term, meucci)); SpanQuery[] clauses = new SpanQuery[] { span1, span2 }; SpanNearQuery near = new SpanNearQuery(clauses, 2, true); Spans spans = near.getSpans(reader); while(spans.next()) { int docNumber = spans.doc(); Document doc = reader.document(docNumber); int primoToken = spans.start(); int ultimoToken = spans.end();// e il primo token che segue il match // fa qualcosa con il documento } JAVA Code SpanNearQuery Effettua interrogazioni ponendo un limite di vicinanza per le varie clausole di tipo SpanQuery nellordine o no?distanza massima

33 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 33 Term Vector In Lucene, è possibile rappresentare tutti i termini e i conteggi di occorrenze dei termini in uno specifico campo di unistanza di Document: –(nomeCampo, (term 1, termCount 1 ),..., (term n, termCount n )) Queste informazioni vengono memorizzate in un campo solo se specificato esplicitamente: Field f = new Field(term, testo, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.YES); JAVA Code

34 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 34 Term Vector Le opzioni sono: –Field.TermVector.NO Non memorizza questa informazione –Field.TermVector.YES Memorizza le coppie (termine, conteggio) –Field.TermVector.WITH_POSITIONS Memorizza anche le posizioni dei token –Field.TermVector.WITH_OFFSETS Memorizza anche le posizioni dei token al livello del carattere –Field.TermVector.WITH_POSITIONS_OFFSETS Memorizza anche le posizioni dei token e al livello del carattere

35 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 35 Accedere ai Term Vector Per accedere a un term vector, è necessario richiamare un apposito metodo della classe IndexReader: Se è stata memorizzata anche linformazione di posizione e/o offset, è possibile effettuare un cast alla classe TermPositionVector: TermFreqVector tfv = reader.getTermFreqVector(docNumber, fieldName); TermFreqVector[] tfvs = reader.getTermFreqVectors(docNumber); String[] terms = tfv.getTerms(); int[] freqs = tfv.getTermFrequencies(); JAVA Code TermPositionVector tpv = (TermPositionVector)tfv; For (int k = 0; k < terms.length; k++) { // lavora sul termine k-esimo int[] positions = tpv.getTermPositions(k); TermVectorOffsetInfo[] offsets = tpv.getOffsets(k); //... } JAVA Code

36 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 36 Come ottenere il numero di un documento? Dato il risultato di una interrogazione, è necessario chiamare il metodo id(): Hits hits = is.search(q); for (int k = 0; k < hits.length(); k++) { int docNumber = hits.id(k); TermFreqVector tfv = reader.getTermFreqVector(docNumber, fieldName); // usa tfv... } JAVA Trick

37 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 37 Perché utilizzare i TermFreqVector? Permettono di espandere linterrogazione originaria utilizzando termini dai documenti (Relevance Feedback) –Lutente o il sistema selezionano i documenti più rilevanti (es. i primi x documenti nella lista ordinata per punteggio) –Si ottengono i termini dai TermFreqVector di ciascun documento e si costruisce una nuova interrogazione –E possibile applicare un boost sulle frequenze dei termini

38 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 38 Boosting Come aumentare limportanza di un documento e/o di un campo in fase di indicizzazione? Metodo setBoost() Il valore di boost è un float compreso tra 0.0 e 1.0 Il valore di boost del documento e del campo viene utilizzato da Lucene per calcolare limportanza del documento recuperato in fase di ricerca –http://lucene.apache.org/java/2_3_1/api/org/apache/lucene/search/Simi larity.html Document d = new Document(); Field f = new Field(term, assistito, Field.Store.NO, Field.Index.ANALYZED) d.setBoost(1.0); f.setBoost(0.9); d.add(f); writer.addDocument(d); JAVA Code

39 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 39 Visualizzazione e diagnosi di un indice: Luke Luke: uno strumento di visualizzazione e diagnostica degli indici Lucene –Scorrere i documenti per id o per termine –Visualizzare documenti –Recuperare una lista ordinata dei termini più frequenti –Eseguire ricerche e scorrere i risultati –Eliminare documenti dallindice –Ottimizzare un indice

40 25/01/2014Lucene: API efficienti per ricerche indicizzatePagina 40 Sviluppi di Lucene Nutch –Un motore di ricerca web che si basa su Lucene Solr –Server di ricerca ad alte prestazioni costruito utilizzando Lucene Mahout –Sottoprogetto Lucene con lobiettivo di creare una suite di librerie scalabili di apprendimento automatico


Scaricare ppt "Roberto Navigli, Fulvio DAntonio Lucene: Una libreria efficiente per ricerche di testo."

Presentazioni simili


Annunci Google