Pregunta

Con un documento con { 'foo', 'valor', 'baz'}, quiero coincidir con el uso de SpanNearQuery con las fichas { 'baz', 'extra'}

Sin embargo, esto no funciona.

¿Cómo puedo evitar esto?

prueba de la muestra (usando lucene 2.9.1) con los siguientes resultados:

  • givenSingleMatch - PASS
  • givenTwoMatches - PASS
  • givenThreeMatches - PASS
  • givenSingleMatch_andExtraTerm - FALLO

...

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);
    }
}
¿Fue útil?

Solución

SpanNearQuery le permite encontrar términos que están dentro de una cierta distancia el uno del otro.

Ejemplo (de http://www.lucidimagination.com/ blog / 2009/07/18 / el-spanquery / ):

  

Supongamos que queremos encontrar Lucene dentro de los 5   posiciones de Doug, con Doug siguiente   Lucene (orden importa) - se puede utilizar   la siguiente 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

  

En este texto de ejemplo, Lucene está dentro de   3 de Doug

Sin embargo, por su ejemplo, el único partido que puedo ver es que tanto su consulta y el documento de destino tienen "cd" (y estoy haciendo la suposición de que todos esos términos se encuentran en un solo campo). En ese caso, no es necesario utilizar ningún tipo de consulta especial. El uso de los mecanismos estándar, obtendrá cierta ponderación distinta de cero basado en el hecho de que ambos contienen el mismo término en el mismo campo.

Editar 3 - en respuesta a la última observación, la respuesta es que no se puede utilizar SpanNearQuery que hacer aparte de lo que se pretende para el, que es para averiguar si varios términos en un documento nada ocurrir dentro de un cierto número de plazas de cada uno. No puedo decir lo que su caso de uso específico / resultados esperados son (no dude en publicarlo), pero en el último caso si sólo desea averiguar si una o más de ( "BAZ", "extra") está en el documento, un BooleanQuery funcionará bien.

Editar 4 - ahora que usted ha publicado su caso de uso, entiendo qué es lo que quiere hacer. Aquí es cómo puede hacerlo:. Usar un BooleanQuery como se mencionó anteriormente para combinar los términos individuales que desee, así como la SpanNearQuery, y establecer un impulso en la SpanNearQuery

Por lo tanto, la consulta en forma de texto se vería así:

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

(como un ejemplo - esto coincidiría con todos los documentos que contienen ya sea "BAZ" o "extra", pero asignar una puntuación más alta a los documentos donde los términos "BAZ" y "ocurren EXTRA dentro de los 100 lugares del uno al otro, ajustar la posición y aumentar a su gusto. este ejemplo es del libro de cocina Solr por lo que no se puede analizar en Lucene, o puede dar resultados no deseados. Eso es bueno, porque en la siguiente sección os muestro cómo construir este uso de la API).

mediante programación, debe estructurar de la siguiente manera:

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

Espero que ayude! En el futuro, tratar de empezar por publicar exactamente qué resultados está esperando - incluso si es obvio para usted, puede que no sea para el lector, y ser explícito puede evitar tener que ir y venir tantas veces

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top