Frage

Bei einem Dokument { 'foo', 'bar', 'baz'}, ich will mit SpanNearQuery mit den Tokens übereinstimmen { 'baz', 'Extra'}

Aber dies nicht gelingt.

Wie kann ich um dieses gehen?

Probentest (unter Verwendung von Lucene 2.9.1) mit den folgenden Ergebnissen:

  • givenSingleMatch - PASS
  • givenTwoMatches - PASS
  • givenThreeMatches - PASS
  • givenSingleMatch_andExtraTerm - FAIL

...

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.spans.SpanNearQuery;
import org.apache.lucene.search.spans.SpanQuery;
import org.apache.lucene.search.spans.SpanTermQuery;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.Version;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

public class SpanNearQueryTest {

    private RAMDirectory directory = null;

    private static final String BAZ = "baz";
    private static final String BAR = "bar";
    private static final String FOO = "foo";
    private static final String TERM_FIELD = "text";

    @Before
    public void given() throws IOException {
        directory = new RAMDirectory();
        IndexWriter writer = new IndexWriter(
                directory,
                new StandardAnalyzer(Version.LUCENE_29),
                IndexWriter.MaxFieldLength.UNLIMITED);

        Document doc = new Document();
        doc.add(new Field(TERM_FIELD, FOO, Field.Store.NO, Field.Index.ANALYZED));
        doc.add(new Field(TERM_FIELD, BAR, Field.Store.NO, Field.Index.ANALYZED));
        doc.add(new Field(TERM_FIELD, BAZ, Field.Store.NO, Field.Index.ANALYZED));

        writer.addDocument(doc);
        writer.commit();
        writer.optimize();
        writer.close();
    }

    @After
    public void cleanup() {
        directory.close();
    }

    @Test
    public void givenSingleMatch() throws IOException {

        SpanNearQuery spanNearQuery = new SpanNearQuery(
                new SpanQuery[] {
                        new SpanTermQuery(new Term(TERM_FIELD, FOO))
                }, Integer.MAX_VALUE, false);

        TopDocs topDocs = new IndexSearcher(IndexReader.open(directory)).search(spanNearQuery, 100);

        Assert.assertEquals("Should have made a match.", 1, topDocs.scoreDocs.length);
    }

    @Test
    public void givenTwoMatches() throws IOException {

        SpanNearQuery spanNearQuery = new SpanNearQuery(
                new SpanQuery[] {
                        new SpanTermQuery(new Term(TERM_FIELD, FOO)),
                        new SpanTermQuery(new Term(TERM_FIELD, BAR))
                }, Integer.MAX_VALUE, false);

        TopDocs topDocs = new IndexSearcher(IndexReader.open(directory)).search(spanNearQuery, 100);

        Assert.assertEquals("Should have made a match.", 1, topDocs.scoreDocs.length);
    }

    @Test
    public void givenThreeMatches() throws IOException {

        SpanNearQuery spanNearQuery = new SpanNearQuery(
                new SpanQuery[] {
                        new SpanTermQuery(new Term(TERM_FIELD, FOO)),
                        new SpanTermQuery(new Term(TERM_FIELD, BAR)),
                        new SpanTermQuery(new Term(TERM_FIELD, BAZ))
                }, Integer.MAX_VALUE, false);

        TopDocs topDocs = new IndexSearcher(IndexReader.open(directory)).search(spanNearQuery, 100);

        Assert.assertEquals("Should have made a match.", 1, topDocs.scoreDocs.length);
    }

    @Test
    public void givenSingleMatch_andExtraTerm() throws IOException {

        SpanNearQuery spanNearQuery = new SpanNearQuery(
                new SpanQuery[] {
                        new SpanTermQuery(new Term(TERM_FIELD, BAZ)),
                        new SpanTermQuery(new Term(TERM_FIELD, "EXTRA"))
                },
                Integer.MAX_VALUE, false);

        TopDocs topDocs = new IndexSearcher(IndexReader.open(directory)).search(spanNearQuery, 100);

        Assert.assertEquals("Should have made a match.", 1, topDocs.scoreDocs.length);
    }
}
War es hilfreich?

Lösung

SpanNearQuery können Sie Begriffe finden, die in einem gewissen Abstand voneinander sind.

Beispiel (von http://www.lucidimagination.com/ Blog / 2009/07/18 / the-spanquery / ):

  

Sagen wir lucene innerhalb von 5 finden möchten   Positionen von Doug, mit folgenden doug   lucene (Ordnung Sachen) - Sie konnten verwenden   die folgenden SpanQuery:

new SpanNearQuery(new SpanQuery[] {
  new SpanTermQuery(new Term(FIELD, "lucene")),
  new SpanTermQuery(new Term(FIELD, "doug"))},
  5,
  true);

alt text http: // www. lucidimagination.com/blog/wp-content/uploads/2009/07/spanquery-dia1.png

  

In diesem Beispieltext, Lucene ist innerhalb   3 von Doug

Aber für Ihr Beispiel, das einzige Spiel ich sehen kann, ist, dass sowohl Ihre Anfrage und das Zieldokument haben „cd“ (und ich mache die Annahme, dass alle diese Begriffe in einem einzigen Feld sind). In diesem Fall brauchen Sie keinen speziellen Abfragetyp zu verwenden. die Standard-Mechanismen verwenden, werden Sie einig Nicht-Null-Gewichtung erhalten, basierend auf der Tatsache, dass sie beide den gleichen Begriff im gleichen Feld enthalten.

Bearbeiten 3 - als Antwort auf neuesten Kommentar, ist die Antwort, dass man nicht SpanNearQuery etwas anderes als das zu tun, verwenden kann, die sie für die bestimmt sind, die aus, ob mehrere Begriffe in einem Dokument zu finden sind tritt innerhalb einer bestimmten Anzahl von Plätzen voneinander. Ich kann nicht sagen, was Ihre spezifischen Anwendungsfall / erwartete Ergebnisse (fühlen sich frei, es zu schreiben), aber im letzten Fall, wenn Sie nur, ob ein oder mehrere finden möchten ( „BAZ“, „EXTRA“) ist in das Dokument, ein BooleanQuery wird gut funktionieren.

Bearbeiten 4 - jetzt, dass Sie Ihren Anwendungsfall gebucht haben, verstehe ich, was Sie tun wollen. Hier ist, wie Sie es tun können. Verwenden, um eine BooleanQuery, wie oben erwähnt, die einzelnen Begriffe kombinieren Sie sowie die SpanNearQuery wollen, und legen Sie einen Schub auf der SpanNearQuery

So würde die Abfrage in Textform wie folgt aussehen:

BAZ OR EXTRA OR "BAZ EXTRA"~100^5

(als Beispiel - dies würde alle Dokumente gefunden eine höhere Punktzahl zu Dokumenten, die entweder „BAZ“ oder „EXTRA“, aber zuweisen, wo die Begriffe „BAZ“ und „EXTRA innerhalb von 100 Stellen voneinander auftreten, stellen Sie die Position und steigern Sie, wie Sie möchten. in diesem Beispiel wird aus der Solr Kochbuch ist, damit es nicht in Lucene analysieren oder können zu unerwünschten Ergebnissen führen. das ist in Ordnung, denn im nächsten Abschnitt zeige ich Ihnen, wie Sie bauen diese mithilfe der API).

Programmatisch würde konstruieren Sie dies wie folgt:

Query top = new BooleanQuery();

// Construct the terms since they will be used more than once
Term bazTerm = new Term("Field", "BAZ");
Term extraTerm = new Term("Field", "EXTRA");

// Add each term as "should" since we want a partial match
top.add(new TermQuery(bazTerm), BooleanClause.Occur.SHOULD);
top.add(new TermQuery(extraTerm), BooleanClause.Occur.SHOULD);

// Construct the SpanNearQuery, with slop 100 - a document will get a boost only
// if BAZ and EXTRA occur within 100 places of each other.  The final parameter means
// that BAZ must occur before EXTRA.
SpanNearQuery spanQuery = new SpanNearQuery(
                              new SpanQuery[] { new SpanTermQuery(bazTerm), 
                                                new SpanTermQuery(extraTerm) }, 
                              100, true);

// Give it a boost of 5 since it is more important that the words are together
spanQuery.setBoost(5f);

// Add it as "should" since we want a match even when we don't have proximity
top.add(spanQuery, BooleanClause.Occur.SHOULD);

Ich hoffe, das hilft! In der Zukunft versuchen, durch die Veröffentlichung genau zu beginnen, welche Ergebnisse Sie erwarten - auch wenn es Ihnen offensichtlich ist, kann es den Leser nicht sein, und explizit sein kann vermeiden hin und her, so viele Male gehen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top