SOLR-648: SpellCheckComponent throws NullPointerException on using spellcheck.q request parameter after restarting Solr, if reload is called but build is not called.

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@679816 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Shalin Shekhar Mangar 2008-07-25 14:28:39 +00:00
parent feb5d94cab
commit 22cd8ef46f
9 changed files with 81 additions and 45 deletions

View File

@ -486,6 +486,10 @@ Bug Fixes
42. SOLR-616: SpellChecker accuracy configuration is not applied for FileBasedSpellChecker.
Apply it for FileBasedSpellChecker and IndexBasedSpellChecker both.
(shalin)
43. SOLR-648: SpellCheckComponent throws NullPointerException on using spellcheck.q request
parameter after restarting Solr, if reload is called but build is not called.
(Jonathan Lee, shalin)
Other Changes
1. SOLR-135: Moved common classes to org.apache.solr.common and altered the

View File

@ -246,7 +246,7 @@ public class SpellCheckComponent extends SearchComponent implements SolrCoreAwar
SolrResourceLoader loader = core.getResourceLoader();
SolrSpellChecker checker = (SolrSpellChecker) loader.newInstance(className);
if (checker != null) {
String dictionary = checker.init(spellchecker, loader);
String dictionary = checker.init(spellchecker, core);
if (dictionary != null) {
boolean isDefault = dictionary.equals(SolrSpellChecker.DEFAULT_DICTIONARY_NAME);
if (isDefault == true && hasDefault == false){

View File

@ -5,8 +5,10 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import org.apache.lucene.analysis.Token;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.spell.Dictionary;
@ -17,7 +19,8 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.RAMDirectory;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.core.SolrCore;
import org.apache.solr.schema.FieldType;
/**
@ -30,12 +33,16 @@ import org.apache.solr.core.SolrResourceLoader;
* @since solr 1.3
*/
public abstract class AbstractLuceneSpellChecker extends SolrSpellChecker {
public static final Logger LOG = Logger.getLogger(AbstractLuceneSpellChecker.class.getName());
public static final String SPELLCHECKER_ARG_NAME = "spellchecker";
public static final String LOCATION = "sourceLocation";
public static final String INDEX_DIR = "spellcheckIndexDir";
public static final String ACCURACY = "accuracy";
public static final String STRING_DISTANCE = "distanceMeasure";
public static final String FIELD_TYPE = "fieldType";
protected String field;
protected String fieldTypeName;
protected org.apache.lucene.search.spell.SpellChecker spellChecker;
protected String sourceLocation;
@ -50,14 +57,14 @@ public abstract class AbstractLuceneSpellChecker extends SolrSpellChecker {
protected float accuracy = 0.5f;
public static final String FIELD = "field";
public String init(NamedList config, SolrResourceLoader loader) {
super.init(config, loader);
public String init(NamedList config, SolrCore core) {
super.init(config, core);
indexDir = (String) config.get(INDEX_DIR);
String accuracy = (String) config.get(ACCURACY);
//If indexDir is relative then create index inside core.getDataDir()
if (indexDir != null) {
if (!new File(indexDir).isAbsolute()) {
indexDir = loader.getDataDir() + File.separator + indexDir;
indexDir = core.getDataDir() + File.separator + indexDir;
}
}
sourceLocation = (String) config.get(LOCATION);
@ -65,7 +72,7 @@ public abstract class AbstractLuceneSpellChecker extends SolrSpellChecker {
String strDistanceName = (String)config.get(STRING_DISTANCE);
StringDistance sd = null;
if (strDistanceName != null) {
sd = (StringDistance) loader.newInstance(strDistanceName);
sd = (StringDistance) core.getResourceLoader().newInstance(strDistanceName);
//TODO: Figure out how to configure options. Where's Spring when you need it? Or at least BeanUtils...
} else {
sd = new LevensteinDistance();
@ -85,6 +92,18 @@ public abstract class AbstractLuceneSpellChecker extends SolrSpellChecker {
"Unparseable accuracy given for dictionary: " + name, e);
}
}
if (field != null && core.getSchema().getFieldTypeNoEx(field) != null) {
analyzer = core.getSchema().getFieldType(field).getQueryAnalyzer();
}
fieldTypeName = (String) config.get(FIELD_TYPE);
if (core.getSchema().getFieldTypes().containsKey(fieldTypeName)) {
FieldType fieldType = core.getSchema().getFieldTypes().get(fieldTypeName);
analyzer = fieldType.getQueryAnalyzer();
}
if (analyzer == null) {
LOG.info("Using WhitespaceAnalzyer for dictionary: " + name);
analyzer = new WhitespaceAnalyzer();
}
return name;
}
@ -132,14 +151,11 @@ public abstract class AbstractLuceneSpellChecker extends SolrSpellChecker {
return reader;
}
public void reload() throws IOException {
spellChecker.setSpellIndex(index);
}
/**
* Initialize the {@link #index} variable based on the {@link #indexDir}. Does not actually create the spelling index.
*

View File

@ -38,7 +38,6 @@ import org.apache.solr.schema.IndexSchema;
import org.apache.solr.util.HighFrequencyDictionary;
import org.apache.solr.search.SolrIndexSearcher;
/**
* <p>
* A spell checker implementation which can load words from a text
@ -51,17 +50,13 @@ public class FileBasedSpellChecker extends AbstractLuceneSpellChecker {
private static final Logger log = Logger.getLogger(FileBasedSpellChecker.class.getName());
public static final String FIELD_TYPE = "fieldType";
public static final String SOURCE_FILE_CHAR_ENCODING = "characterEncoding";
private String fieldTypeName;
private String characterEncoding;
public static final String WORD_FIELD_NAME = "word";
public String init(NamedList config, SolrResourceLoader loader) {
super.init(config, loader);
fieldTypeName = (String) config.get(FIELD_TYPE);
public String init(NamedList config, SolrCore core) {
super.init(config, core);
characterEncoding = (String) config.get(SOURCE_FILE_CHAR_ENCODING);
return name;
}
@ -113,12 +108,7 @@ public class FileBasedSpellChecker extends AbstractLuceneSpellChecker {
dictionary = new HighFrequencyDictionary(IndexReader.open(ramDir),
WORD_FIELD_NAME, 0.0f);
analyzer = fieldType.getQueryAnalyzer();
} else {
log.warning("No fieldType: " + fieldTypeName
+ " found for dictionary: " + name + ". Using WhitespaceAnalzyer.");
analyzer = new WhitespaceAnalyzer();
// check if character encoding is defined
if (characterEncoding == null) {
dictionary = new PlainTextDictionary(loader.openResource(sourceLocation));

View File

@ -50,8 +50,8 @@ public class IndexBasedSpellChecker extends AbstractLuceneSpellChecker {
protected float threshold;
protected IndexReader reader;
public String init(NamedList config, SolrResourceLoader loader) {
super.init(config, loader);
public String init(NamedList config, SolrCore core) {
super.init(config, core);
threshold = config.get(THRESHOLD_TOKEN_FREQUENCY) == null ? 0.0f
: (Float) config.get(THRESHOLD_TOKEN_FREQUENCY);
initSourceReader();
@ -80,8 +80,9 @@ public class IndexBasedSpellChecker extends AbstractLuceneSpellChecker {
reader = this.reader;
}
loadLuceneDictionary(core.getSchema(), reader);
// Create the dictionary
dictionary = new HighFrequencyDictionary(reader, field,
threshold);
spellChecker.clearIndex();
spellChecker.indexDictionary(dictionary);
@ -101,17 +102,6 @@ public class IndexBasedSpellChecker extends AbstractLuceneSpellChecker {
return result;
}
@SuppressWarnings("unchecked")
private void loadLuceneDictionary(IndexSchema schema, IndexReader reader) {
// Create the dictionary
dictionary = new HighFrequencyDictionary(reader, field,
threshold);
// Get the field's analyzer
FieldType fieldType = schema.getFieldTypeNoEx(field);
analyzer = fieldType == null ? new WhitespaceAnalyzer()
: fieldType.getQueryAnalyzer();
}
@Override
public void reload() throws IOException {
super.reload();

View File

@ -21,7 +21,6 @@ import org.apache.lucene.analysis.Token;
import org.apache.lucene.index.IndexReader;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.search.SolrIndexSearcher;
import java.io.IOException;
@ -41,7 +40,7 @@ public abstract class SolrSpellChecker {
protected String name;
protected Analyzer analyzer;
public String init(NamedList config, SolrResourceLoader loader){
public String init(NamedList config, SolrCore core){
name = (String) config.get(DICTIONARY_NAME);
if (name == null) {
name = DEFAULT_DICTIONARY_NAME;

View File

@ -18,6 +18,7 @@
package org.apache.solr.handler.component;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@ -32,6 +33,7 @@ import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.spelling.AbstractLuceneSpellChecker;
import org.apache.solr.spelling.IndexBasedSpellChecker;
import org.apache.solr.util.AbstractSolrTestCase;
@ -311,6 +313,41 @@ public class SpellCheckComponentTest extends AbstractSolrTestCase {
"spellcheckerIndexDir was not created inside the configured value for dataDir folder as configured in solrconfig.xml",
indexDir.exists());
}
public void testReloadOnStart() throws Exception {
assertU(adoc("id", "0", "lowerfilt", "This is a title"));
assertU(commit());
SolrQueryRequest request = req("qt", "spellCheckCompRH", "q", "*:*",
"spellcheck.q", "ttle", "spellcheck", "true", "spellcheck.dictionary",
"default", "spellcheck.build", "true");
assertQ(request, "//arr[@name='suggestion'][.='title']");
NamedList args = new NamedList();
NamedList spellchecker = new NamedList();
spellchecker.add(AbstractLuceneSpellChecker.DICTIONARY_NAME, "default");
spellchecker.add(AbstractLuceneSpellChecker.FIELD, "lowerfilt");
spellchecker.add(AbstractLuceneSpellChecker.INDEX_DIR, "spellchecker1");
args.add("spellchecker", spellchecker);
SpellCheckComponent checker = new SpellCheckComponent();
checker.init(args);
checker.inform(h.getCore());
request = req("qt", "spellCheckCompRH", "q", "*:*", "spellcheck.q", "ttle",
"spellcheck", "true", "spellcheck.dictionary", "default",
"spellcheck.reload", "true");
ResponseBuilder rb = new ResponseBuilder();
rb.req = request;
rb.rsp = new SolrQueryResponse();
rb.components = new ArrayList(h.getCore().getSearchComponents().values());
checker.prepare(rb);
try {
checker.process(rb);
} catch (NullPointerException e) {
fail("NullPointerException due to reload not initializing analyzers");
}
}
// TODO: add more tests for various spelling options

View File

@ -70,7 +70,7 @@ public class FileBasedSpellCheckerTest extends AbstractSolrTestCase{
indexDir.mkdirs();
spellchecker.add(FileBasedSpellChecker.INDEX_DIR, indexDir.getAbsolutePath());
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + "external", dictName.equals("external") == true);
checker.build(core, null);
@ -108,7 +108,7 @@ public class FileBasedSpellCheckerTest extends AbstractSolrTestCase{
spellchecker.add(FileBasedSpellChecker.FIELD_TYPE, "teststop");
spellchecker.add(AbstractLuceneSpellChecker.SPELLCHECKER_ARG_NAME, spellchecker);
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + "external", dictName.equals("external") == true);
checker.build(core, null);
@ -149,7 +149,7 @@ public class FileBasedSpellCheckerTest extends AbstractSolrTestCase{
spellchecker.add(AbstractLuceneSpellChecker.SPELLCHECKER_ARG_NAME, spellchecker);
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + "external", dictName.equals("external") == true);
checker.build(core, null);

View File

@ -89,7 +89,7 @@ public class IndexBasedSpellCheckerTest extends AbstractSolrTestCase {
spellchecker.add(AbstractLuceneSpellChecker.SPELLCHECKER_ARG_NAME, spellchecker);
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + SolrSpellChecker.DEFAULT_DICTIONARY_NAME,
dictName.equals(SolrSpellChecker.DEFAULT_DICTIONARY_NAME) == true);
RefCounted<SolrIndexSearcher> holder = core.getSearcher();
@ -162,7 +162,7 @@ public class IndexBasedSpellCheckerTest extends AbstractSolrTestCase {
spellchecker.add(IndexBasedSpellChecker.FIELD, "title");
spellchecker.add(AbstractLuceneSpellChecker.SPELLCHECKER_ARG_NAME, spellchecker);
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + SolrSpellChecker.DEFAULT_DICTIONARY_NAME,
dictName.equals(SolrSpellChecker.DEFAULT_DICTIONARY_NAME) == true);
RefCounted<SolrIndexSearcher> holder = core.getSearcher();
@ -218,7 +218,7 @@ public class IndexBasedSpellCheckerTest extends AbstractSolrTestCase {
spellchecker.add(AbstractLuceneSpellChecker.SPELLCHECKER_ARG_NAME, spellchecker);
spellchecker.add(AbstractLuceneSpellChecker.STRING_DISTANCE, JaroWinklerDistance.class.getName());
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + SolrSpellChecker.DEFAULT_DICTIONARY_NAME,
dictName.equals(SolrSpellChecker.DEFAULT_DICTIONARY_NAME) == true);
RefCounted<SolrIndexSearcher> holder = core.getSearcher();
@ -268,7 +268,7 @@ public class IndexBasedSpellCheckerTest extends AbstractSolrTestCase {
spellchecker.add(IndexBasedSpellChecker.FIELD, "title");
spellchecker.add(AbstractLuceneSpellChecker.SPELLCHECKER_ARG_NAME, spellchecker);
SolrCore core = h.getCore();
String dictName = checker.init(spellchecker, core.getResourceLoader());
String dictName = checker.init(spellchecker, core);
assertTrue(dictName + " is not equal to " + SolrSpellChecker.DEFAULT_DICTIONARY_NAME,
dictName.equals(SolrSpellChecker.DEFAULT_DICTIONARY_NAME) == true);
RefCounted<SolrIndexSearcher> holder = core.getSearcher();