2012-05-15 6 views
6

Ist es möglich, eine Lucene SpanQuery zu verwenden, um alle Vorkommen zu finden, bei denen die Begriffe "rot", "grün" und "blau" in einem einzigen Satz vorkommen?Satzbewusste Suche mit Lucene SpanQueries

Mein erster (unvollständiger/inkorrekter) Ansatz besteht darin, einen Analysator zu schreiben, der ein spezielles Satzmarker-Token und den Anfang eines Satzes an der gleichen Position wie das erste Wort des Satzes platziert und dann nach etwas Ähnlichem abfragt folgende:

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); 

das Problem ist natürlich, dass nextSentence Satz nicht wirklich der nächsten ist, dann ist es jeden Satz Marker, einschließlich der in dem Satz, dass termsInSentence Streichhölzer. Daher wird das nicht funktionieren.

Meine nächste Annäherung ist, den Analysator zu verursachen, der das Zeichen vor dem Satz setzt (das ist vor das erste Wort und nicht in der gleichen Position wie das erste Wort). Das Problem dabei ist, dass ich dann den zusätzlichen Offset berücksichtigen muss, der durch MY_SPECIAL_SENTENCE_TOKEN verursacht wird. Darüber hinaus ist es besonders schlecht, wenn ich ein naives Muster verwende, um Sätze zu teilen (zB split auf /\.\s+[A-Z0-9]/), weil ich alle (falschen) Satzmarker berücksichtigen muss, wenn ich nach USS Enterprise suche.

Also ... wie soll ich das angehen?

Antwort

1

Ich würde jeden Satz als Lucene-Dokument indizieren, einschließlich eines Feldes, das angibt, aus welchem ​​Quelldokument der Satz stammt. Abhängig von Ihrem Ausgangsmaterial kann der Overhead von Satz/LuceneDoc akzeptabel sein.

0

Eigentlich sieht es so aus, als ob Sie der Lösung ziemlich nahe sind. Ich denke, das Indizieren einer Ende-von-Satz-Flagge ist ein guter Ansatz. Das Problem ist, dass Ihr Satzende-Flag in Ihrem SpanNearQuery ist, was Sie abschrecken wird. Sie bitten es, einen Bereich zu finden, der beides enthält und nichtMY_SPECIAL_SENTENCE_TOKEN enthält. Die Abfrage widerspricht sich selbst, daher findet sie natürlich keine Übereinstimmungen. Was Sie wirklich wissen müssen, ist, dass die drei Begriffe ("rot", "grün" und "blau") in einem Bereich auftreten, der sich nicht mit MY_SPECIAL_SENTENCE_TOKEN überschneidet (das heißt, das Satz-Token erscheint nicht dazwischen) Begriffe).

Auch das Fehlen von Feldnamen in dem Term ctors wäre Problem, aber Lucene sollte eine Ausnahme darüber beschwert werfen, so raten, das ist nicht das eigentliche Problem hier. Könnte sein, dass die Lucene-Version zu der Zeit, als sie geschrieben wurde, sich nicht über nicht übereinstimmende Felder in SpanNears beschwert hat, also vielleicht erwähnenswert.

Dies ist für mich zu arbeiten scheint:

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); 

Soweit wo Sätze zu spalten, anstatt den naiven regex Ansatz zu verwenden, würde ich versuchen, java.text.Breakiterator verwenden. Es ist nicht perfekt, aber es macht einen ziemlich guten Job.