SOLR-622: SpellCheckComponent supports auto-loading indices on startup and optionally, (re)builds indices on newSearcher event, if configured in solrconfig.xml

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@681604 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Shalin Shekhar Mangar 2008-08-01 06:11:58 +00:00
parent 258cb3e84d
commit 68083b3af4
4 changed files with 87 additions and 17 deletions

View File

@ -336,6 +336,10 @@ New Features
data sources, processors and transformers for importing data. Supports full data imports as well as 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. incremental (delta) indexing. See http://wiki.apache.org/solr/DataImportHandler for more details.
(Noble Paul, shalin) (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 Changes in runtime behavior
1. SOLR-559: use Lucene updateDocument, deleteDocuments methods. This 1. SOLR-559: use Lucene updateDocument, deleteDocuments methods. This

View File

@ -17,10 +17,24 @@
package org.apache.solr.handler.component; package org.apache.solr.handler.component;
import org.apache.lucene.analysis.Token; import java.io.IOException;
import org.apache.lucene.analysis.WhitespaceAnalyzer; 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.Analyzer;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams; 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.common.util.SimpleOrderedMap;
import org.apache.solr.core.SolrConfig; import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore; import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrEventListener;
import org.apache.solr.core.SolrResourceLoader; import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.schema.FieldType; import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema; 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.IndexBasedSpellChecker;
import org.apache.solr.spelling.QueryConverter;
import org.apache.solr.spelling.SolrSpellChecker; import org.apache.solr.spelling.SolrSpellChecker;
import org.apache.solr.spelling.SpellingResult; 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.NamedListPluginLoader;
import org.apache.solr.util.plugin.SolrCoreAware; import org.apache.solr.util.plugin.SolrCoreAware;
import org.w3c.dom.NodeList; 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 * A SearchComponent implementation which provides support for spell checking
* and suggestions using the Lucene contributed SpellChecker. * 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."); 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 { } else {
throw new RuntimeException("Can't load spell checker: " + className); 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 // / SolrInfoMBean
// ////////////////////////////////////////// // //////////////////////////////////////////

View File

@ -67,7 +67,7 @@ public class SpellCheckComponentTest extends AbstractSolrTestCase {
assertU(adoc("id", "8", "lowerfilt", "blee")); assertU(adoc("id", "8", "lowerfilt", "blee"));
assertU("commit", commit()); assertU("commit", commit());
} }
public void testExtendedResultsCount() throws Exception { public void testExtendedResultsCount() throws Exception {
SolrCore core = h.getCore(); SolrCore core = h.getCore();
SearchComponent speller = core.getSearchComponent("spellcheck"); SearchComponent speller = core.getSearchComponent("spellcheck");
@ -348,7 +348,19 @@ public class SpellCheckComponentTest extends AbstractSolrTestCase {
fail("NullPointerException due to reload not initializing analyzers"); 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 // TODO: add more tests for various spelling options
} }

View File

@ -326,6 +326,7 @@
<str name="name">default</str> <str name="name">default</str>
<str name="field">lowerfilt</str> <str name="field">lowerfilt</str>
<str name="spellcheckIndexDir">spellchecker1</str> <str name="spellcheckIndexDir">spellchecker1</str>
<str name="buildOnCommit">true</str>
</lst> </lst>
<!-- Example of using different distance measure --> <!-- Example of using different distance measure -->
<lst name="spellchecker"> <lst name="spellchecker">