2013-03-01 5 views
11

Rozumiem, jak zwiększyć pola w czasie indeksowania lub czasu zapytania. Jak jednak zwiększyć wynik dopasowania hasła bliższego początkowi tytułu?lucene - podać większą wagę im bliżej początku tytułu

Przykład:

Query = "lucene" 

Doc1 title = "Lucene: Homepage" 
Doc2 title = "I have a question about lucene?" 

Chciałbym pierwszy dokument zdobyć wyższy od „Lucene” jest bliżej początku (pomijając termin freq na razie).

Widzę, jak używać SpanQuery do określania odległości między terminami, ale nie jestem pewien, jak wykorzystać informacje o pozycji w polu.

Używam Lucene 4.1 w Javie.

+0

W odwróconym indeksie terminy nie mają pozycji, a pojedynczy termin pojawia się wiele razy w dokumencie (polu). Nie widzę oczywistego rozwiązania. –

+0

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

+0

@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

Odpowiedz

9

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); 
      } 
     } 
    } 
+0

zadziałało jak czar! – prestomanifesto

+0

To tylko zwiększa pierwszą pozycję, prawda? Więc punktacja jest naprawdę realizowana ręcznie, nie ma wsparcia od 'SpanQuery'. Można również dodać więcej klauzul dla dalszych pozycji, ale stałoby się to dość nieporęczne, szczególnie jeśli dwa lub więcej terminów zostało zdobyty w ten sposób. Powiedzmy, że nie nazywam tego "oczywistym" rozwiązaniem :) –

+0

To zwiększa pierwszą pozycję, jeśli powiesz 'nowy SpanFirstQuery (spanTermQuery, 1)'. Możesz maksymalnie zwiększyć maksymalną pozycję, nie musisz dodawać innych klauzul. Nie wiem, co masz na myśli "ręcznie", nie zrobiłem żadnego wyniku ręcznie, po prostu użyłem tego, co lucene odkrywa po wyjęciu z pudełka. Oczywiste czy nie jest osobiste. Z mojej perspektywy jest to łatwe, ponieważ nie musiałem pisać niestandardowego kodu o podobieństwach/wynikach itp. – javanna

0

z książki „Lucene w Akcji 2.”

"Lucene posiada wbudowany w PayloadTermQuery zapytań, w opakowaniu org.apache.lucene.search.payloads. To zapytanie jest tylko jak SpanTermQuery że w to pasuje do wszystkich dokumentów zawierających określony termin i śledzi rzeczywistych zdarzeń (przęseł) z meczów.

Ale potem idzie dalej, umożliwiając przyczynić czynnik punktacji na podstawie ładunków, które pojawiają na każdym zdarzeniu. Aby to zrobić, musisz utworzyć własną klasę Podobieństwa definiujący metody scorePayload, jak to "

public class BoostingSimilarity extends DefaultSimilarity { 
public float scorePayload(int docID, String fieldName, 
int start, int end, byte[] payload, 
int offset, int length) { 
.... 
} 

«start»w powyższym kodzie jest tylko położenie ładunku zacząć. Ładunek jest związany Tak więc pozycja początkowa odnosi się również do tego terminu (przynajmniej tak uważam).

Używając powyższego kodu, ale pomijając ładunek, uzyskasz dostęp do pozycji "start" po miejsce punktacji, a następnie możesz zwiększyć wynik w oparciu o tę wartość początkową.

Na przykład: nowy wynik = Oryginalny wynik * (1.0f/start-pozycja)

Mam nadzieję, że powyższe prace, proszę pisać tutaj jeśli znajdziesz jakieś inne skuteczne rozwiązanie ..

+1

To brzmiało dobrze, ale nie mogłem go uruchomić w Lucene 4.1 – prestomanifesto

+0

przepraszam za wprowadzanie w błąd .. mogę wiedzieć dlaczego nie pracowałem ? – phani

+0

Funkcja 'scorePayload()' nie jest wywoływana, jeśli nie masz rzeczywistych ładunków. To samo dla parametru PayloadFunction PayloadTermQuery – sbk