سؤال

بالنظر إلى وثيقة {'FOO'، "BAR"، "Baz"}، أريد أن أتطابق باستخدام Spanearquery مع الرموز {'Baz' و "Extra '}

ولكن هذا فشل.

كيف أذهب حول هذا؟

اختبار عينة (باستخدام Lucene 2.9.1) مع النتائج التالية:

  • givensinglematch - تمرير
  • giventwomatches - تمرير
  • giventhreematches - تمرير
  • givensinglematch_andextraintm - فشل

...

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);
    }
}
هل كانت مفيدة؟

المحلول

يتيح لك Spannearquery العثور على مصطلحات ضمن مسافة معينة من بعضها البعض.

مثال (من http://www.lucidimagination.com/blog/2009/07/18/the-spanquery/):

قل نريد أن نجد لوسين في غضون 5 مناصب دوغ، مع دوغ بعد لوسن (أمر المسائل) - يمكنك استخدام الابتدائية التالية:

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

النص البديل http://www.lucidimagining.com/blog/wp-content/uploads/2009/07/spanquery-dia1.png.

في هذا النص العينة، Lucene ضمن 3 من Doug

ولكن بالنسبة لمزيد من مثالك، فإن المباراة الوحيدة التي يمكنني رؤيتها هي أن كل من الاستعلام الخاص بك والوثيقة المستهدفة لها "قرص مضغوط" (وأقدم افتراض أن كل هذه الشروط في مجال واحد). في هذه الحالة، لا تحتاج إلى استخدام أي نوع استعلام خاص. باستخدام الآليات القياسية، سوف تحصل على بعض الترجيح غير الصفري بناء على حقيقة أن كلاهما يحتوي على نفس المصطلح في نفس المجال.

تحرير 3. - ردا على آخر تعليق، الجواب هو أنه لا يمكنك استخدام SpanNearQuery للقيام بأي شيء آخر غير المخصص له، والتي تعاني من معرفة ما إذا كانت مصطلحات متعددة في المستند تحدث ضمن عدد معين من أماكن بعضها البعض. لا أستطيع أن أقول ما هي حالة الاستخدام المحددة / النتائج المتوقعة الخاصة بك (لا تتردد في نشرها)، ولكن في الحالة الأخيرة إذا كنت ترغب فقط في معرفة ما إذا كان واحدا أو أكثر من ("Baz"، "Extra") الوثيقة، BooleanQuery سوف تعمل على ما يرام.

تحرير 4. - الآن بعد أن قمت بنشر حالة استخدامك، أفهم ما تريد القيام به. هنا كيف يمكنك القيام بذلك: استخدم BooleanQuery كما ذكر أعلاه للجمع بين المصطلحات الفردية التي تريدها وكذلك SpanNearQuery, ، وتعيين دفعة على SpanNearQuery.

لذلك، فإن الاستعلام في نموذج النص سيبدو كما يلي:

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

(كمثال - هذا من شأنه أن يتطابق مع جميع المستندات التي تحتوي على "baz" أو "إضافي"، ولكن قم بتعيين درجات أعلى للمستندات التي تكون فيها المصطلحات "BAZ" و "تحدث إضافية في غضون 100 مكان من بعضها البعض؛ ضبط الموضع والتعزيز تريد. هذا المثال موجود من كتاب الطبخ Solr، لذا فقد لا يتم تحليله في لوسن، أو قد يعطي نتائج غير مرغوب فيها. هذا جيد، لأنه في القسم التالي، أظهر لك كيفية بناء هذا باستخدام API).

برمجيا، سوف تبني ذلك على النحو التالي:

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

امل ان يساعد! في المستقبل، حاول البدء بالإخراج بالتحديد ما هي النتائج التي تتوقعها بالضبط - حتى لو كانت واضحة لك، فقد لا يكون ذلك للقارئ، ويمكن أن يتجنب أن يتجنب الاضطرار إلى العودة ذهابا وإيابا عدة مرات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top