diff --git a/CHANGES.txt b/CHANGES.txt
index 0f62f0ec960..8ca6fb5da56 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -336,6 +336,10 @@ New Features
data sources, processors and transformers for importing data. Supports full data imports as well as
incremental (delta) indexing. See http://wiki.apache.org/solr/DataImportHandler for more details.
(Noble Paul, shalin)
+
+67. SOLR-622: SpellCheckComponent supports auto-loading indices on startup and optionally, (re)builds indices
+ on newSearcher event, if configured in solrconfig.xml
+ (shalin)
Changes in runtime behavior
1. SOLR-559: use Lucene updateDocument, deleteDocuments methods. This
diff --git a/src/java/org/apache/solr/handler/component/SpellCheckComponent.java b/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
index a06ef452d7e..6664bdc64fc 100644
--- a/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
+++ b/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
@@ -17,10 +17,24 @@
package org.apache.solr.handler.component;
-import org.apache.lucene.analysis.Token;
-import org.apache.lucene.analysis.WhitespaceAnalyzer;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.xml.xpath.XPathConstants;
+
import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
@@ -30,29 +44,21 @@ import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.SolrEventListener;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.search.SolrIndexSearcher;
+import org.apache.solr.spelling.AbstractLuceneSpellChecker;
import org.apache.solr.spelling.IndexBasedSpellChecker;
+import org.apache.solr.spelling.QueryConverter;
import org.apache.solr.spelling.SolrSpellChecker;
import org.apache.solr.spelling.SpellingResult;
-import org.apache.solr.spelling.QueryConverter;
+import org.apache.solr.util.RefCounted;
import org.apache.solr.util.plugin.NamedListPluginLoader;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.w3c.dom.NodeList;
-import javax.xml.xpath.XPathConstants;
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.Iterator;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Logger;
-
/**
* A SearchComponent implementation which provides support for spell checking
* and suggestions using the Lucene contributed SpellChecker.
@@ -263,6 +269,12 @@ public class SpellCheckComponent extends SearchComponent implements SolrCoreAwar
throw new RuntimeException("More than one dictionary is missing name.");
}
}
+ // Register event listeners for this SpellChecker
+ core.registerFirstSearcherListener(new SpellCheckerListener(core, checker, true));
+ if (Boolean.parseBoolean((String)spellchecker.get("buildOnCommit"))) {
+ LOG.info("Registering newSearcher listener for spellchecker: " + checker.getDictionaryName());
+ core.registerNewSearcherListener(new SpellCheckerListener(core, checker, false));
+ }
} else {
throw new RuntimeException("Can't load spell checker: " + className);
}
@@ -294,6 +306,47 @@ public class SpellCheckComponent extends SearchComponent implements SolrCoreAwar
}
}
+ private static class SpellCheckerListener implements SolrEventListener {
+ private final SolrCore core;
+ private final SolrSpellChecker checker;
+ private final boolean firstSearcher;
+
+ public SpellCheckerListener(SolrCore core, SolrSpellChecker checker, boolean firstSearcher) {
+ this.core = core;
+ this.checker = checker;
+ this.firstSearcher = firstSearcher;
+ }
+
+ public void init(NamedList args) {
+ }
+
+ public void newSearcher(SolrIndexSearcher newSearcher,
+ SolrIndexSearcher currentSearcher) {
+ if (firstSearcher) {
+ try {
+ LOG.info("Loading spell index for spellchecker: "
+ + checker.getDictionaryName());
+ checker.reload();
+ } catch (IOException e) {
+ LOG.log(Level.SEVERE, "Exception in reloading spell check index for spellchecker: " + checker.getDictionaryName(), e);
+ }
+ } else {
+ // newSearcher event
+ try {
+ LOG.info("Building spell index for spell checker: " + checker.getDictionaryName());
+ checker.build(core, newSearcher);
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE,
+ "Exception in building spell check index for spellchecker: " + checker.getDictionaryName(), e);
+ }
+ }
+
+ }
+
+ public void postCommit() {
+ }
+ }
+
// ///////////////////////////////////////////
// / SolrInfoMBean
// //////////////////////////////////////////
diff --git a/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java b/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
index c15845e33a5..0b11a4e3e19 100644
--- a/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
+++ b/src/test/org/apache/solr/handler/component/SpellCheckComponentTest.java
@@ -67,7 +67,7 @@ public class SpellCheckComponentTest extends AbstractSolrTestCase {
assertU(adoc("id", "8", "lowerfilt", "blee"));
assertU("commit", commit());
}
-
+
public void testExtendedResultsCount() throws Exception {
SolrCore core = h.getCore();
SearchComponent speller = core.getSearchComponent("spellcheck");
@@ -348,7 +348,19 @@ public class SpellCheckComponentTest extends AbstractSolrTestCase {
fail("NullPointerException due to reload not initializing analyzers");
}
}
-
+
+ @SuppressWarnings("unchecked")
+ public void testRebuildOnCommit() throws Exception {
+ SolrQueryRequest req = req("q", "lowerfilt:lucenejavt", "qt", "spellCheckCompRH", "spellcheck", "true");
+ String response = h.query(req);
+ assertFalse("No suggestions should be returned", response.contains("lucenejava"));
+
+ assertU(adoc("id", "11231", "lowerfilt", "lucenejava"));
+ assertU("commit", commit());
+
+ assertQ(req, "//arr[@name='suggestion'][.='lucenejava']");
+ }
+
// TODO: add more tests for various spelling options
}
diff --git a/src/test/test-files/solr/conf/solrconfig.xml b/src/test/test-files/solr/conf/solrconfig.xml
index 723109e5b5a..4b0b94654a8 100644
--- a/src/test/test-files/solr/conf/solrconfig.xml
+++ b/src/test/test-files/solr/conf/solrconfig.xml
@@ -326,6 +326,7 @@
default
lowerfilt
spellchecker1
+ true