You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by kr...@apache.org on 2022/04/27 19:33:43 UTC

[solr] branch main updated: SOLR-16169: IndexBasedSpellChecker with empty spellcheck.q results in NegativeArraySizeException (#820)

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

krisden pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 6510f14a267 SOLR-16169: IndexBasedSpellChecker with empty spellcheck.q results in NegativeArraySizeException (#820)
6510f14a267 is described below

commit 6510f14a267835f2f7aa4f795714d162eb3a0c82
Author: Kevin Risden <ri...@users.noreply.github.com>
AuthorDate: Wed Apr 27 15:33:39 2022 -0400

    SOLR-16169: IndexBasedSpellChecker with empty spellcheck.q results in NegativeArraySizeException (#820)
---
 solr/CHANGES.txt                                   |  2 ++
 .../solr/spelling/AbstractLuceneSpellChecker.java  |  4 +++
 .../solr/spelling/DirectSolrSpellChecker.java      |  4 +++
 .../solr/spelling/DirectSolrSpellCheckerTest.java  | 13 ++++++--
 .../solr/spelling/FileBasedSpellCheckerTest.java   | 38 ++++++++++++++--------
 .../solr/spelling/IndexBasedSpellCheckerTest.java  |  9 +++++
 6 files changed, 55 insertions(+), 15 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 484631dda9f..42f8813e54f 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -71,6 +71,8 @@ Bug Fixes
 
 * SOLR-15830: Concurrent core reloads mess up commits when using Schema API (Bence Szabo via Andras Salamon)
 
+* SOLR-16169: IndexBasedSpellChecker with empty spellcheck.q results in NegativeArraySizeException (Kevin Risden)
+
 Other Changes
 ---------------------
 * SOLR-15897: Remove <jmx/> from all unit test solrconfig.xml files. (Eric Pugh)
diff --git a/solr/core/src/java/org/apache/solr/spelling/AbstractLuceneSpellChecker.java b/solr/core/src/java/org/apache/solr/spelling/AbstractLuceneSpellChecker.java
index 1af07e16388..0ddb6149421 100644
--- a/solr/core/src/java/org/apache/solr/spelling/AbstractLuceneSpellChecker.java
+++ b/solr/core/src/java/org/apache/solr/spelling/AbstractLuceneSpellChecker.java
@@ -141,6 +141,10 @@ public abstract class AbstractLuceneSpellChecker extends SolrSpellChecker {
 
     int count = Math.max(options.count, AbstractLuceneSpellChecker.DEFAULT_SUGGESTION_COUNT);
     for (Token token : options.tokens) {
+      if (token.length() == 0) {
+        result.add(token, Collections.emptyList());
+        continue;
+      }
       String tokenText = new String(token.buffer(), 0, token.length());
       term = new Term(field, tokenText);
       int docFreq = 0;
diff --git a/solr/core/src/java/org/apache/solr/spelling/DirectSolrSpellChecker.java b/solr/core/src/java/org/apache/solr/spelling/DirectSolrSpellChecker.java
index 25f9f1218c1..04b8bec49e4 100644
--- a/solr/core/src/java/org/apache/solr/spelling/DirectSolrSpellChecker.java
+++ b/solr/core/src/java/org/apache/solr/spelling/DirectSolrSpellChecker.java
@@ -186,6 +186,10 @@ public class DirectSolrSpellChecker extends SolrSpellChecker {
         (options.accuracy == Float.MIN_VALUE) ? checker.getAccuracy() : options.accuracy;
 
     for (Token token : options.tokens) {
+      if (token.length() == 0) {
+        result.add(token, Collections.emptyList());
+        continue;
+      }
       String tokenText = token.toString();
       Term term = new Term(field, tokenText);
       int freq = options.reader.docFreq(term);
diff --git a/solr/core/src/test/org/apache/solr/spelling/DirectSolrSpellCheckerTest.java b/solr/core/src/test/org/apache/solr/spelling/DirectSolrSpellCheckerTest.java
index 9e1e192f566..5aff7b50b8f 100644
--- a/solr/core/src/test/org/apache/solr/spelling/DirectSolrSpellCheckerTest.java
+++ b/solr/core/src/test/org/apache/solr/spelling/DirectSolrSpellCheckerTest.java
@@ -17,6 +17,7 @@
 package org.apache.solr.spelling;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
 import org.apache.lucene.util.LuceneTestCase.SuppressTempFileChecks;
 import org.apache.solr.SolrTestCaseJ4;
@@ -70,7 +71,7 @@ public class DirectSolrSpellCheckerTest extends SolrTestCaseJ4 {
               SpellingOptions spellOpts = new SpellingOptions(tokens, searcher.getIndexReader());
               SpellingResult result = checker.getSuggestions(spellOpts);
               assertNotNull("result shouldn't be null", result);
-              Map<String, Integer> suggestions = result.get(tokens.iterator().next());
+              Map<String, Integer> suggestions = result.get(spellOpts.tokens.iterator().next());
               assertFalse("suggestions shouldn't be empty", suggestions.isEmpty());
               Map.Entry<String, Integer> entry = suggestions.entrySet().iterator().next();
               assertEquals("foo", entry.getKey());
@@ -85,6 +86,14 @@ public class DirectSolrSpellCheckerTest extends SolrTestCaseJ4 {
               suggestions = result.get(spellOpts.tokens.iterator().next());
               assertNotNull("suggestions shouldn't be null", suggestions);
               assertTrue("suggestions should be empty", suggestions.isEmpty());
+
+              // Check empty token due to spellcheck.q = ""
+              spellOpts.tokens = Collections.singletonList(new Token("", 0, 0));
+              result = checker.getSuggestions(spellOpts);
+              assertNotNull("result shouldn't be null", result);
+              suggestions = result.get(spellOpts.tokens.iterator().next());
+              assertNotNull("suggestions shouldn't be null", suggestions);
+              assertTrue("suggestions should be empty", suggestions.isEmpty());
               return null;
             });
   }
@@ -138,7 +147,7 @@ public class DirectSolrSpellCheckerTest extends SolrTestCaseJ4 {
               SpellingOptions spellOpts = new SpellingOptions(tokens, searcher.getIndexReader());
               SpellingResult result = checker.getSuggestions(spellOpts);
               assertNotNull("result shouldn't be null", result);
-              Map<String, Integer> suggestions = result.get(tokens.iterator().next());
+              Map<String, Integer> suggestions = result.get(spellOpts.tokens.iterator().next());
               assertNotNull("suggestions shouldn't be null", suggestions);
 
               if (limitQueryLength) {
diff --git a/solr/core/src/test/org/apache/solr/spelling/FileBasedSpellCheckerTest.java b/solr/core/src/test/org/apache/solr/spelling/FileBasedSpellCheckerTest.java
index a7569d85268..ee3aa8a57f1 100644
--- a/solr/core/src/test/org/apache/solr/spelling/FileBasedSpellCheckerTest.java
+++ b/solr/core/src/test/org/apache/solr/spelling/FileBasedSpellCheckerTest.java
@@ -18,6 +18,7 @@ package org.apache.solr.spelling;
 
 import java.io.File;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util.LuceneTestCase.SuppressTempFileChecks;
@@ -80,8 +81,8 @@ public class FileBasedSpellCheckerTest extends SolrTestCaseJ4 {
               Collection<Token> tokens = queryConverter.convert("fob");
               SpellingOptions spellOpts = new SpellingOptions(tokens, searcher.getIndexReader());
               SpellingResult result = checker.getSuggestions(spellOpts);
-              assertTrue("result is null and it shouldn't be", result != null);
-              Map<String, Integer> suggestions = result.get(tokens.iterator().next());
+              assertNotNull("result shouldn't be null", result);
+              Map<String, Integer> suggestions = result.get(spellOpts.tokens.iterator().next());
               Map.Entry<String, Integer> entry = suggestions.entrySet().iterator().next();
               assertTrue(
                   entry.getKey() + " is not equal to " + "foo",
@@ -92,9 +93,18 @@ public class FileBasedSpellCheckerTest extends SolrTestCaseJ4 {
 
               spellOpts.tokens = queryConverter.convert("super");
               result = checker.getSuggestions(spellOpts);
-              assertTrue("result is null and it shouldn't be", result != null);
-              suggestions = result.get(tokens.iterator().next());
-              assertTrue("suggestions is not null and it should be", suggestions == null);
+              assertNotNull("result shouldn't be null", result);
+              suggestions = result.get(spellOpts.tokens.iterator().next());
+              assertNotNull("suggestions shouldn't be null", suggestions);
+              assertTrue("suggestions should be empty", suggestions.isEmpty());
+
+              // Check empty token due to spellcheck.q = ""
+              spellOpts.tokens = Collections.singletonList(new Token("", 0, 0));
+              result = checker.getSuggestions(spellOpts);
+              assertNotNull("result shouldn't be null", result);
+              suggestions = result.get(spellOpts.tokens.iterator().next());
+              assertNotNull("suggestions shouldn't be null", suggestions);
+              assertTrue("suggestions should be empty", suggestions.isEmpty());
               return null;
             });
   }
@@ -125,7 +135,7 @@ public class FileBasedSpellCheckerTest extends SolrTestCaseJ4 {
               SpellingResult result = checker.getSuggestions(spellOpts);
               assertTrue("result is null and it shouldn't be", result != null);
               // should be lowercased, b/c we are using a lowercasing analyzer
-              Map<String, Integer> suggestions = result.get(tokens.iterator().next());
+              Map<String, Integer> suggestions = result.get(spellOpts.tokens.iterator().next());
               assertTrue(
                   "suggestions Size: " + suggestions.size() + " is not: " + 1,
                   suggestions.size() == 1);
@@ -140,9 +150,10 @@ public class FileBasedSpellCheckerTest extends SolrTestCaseJ4 {
               // test something not in the spell checker
               spellOpts.tokens = queryConverter.convert("super");
               result = checker.getSuggestions(spellOpts);
-              assertTrue("result is null and it shouldn't be", result != null);
-              suggestions = result.get(tokens.iterator().next());
-              assertTrue("suggestions is not null and it should be", suggestions == null);
+              assertNotNull("result shouldn't be null", result);
+              suggestions = result.get(spellOpts.tokens.iterator().next());
+              assertNotNull("suggestions shouldn't be null", suggestions);
+              assertTrue("suggestions should be empty", suggestions.isEmpty());
               return null;
             });
   }
@@ -172,9 +183,9 @@ public class FileBasedSpellCheckerTest extends SolrTestCaseJ4 {
               Collection<Token> tokens = queryConverter.convert("solar");
               SpellingOptions spellOpts = new SpellingOptions(tokens, searcher.getIndexReader());
               SpellingResult result = checker.getSuggestions(spellOpts);
-              assertTrue("result is null and it shouldn't be", result != null);
+              assertNotNull("result shouldn't be null", result);
               // should be lowercased, b/c we are using a lowercasing analyzer
-              Map<String, Integer> suggestions = result.get(tokens.iterator().next());
+              Map<String, Integer> suggestions = result.get(spellOpts.tokens.iterator().next());
               assertTrue(
                   "suggestions Size: " + suggestions.size() + " is not: " + 1,
                   suggestions.size() == 1);
@@ -188,9 +199,10 @@ public class FileBasedSpellCheckerTest extends SolrTestCaseJ4 {
 
               spellOpts.tokens = queryConverter.convert("super");
               result = checker.getSuggestions(spellOpts);
-              assertTrue("result is null and it shouldn't be", result != null);
+              assertNotNull("result shouldn't be null", result);
               suggestions = result.get(spellOpts.tokens.iterator().next());
-              assertTrue("suggestions size should be 0", suggestions.size() == 0);
+              assertNotNull("suggestions shouldn't be null", suggestions);
+              assertTrue("suggestions should be empty", suggestions.isEmpty());
               return null;
             });
   }
diff --git a/solr/core/src/test/org/apache/solr/spelling/IndexBasedSpellCheckerTest.java b/solr/core/src/test/org/apache/solr/spelling/IndexBasedSpellCheckerTest.java
index 4f82333e557..dfb640cba79 100644
--- a/solr/core/src/test/org/apache/solr/spelling/IndexBasedSpellCheckerTest.java
+++ b/solr/core/src/test/org/apache/solr/spelling/IndexBasedSpellCheckerTest.java
@@ -18,6 +18,7 @@ package org.apache.solr.spelling;
 
 import java.io.File;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.Map;
@@ -188,6 +189,14 @@ public class IndexBasedSpellCheckerTest extends SolrTestCaseJ4 {
               assertTrue(
                   entry.getValue() + " does not equal: " + SpellingResult.NO_FREQUENCY_INFO,
                   entry.getValue() == SpellingResult.NO_FREQUENCY_INFO);
+
+              // Check empty token due to spellcheck.q = ""
+              spellOpts.tokens = Collections.singletonList(new Token("", 0, 0));
+              result = checker.getSuggestions(spellOpts);
+              assertNotNull(result);
+              suggestions = result.get(spellOpts.tokens.iterator().next());
+              assertNotNull(suggestions);
+              assertTrue("suggestions should be empty", suggestions.isEmpty());
               return null;
             });
   }