You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2020/10/16 17:21:15 UTC

[lucene-solr] branch branch_8x updated (5d45c4b -> 21cef0f)

This is an automated email from the ASF dual-hosted git repository.

jpountz pushed a change to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git.


    from 5d45c4b  SOLR-14933: Ability to add T and P type replica from admin UI (#1991)
     new 2c6a7d3  LUCENE-9578: TermRangeQuery empty string lower bound edge case (#1976)
     new 4ea1b47  LUCENE-9578: Add CHANGES entry.
     new 21cef0f  LUCENE-9524: Fix NPE in SpanWeight#explain when no scoring is require… (#1978)

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 lucene/CHANGES.txt                                 |  9 +++++
 .../org/apache/lucene/search/spans/SpanWeight.java | 21 ++++++++----
 .../org/apache/lucene/util/automaton/Automata.java | 27 ++++++++++++---
 .../lucene/search/spans/TestSpanExplanations.java  | 38 ++++++++++++++++++++++
 .../lucene/util/automaton/TestAutomaton.java       | 36 ++++++++++++++++++++
 5 files changed, 120 insertions(+), 11 deletions(-)


[lucene-solr] 03/03: LUCENE-9524: Fix NPE in SpanWeight#explain when no scoring is require… (#1978)

Posted by jp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jpountz pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 21cef0f526eb46ae4f338e3bf49e949637181080
Author: zacharymorn <za...@gmail.com>
AuthorDate: Fri Oct 16 10:00:46 2020 -0700

    LUCENE-9524: Fix NPE in SpanWeight#explain when no scoring is require… (#1978)
---
 lucene/CHANGES.txt                                 |  4 +++
 .../org/apache/lucene/search/spans/SpanWeight.java | 21 ++++++++----
 .../lucene/search/spans/TestSpanExplanations.java  | 38 ++++++++++++++++++++++
 3 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index b76cd67..0041950 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -116,6 +116,10 @@ Bug Fixes
   all while it should match all non-empty strings.
   (Christoph Buescher via Adrien Grand)
 
+* LUCENE-9524: Fix NPE in SpanWeight#explain when no scoring is required and
+  SpanWeight has null Similarity.SimScorer.
+  (Zach Chen)
+
 Documentation
 ---------------------
 
diff --git a/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java b/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java
index d70d277..f9787fd 100644
--- a/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java
+++ b/lucene/core/src/java/org/apache/lucene/search/spans/SpanWeight.java
@@ -20,6 +20,7 @@ package org.apache.lucene.search.spans;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.Locale;
 import java.util.Map;
 
 import org.apache.lucene.index.LeafReaderContext;
@@ -156,13 +157,19 @@ public abstract class SpanWeight extends Weight {
     if (scorer != null) {
       int newDoc = scorer.iterator().advance(doc);
       if (newDoc == doc) {
-        float freq = scorer.sloppyFreq();
-        LeafSimScorer docScorer = new LeafSimScorer(simScorer, context.reader(), field, true);
-        Explanation freqExplanation = Explanation.match(freq, "phraseFreq=" + freq);
-        Explanation scoreExplanation = docScorer.explain(doc, freqExplanation);
-        return Explanation.match(scoreExplanation.getValue(),
-            "weight("+getQuery()+" in "+doc+") [" + similarity.getClass().getSimpleName() + "], result of:",
-            scoreExplanation);
+        if (simScorer != null) {
+          float freq = scorer.sloppyFreq();
+          LeafSimScorer docScorer = new LeafSimScorer(simScorer, context.reader(), field, true);
+          Explanation freqExplanation = Explanation.match(freq, "phraseFreq=" + freq);
+          Explanation scoreExplanation = docScorer.explain(doc, freqExplanation);
+          return Explanation.match(scoreExplanation.getValue(),
+              "weight("+getQuery()+" in "+doc+") [" + similarity.getClass().getSimpleName() + "], result of:",
+              scoreExplanation);
+        } else {
+          // simScorer won't be set when scoring isn't needed
+          return Explanation.match(0f, String.format(Locale.ROOT,
+              "match %s in %s without score", getQuery(), doc));
+        }
       }
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanExplanations.java b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanExplanations.java
index b986cd4..966cde1 100644
--- a/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanExplanations.java
+++ b/lucene/core/src/test/org/apache/lucene/search/spans/TestSpanExplanations.java
@@ -17,12 +17,22 @@
 package org.apache.lucene.search.spans;
 
 
+import java.io.IOException;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.Term;
 import org.apache.lucene.search.*;
+import org.apache.lucene.store.Directory;
 
 /**
  * TestExplanations subclass focusing on span queries
  */
 public class TestSpanExplanations extends BaseExplanationTestCase {
+  private static final String FIELD_CONTENT = "content";
 
   /* simple SpanTermQueries */
   
@@ -165,4 +175,32 @@ public class TestSpanExplanations extends BaseExplanationTestCase {
     qtest(q, new int[] {0,1,3});
   }
 
+  public void testExplainWithoutScoring() throws IOException {
+    SpanNearQuery query = new SpanNearQuery(new SpanQuery[]{
+        new SpanTermQuery(new Term(FIELD_CONTENT, "dolor")),
+        new SpanTermQuery(new Term(FIELD_CONTENT, "lorem"))},
+        0,
+        true);
+
+    try (Directory rd = newDirectory()) {
+      try (IndexWriter writer = new IndexWriter(rd, newIndexWriterConfig(analyzer))) {
+        Document doc = new Document();
+        doc.add(newTextField(FIELD_CONTENT, "dolor lorem ipsum", Field.Store.YES));
+        writer.addDocument(doc);
+      }
+
+      try (DirectoryReader reader = DirectoryReader.open(rd)) {
+        IndexSearcher indexSearcher = newSearcher(reader);
+        SpanWeight spanWeight = query.createWeight(indexSearcher, ScoreMode.COMPLETE_NO_SCORES, 1f);
+
+        final LeafReaderContext ctx = reader.leaves().get(0);
+        Explanation explanation = spanWeight.explain(ctx, 0);
+
+        assertEquals(0f, explanation.getValue());
+        assertEquals("match spanNear([content:dolor, content:lorem], 0, true) in 0 without score",
+            explanation.getDescription());
+
+      }
+    }
+  }
 }


[lucene-solr] 01/03: LUCENE-9578: TermRangeQuery empty string lower bound edge case (#1976)

Posted by jp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jpountz pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 2c6a7d3efd60d697104cb8ab495fecc4554803c3
Author: Christoph Büscher <cb...@posteo.de>
AuthorDate: Fri Oct 16 19:01:35 2020 +0200

    LUCENE-9578: TermRangeQuery empty string lower bound edge case (#1976)
    
    Currently a TermRangeQuery with the empty String ("") as lower bound and
    includeLower=false leads internally constructs an Automaton that doesn't match
    anything. This is unexpected expecially for open upper bounds where any string
    should be considered to be "higher" than the empty string.
    
    This PR changes "Automata#makeBinaryInterval" so that for an empty string lower
    bound and an open upper bound, any String should match the query regardless or
    the includeLower flag.
---
 .../org/apache/lucene/util/automaton/Automata.java | 27 +++++++++++++---
 .../lucene/util/automaton/TestAutomaton.java       | 36 ++++++++++++++++++++++
 2 files changed, 59 insertions(+), 4 deletions(-)

diff --git a/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java b/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java
index 294700b..deb7375 100644
--- a/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java
+++ b/lucene/core/src/java/org/apache/lucene/util/automaton/Automata.java
@@ -85,7 +85,22 @@ final public class Automata {
     a.finishState();
     return a;
   }
-  
+
+  /**
+   * Returns a new (deterministic) automaton that accepts all binary terms except
+   * the empty string.
+   */
+  public static Automaton makeNonEmptyBinary() {
+    Automaton a = new Automaton();
+    int s1 = a.createState();
+    int s2 = a.createState();
+    a.setAccept(s2, true);
+    a.addTransition(s1, s2, 0, 255);
+    a.addTransition(s2, s2, 0, 255);
+    a.finishState();
+    return a;
+  }
+
   /**
    * Returns a new (deterministic) automaton that accepts any single codepoint.
    */
@@ -254,8 +269,12 @@ final public class Automata {
       cmp = min.compareTo(max);
     } else {
       cmp = -1;
-      if (min.length == 0 && minInclusive) {
-        return makeAnyBinary();
+      if (min.length == 0) {
+        if (minInclusive) {
+          return makeAnyBinary();
+        } else {
+          return makeNonEmptyBinary();
+        }
       }
     }
 
@@ -266,7 +285,7 @@ final public class Automata {
         return makeBinary(min);
       }
     } else if (cmp > 0) {
-      // max > min
+      // max < min
       return makeEmpty();
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/util/automaton/TestAutomaton.java b/lucene/core/src/test/org/apache/lucene/util/automaton/TestAutomaton.java
index e4a09dc..2f521d7 100644
--- a/lucene/core/src/test/org/apache/lucene/util/automaton/TestAutomaton.java
+++ b/lucene/core/src/test/org/apache/lucene/util/automaton/TestAutomaton.java
@@ -1331,6 +1331,23 @@ public class TestAutomaton extends LuceneTestCase {
     assertFalse(Operations.run(a, intsRef("baq")));
     assertTrue(Operations.run(a, intsRef("bara")));
   }
+  
+  public void testMakeBinaryIntervalLowerBoundEmptyString() throws Exception {
+    Automaton a = Automata.makeBinaryInterval(new BytesRef(""), true, new BytesRef("bar"), true);
+    assertTrue(Operations.run(a, intsRef("")));
+    assertTrue(Operations.run(a, intsRef("a")));
+    assertTrue(Operations.run(a, intsRef("bar")));
+    assertFalse(Operations.run(a, intsRef("bara")));
+    assertFalse(Operations.run(a, intsRef("baz")));
+    
+    
+    a = Automata.makeBinaryInterval(new BytesRef(""), false, new BytesRef("bar"), true);
+    assertFalse(Operations.run(a, intsRef("")));
+    assertTrue(Operations.run(a, intsRef("a")));
+    assertTrue(Operations.run(a, intsRef("bar")));
+    assertFalse(Operations.run(a, intsRef("bara")));
+    assertFalse(Operations.run(a, intsRef("baz")));
+  }
 
   public void testMakeBinaryIntervalEqual() throws Exception {
     Automaton a = Automata.makeBinaryInterval(new BytesRef("bar"), true, new BytesRef("bar"), true);
@@ -1352,6 +1369,12 @@ public class TestAutomaton extends LuceneTestCase {
     assertFalse(Operations.run(a, intsRef("barfoop")));
   }
 
+  public void testMakeBinaryExceptEmpty() throws Exception {
+    Automaton a = Automata.makeNonEmptyBinary();
+    assertFalse(Operations.run(a, intsRef("")));
+    assertTrue(Operations.run(a, intsRef(TestUtil.randomRealisticUnicodeString(random(), 1, 10))));
+  }
+
   public void testMakeBinaryIntervalOpenMax() throws Exception {
     Automaton a = Automata.makeBinaryInterval(new BytesRef("bar"), true, null, true);
     assertFalse(Operations.run(a, intsRef("bam")));
@@ -1366,6 +1389,19 @@ public class TestAutomaton extends LuceneTestCase {
     assertTrue(Operations.run(a, intsRef("zzz")));
   }
 
+  public void testMakeBinaryIntervalOpenMaxZeroLengthMin() throws Exception {
+    // when including min, automaton should accept "a"
+    Automaton a = Automata.makeBinaryInterval(new BytesRef(""), true, null, true);
+    assertTrue(Operations.run(a, intsRef("")));
+    assertTrue(Operations.run(a, intsRef("a")));
+    assertTrue(Operations.run(a, intsRef("aaaaaa")));
+    // excluding min should still accept "a"
+    a = Automata.makeBinaryInterval(new BytesRef(""), false, null, true);
+    assertFalse(Operations.run(a, intsRef("")));
+    assertTrue(Operations.run(a, intsRef("a")));
+    assertTrue(Operations.run(a, intsRef("aaaaaa")));
+  }
+
   public void testMakeBinaryIntervalOpenMin() throws Exception {
     Automaton a = Automata.makeBinaryInterval(null, true, new BytesRef("foo"), true);
     assertFalse(Operations.run(a, intsRef("foz")));


[lucene-solr] 02/03: LUCENE-9578: Add CHANGES entry.

Posted by jp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jpountz pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 4ea1b47e37390e05868eeb47699ff514441682c0
Author: Adrien Grand <jp...@gmail.com>
AuthorDate: Fri Oct 16 19:11:19 2020 +0200

    LUCENE-9578: Add CHANGES entry.
---
 lucene/CHANGES.txt | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index c2b871f..b76cd67 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -111,6 +111,11 @@ Bug Fixes
 
 * LUCENE-9401: Include field in ComplexPhraseQuery's toString() (Thomas Hecker via Munendra S N)
 
+* LUCENE-9578: Fix TermRangeQuery when there is no upper bound and the lower
+  bound is the empty string excluded. This would previously match no strings at
+  all while it should match all non-empty strings.
+  (Christoph Buescher via Adrien Grand)
+
 Documentation
 ---------------------