2012-05-15 15 views
6

È possibile utilizzare Lucene SpanQuery per trovare tutte le occorrenze in cui i termini "rosso" "verde" e "blu" appaiono tutti all'interno di una singola frase?Ricerca sensibile alle frasi con Lucene SpanQuery

Il mio primo approccio (incompleto/errato) è quello di scrivere un analizzatore che posiziona un token marcatore di frase speciale e l'inizio di una frase nella stessa posizione della prima parola della frase e quindi di eseguire una query per qualcosa di simile al seguenti:

SpanQuery termsInSentence = new SpanNearQuery(
    SpanQuery[] { 
    new SpanTermQuery(new Term (MY_SPECIAL_SENTENCE_TOKEN)), 
    new SpanTermQuery(new Term ("red")), 
    new SpanTermQuery(new Term ("green")), 
    new SpanTermQuery(new Term ("blue")), 
    }, 
    999999999999, 
    false 
); 

SpanQuery nextSentence = new SpanTermQuery(new Term (MY_SPECIAL_SENTENCE_TOKEN)); 

SpanNotQuery notInNextSentence = new SpanNotQuery(termsInSentence,nextSentence); 

il problema, naturalmente, è che nextSentence non è davvero il prossimo frase, è qualsiasi marcatore frase, compreso quello nella frase che termsInSentence partite. Quindi questo non funzionerà.

Il mio prossimo approccio è creare l'analizzatore che posiziona il token prima della frase (ovvero prima della prima parola anziché nella stessa posizione della prima parola). Il problema con questo è che devo quindi tenere conto dell'offset extra causato da MY_SPECIAL_SENTENCE_TOKEN. Inoltre, questo sarà particolarmente negativo all'inizio quando sto usando un modello naif per dividere le frasi (ad es. Dividere su /\.\s+[A-Z0-9]/) perché dovrò tenere conto di tutti i (falsi) indicatori di frase quando cerco USS Enterprise.

Quindi ... come dovrei avvicinarmi a questo?

risposta

1

Indicherei ogni frase come un documento di Lucene, incluso un campo che indica da quale fonte proviene la frase. A seconda del materiale sorgente, il sovraccarico di frase/LuceneDoc può essere accettabile.

0

In realtà, sembra che tu sia abbastanza vicino alla soluzione. Penso che indicizzare una bandiera di fine frase sia un buon approccio. Il problema è che il tuo flag di fine frase è nel tuo SpanNearQuery, che è ciò che ti sta buttando fuori. Stai chiedendo di trovare un intervallo che contiene entrambi e non contiene MY_SPECIAL_SENTENCE_TOKEN. La query si contraddice, quindi, ovviamente, non troverà corrispondenze. Quello che devi sapere, è che i tre termini ("rosso", "verde" e "blu") si verificano in uno span che non si sovrappone a MY_SPECIAL_SENTENCE_TOKEN (ovvero, il token di frase non compare tra quelli termini).

Inoltre, la mancanza di nomi di campo nei Term ctors sarebbe problema, ma Lucene dovrebbe un'eccezione lamentano che, in modo indovinando che non è il vero problema qui. Potrebbe essere che la versione di Lucene al momento in cui questo è stato scritto non si lamentava dei campi non corrispondenti in SpanNears, quindi forse vale la pena menzionarlo.

Questo sembra funzionare per me:

SpanQuery termsInSentence = new SpanNearQuery(
    new SpanQuery[] { 
     new SpanTermQuery(new Term ("text", "red")), 
     new SpanTermQuery(new Term ("text", "green")), 
     new SpanTermQuery(new Term ("text", "blue")), 
    }, 
    9999, 
    false 
); 

SpanQuery nextSentence = new SpanTermQuery(new Term ("text", MY_SPECIAL_SENTENCE_TOKEN)); 

SpanQuery notInNextSentence = new SpanNotQuery(termsInSentence,nextSentence); 

Per quanto riguarda dove dividere le frasi, invece di utilizzare l'approccio regex ingenuo, vorrei provare a utilizzare java.text.Breakiterator. Non è perfetto, ma fa un buon lavoro.