2013-03-23 15 views
5

Sto utilizzando Lucene 4.2 e sto implementando l'impaginazione dei risultati.Lucene 4 Impaginazione

IndexSearcher.searchAfter fornisce un modo efficiente di implementare la funzionalità "pagina successiva" ma qual è il modo migliore per implementare la funzionalità "pagina precedente" o anche "vai alla pagina"? Ad esempio, non c'è IndexSearcher.searchBefore.

Stavo considerando di determinare il numero totale di pagine date le dimensioni della pagina e di mantenere una matrice per tracciare il "dopo" ScoreDoc per ogni pagina (la matrice verrà popolata quando i risultati vengono cercati). Ciò mi consentirebbe di utilizzare il "più vicino" ScoreDoc per l'uso in IndexSearcher.searchAfter (o null nel caso peggiore).

Ha senso? C'è un approccio migliore?

+0

Ciao, puoi spiegare l'impaginazione in lucene 4.x e anche io di fronte allo stesso problema .. –

+0

Sto usando l'approccio discusso nel 3 ° paragrafo sopra. Funziona abbastanza bene tranne che per il paging molto profondo (nessuna sorpresa). – hudsonb

risposta

11

Ho utilizzato Lucene 4.8 e ho lavorato a un'interfaccia REST che include l'impaginazione. La mia soluzione è stata utilizzare un TopScoreDocCollector e chiamare il metodo topDocs (int startIndex, int numberOfhits). L'indice iniziale viene calcolato moltiplicando il numero di pagina basato sullo zero per il numero di risultati.

... 
DirectoryReader reader = DirectoryReader.open(MMapDirectory.open(java.io.File(indexFile)); 
IndexSearcher searcher = new IndexSearcher(reader); 
TopScoreDocCollector collector = TopScoreDocCollector.create(MAX_RESULTS, true); // MAX_RESULTS is just an int limiting the total number of hits 
int startIndex = (page -1) * hitsPerPage; // our page is 1 based - so we need to convert to zero based 
Query query = new QueryParser(Version.LUCENE_48, "All", analyzer).parse(searchQuery); 
searcher.search(query, collector); 
TopDocs hits = collector.topDocs(startIndex, hitsPerPage); 
... 

Quindi l'interfaccia REST accetta il numero di pagina e il numero di hit per pagina come parametri. Quindi andare avanti o indietro è semplice come inviare una nuova richiesta con il valore appropriato per la pagina

+0

Grazie Jaimie, mi piace questo approccio. – hudsonb

4

Sono d'accordo con la soluzione spiegata da Jaimie. Ma voglio sottolineare un altro aspetto di cui devi essere consapevole e che aiuta a capire il meccanismo generale di un motore di ricerca.

Con il TopDocCollector è possibile definire la quantità di visite che si desidera raccogliere in base alla query di ricerca, prima che il risultato sia ordinato per punteggio o altri criteri di ordinamento.

vedere l'esempio seguente:

collector = TopScoreDocCollector.create(9999, true); 
searcher.search(parser.parse("Clone Warrior"), collector); 
// get first page 
topDocs = collector.topDocs(0, 10); 
int resultSize=topDocs.scoreDocs.length; // 10 or less 
int totalHits=topDocs.totalHits; // 9999 or less 

Raccontiamo Lucene qui per raccogliere un massimo di 9999 documenti contenenti la frase di ricerca 'clone Warrior'. Ciò significa che se l'indice contiene più di 9999 documenti contenenti questa frase di ricerca, il raccoglitore si fermerà dopo essere stato riempito con 9999 visite!

Ciò significa che, quanto più grande si sceglie il MAX_RESULTS come meglio diventa il risultato della ricerca. Ma questo è rilevante solo se ti aspetti un gran numero di hit. D'altra parte, se si cerca "Luke Skywalker" e si aspetta un solo colpo, che il MAX_RESULTS può anche essere impostato a 1.

Quindi cambiare le MAX_RESULTS possono influenzare le scoreDocs restituiti come verrà eseguita l'ordinamento sui colpi raccolti. È praticamente possibile impostare MAX_RESULTS su una dimensione sufficientemente grande in modo che l'utente umano non possa discutere di perdere un documento specifico. Questo concetto è totalmente contrario al comportamento di un database SQL, che considera sempre il pool di dati completo.

Ma lucene supporta anche un altro meccanismo. È possibile, invece di definire MAX_RESULTS per il raccoglitore, in alternativa definire la quantità di tempo che si desidera attendere per il set di risultati. Ad esempio, è possibile definire che si desidera sempre interrompere il raccoglitore dopo 300 ms. Questo è un buon approccio per proteggere la tua applicazione per problemi di prestazioni. Ma se vuoi essere sicuro di contare tutti i documenti rilevanti di quello che devi impostare il parametro per MAX_RESULTS o il tempo di attesa massimo su un valore infinito.