Chciałbym skorzystać z SpanFirstQuery
, który pasuje warunki pobliżu początek pola. Jak wszystkie zapytania o zakres, opiera się na pozycjach, domyślnie włączonych podczas indeksowania w lucene.
Przetestujmy to niezależnie: wystarczy podać swoją SpanTermQuery
i maksymalną pozycję, w której można znaleźć termin (jeden w moim przykładzie).
SpanTermQuery spanTermQuery = new SpanTermQuery(new Term("title", "lucene"));
SpanFirstQuery spanFirstQuery = new SpanFirstQuery(spanTermQuery, 1);
Biorąc pod uwagę twoje dwa dokumenty to zapytanie znajdzie tylko pierwszy z nich z tytułem „Lucene: Strona główna”, jeśli analizuje się ją z StandardAnalyzer
.
Teraz możemy w jakiś sposób połączyć powyższe SpanFirstQuery
z normalnym zapytaniem tekstowym i mieć pierwszy wpływ tylko na wynik.Można łatwo zrobić to za pomocą BooleanQuery
i umieszczenie zapytania zakresowego jak powinien klauzula tak:
Term term = new Term("title", "lucene");
TermQuery termQuery = new TermQuery(term);
SpanFirstQuery spanFirstQuery = new SpanFirstQuery(new SpanTermQuery(term), 1);
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.add(new BooleanClause(termQuery, BooleanClause.Occur.MUST));
booleanQuery.add(new BooleanClause(spanFirstQuery, BooleanClause.Occur.SHOULD));
Istnieje prawdopodobnie różne sposoby, aby osiągnąć ten sam, być może przy użyciu CustomScoreQuery
zbyt lub niestandardowy kod do wdrożenia punktacji , ale wydaje mi się to najłatwiejsze.
kod I wykorzystywane do testowania drukuje następujący wynik (wynik w zestawie) wykonania jedynie TermQuery
, następnie tylko SpanFirstQuery
i wreszcie połączona BooleanQuery
:
------ TermQuery --------
Total hits: 2
title: I have a question about lucene - score: 0.26010898
title: Lucene: I have a really hard question about it - score: 0.22295055
------ SpanFirstQuery --------
Total hits: 1
title: Lucene: I have a really hard question about it - score: 0.15764984
------ BooleanQuery: TermQuery (MUST) + SpanFirstQuery (SHOULD) --------
Total hits: 2
title: Lucene: I have a really hard question about it - score: 0.26912516
title: I have a question about lucene - score: 0.09196242
Oto pełny kod:
public static void main(String[] args) throws Exception {
Directory directory = FSDirectory.open(new File("data"));
index(directory);
IndexReader indexReader = DirectoryReader.open(directory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
Term term = new Term("title", "lucene");
System.out.println("------ TermQuery --------");
TermQuery termQuery = new TermQuery(term);
search(indexSearcher, termQuery);
System.out.println("------ SpanFirstQuery --------");
SpanFirstQuery spanFirstQuery = new SpanFirstQuery(new SpanTermQuery(term), 1);
search(indexSearcher, spanFirstQuery);
System.out.println("------ BooleanQuery: TermQuery (MUST) + SpanFirstQuery (SHOULD) --------");
BooleanQuery booleanQuery = new BooleanQuery();
booleanQuery.add(new BooleanClause(termQuery, BooleanClause.Occur.MUST));
booleanQuery.add(new BooleanClause(spanFirstQuery, BooleanClause.Occur.SHOULD));
search(indexSearcher, booleanQuery);
}
private static void index(Directory directory) throws Exception {
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_41, new StandardAnalyzer(Version.LUCENE_41));
IndexWriter writer = new IndexWriter(directory, config);
FieldType titleFieldType = new FieldType();
titleFieldType.setIndexOptions(FieldInfo.IndexOptions.DOCS_AND_FREQS_AND_POSITIONS);
titleFieldType.setIndexed(true);
titleFieldType.setStored(true);
Document document = new Document();
document.add(new Field("title","I have a question about lucene", titleFieldType));
writer.addDocument(document);
document = new Document();
document.add(new Field("title","Lucene: I have a really hard question about it", titleFieldType));
writer.addDocument(document);
writer.close();
}
private static void search(IndexSearcher indexSearcher, Query query) throws Exception {
TopDocs topDocs = indexSearcher.search(query, 10);
System.out.println("Total hits: " + topDocs.totalHits);
for (ScoreDoc hit : topDocs.scoreDocs) {
Document result = indexSearcher.doc(hit.doc);
for (IndexableField field : result) {
System.out.println(field.name() + ": " + field.stringValue() + " - score: " + hit.score);
}
}
}
W odwróconym indeksie terminy nie mają pozycji, a pojedynczy termin pojawia się wiele razy w dokumencie (polu). Nie widzę oczywistego rozwiązania. –
możliwy duplikat [Lucens najlepszy sposób na wykonanie zapytań "zaczynających się"] (http://stackoverflow.com/questions/15005747/lucens-best-way-to-do-starts-w-queries) – mindas
@MarkoTopolnik You może przechowywać pozycje w lucene i wiedzieć, gdzie jest termin. Zapytania o span polegają w rzeczywistości na pozycjach. SpanFirstQuery wydaje się tutaj dobrze pasować. – javanna