/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.solr.handler.component; import java.io.File; import java.util.*; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SpellingParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.SolrCore; import org.apache.solr.request.LocalSolrQueryRequest; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.spelling.AbstractLuceneSpellChecker; import org.apache.solr.spelling.IndexBasedSpellChecker; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; /** * @since solr 1.3 */ public class SpellCheckComponentTest extends SolrTestCaseJ4 { @BeforeClass public static void beforeClass() throws Exception { initCore("solrconfig.xml","schema.xml"); assertNull(h.validateUpdate(adoc("id", "0", "lowerfilt", "This is a title"))); assertNull(h.validateUpdate(adoc("id", "1", "lowerfilt", "The quick reb fox jumped over the lazy brown dogs."))); assertNull(h.validateUpdate(adoc("id", "2", "lowerfilt", "This is a document"))); assertNull(h.validateUpdate(adoc("id", "3", "lowerfilt", "another document"))); //bunch of docs that are variants on blue assertNull(h.validateUpdate(adoc("id", "4", "lowerfilt", "blue"))); assertNull(h.validateUpdate(adoc("id", "5", "lowerfilt", "blud"))); assertNull(h.validateUpdate(adoc("id", "6", "lowerfilt", "boue"))); assertNull(h.validateUpdate(adoc("id", "7", "lowerfilt", "glue"))); assertNull(h.validateUpdate(adoc("id", "8", "lowerfilt", "blee"))); assertNull(h.validateUpdate(adoc("id", "9", "lowerfilt", "pixmaa"))); assertNull(h.validateUpdate(commit())); } @Test public void testExtendedResultsCount() throws Exception { SolrCore core = h.getCore(); SearchComponent speller = core.getSearchComponent("spellcheck"); assertTrue("speller is null and it shouldn't be", speller != null); ModifiableSolrParams params = new ModifiableSolrParams(); params.add(CommonParams.QT, "spellCheckCompRH"); params.add(SpellCheckComponent.SPELLCHECK_BUILD, "true"); params.add(CommonParams.Q, "bluo"); params.add(SpellCheckComponent.COMPONENT_NAME, "true"); params.add(SpellCheckComponent.SPELLCHECK_COUNT, String.valueOf(5)); params.add(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS, String.valueOf(false)); SolrRequestHandler handler = core.getRequestHandler("spellCheckCompRH"); SolrQueryResponse rsp; rsp = new SolrQueryResponse(); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); NamedList values = rsp.getValues(); String cmdExec = (String) values.get("command"); assertEquals("build",cmdExec); NamedList spellCheck = (NamedList) values.get("spellcheck"); NamedList suggestions = (NamedList) spellCheck.get("suggestions"); NamedList blue = (NamedList) suggestions.get("bluo"); assertEquals(5,blue.get("numFound")); Collection<String> theSuggestion = (Collection<String>) blue.get("suggestion"); assertEquals(5,theSuggestion.size()); //we know there are at least 5, but now only get 3 params.remove(SpellCheckComponent.SPELLCHECK_COUNT); params.remove(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS); params.remove(SpellCheckComponent.SPELLCHECK_BUILD); params.add(SpellCheckComponent.SPELLCHECK_COUNT, "3"); params.add(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS, String.valueOf(true)); params.add(SpellCheckComponent.SPELLCHECK_BUILD, "false"); rsp = new SolrQueryResponse(); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); values = rsp.getValues(); spellCheck = (NamedList) values.get("spellcheck"); suggestions = (NamedList) spellCheck.get("suggestions"); blue = (NamedList) suggestions.get("bluo"); assertEquals(3, blue.get("numFound")); List<SimpleOrderedMap> theSuggestions = (List<SimpleOrderedMap>)blue.get("suggestion"); assertEquals(3, theSuggestions.size()); for (SimpleOrderedMap sug : theSuggestions) { assertNotNull(sug.get("word")); assertNotNull(sug.get("freq")); } } @Test public void test() throws Exception { SolrCore core = h.getCore(); SearchComponent speller = core.getSearchComponent("spellcheck"); assertTrue("speller is null and it shouldn't be", speller != null); ModifiableSolrParams params = new ModifiableSolrParams(); params.add(CommonParams.QT, "spellCheckCompRH"); params.add(SpellCheckComponent.SPELLCHECK_BUILD, "true"); params.add(CommonParams.Q, "documemt"); params.add(SpellCheckComponent.COMPONENT_NAME, "true"); SolrRequestHandler handler = core.getRequestHandler("spellCheckCompRH"); SolrQueryResponse rsp = new SolrQueryResponse(); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); NamedList values = rsp.getValues(); String cmdExec = (String) values.get("command"); assertTrue("command is null and it shouldn't be", cmdExec != null); assertTrue(cmdExec + " is not equal to " + "build", cmdExec.equals("build") == true); NamedList spellCheck = (NamedList) values.get("spellcheck"); assertNotNull(spellCheck); NamedList suggestions = (NamedList) spellCheck.get("suggestions"); assertNotNull(suggestions); NamedList document = (NamedList) suggestions.get("documemt"); assertEquals(1, document.get("numFound")); assertEquals(0, document.get("startOffset")); assertEquals(document.get("endOffset"), "documemt".length()); Collection<String> theSuggestion = (Collection<String>) document.get("suggestion"); assertEquals(1, theSuggestion.size()); assertEquals("document", theSuggestion.iterator().next()); } @Test public void testPerDictionary() throws Exception { SolrCore core = h.getCore(); SearchComponent speller = core.getSearchComponent("spellcheck"); assertTrue("speller is null and it shouldn't be", speller != null); ModifiableSolrParams params = new ModifiableSolrParams(); params.add(CommonParams.QT, "spellCheckCompRH"); params.add(SpellCheckComponent.SPELLCHECK_BUILD, "true"); params.add(CommonParams.Q, "documemt"); params.add(SpellCheckComponent.COMPONENT_NAME, "true"); params.add(SpellingParams.SPELLCHECK_DICT, "perDict"); params.add(SpellingParams.SPELLCHECK_PREFIX + ".perDict.foo", "bar"); params.add(SpellingParams.SPELLCHECK_PREFIX + ".perDict.bar", "foo"); SolrRequestHandler handler = core.getRequestHandler("spellCheckCompRH"); SolrQueryResponse rsp = new SolrQueryResponse(); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); NamedList values = rsp.getValues(); NamedList spellCheck = (NamedList) values.get("spellcheck"); NamedList suggestions = (NamedList) spellCheck.get("suggestions"); assertNotNull("suggestions", suggestions); NamedList suggestion; Collection<String> theSuggestion; suggestion = (NamedList) suggestions.get("foo"); assertEquals(1, suggestion.get("numFound")); assertEquals(0, suggestion.get("startOffset")); assertEquals(suggestion.get("endOffset"), 1); theSuggestion = (Collection<String>) suggestion.get("suggestion"); assertEquals(1, theSuggestion.size()); assertEquals("bar", theSuggestion.iterator().next()); suggestion = (NamedList) suggestions.get("bar"); assertEquals(1, suggestion.get("numFound")); assertEquals(2, suggestion.get("startOffset")); assertEquals(3, suggestion.get("endOffset")); theSuggestion = (Collection<String>) suggestion.get("suggestion"); assertEquals(1, theSuggestion.size()); assertEquals("foo", theSuggestion.iterator().next()); } @Test public void testCollate() throws Exception { SolrCore core = h.getCore(); SearchComponent speller = core.getSearchComponent("spellcheck"); assertTrue("speller is null and it shouldn't be", speller != null); ModifiableSolrParams params = new ModifiableSolrParams(); params.add(CommonParams.QT, "spellCheckCompRH"); params.add(SpellCheckComponent.SPELLCHECK_BUILD, "true"); params.add(CommonParams.Q, "documemt"); params.add(SpellCheckComponent.COMPONENT_NAME, "true"); params.add(SpellCheckComponent.SPELLCHECK_COLLATE, "true"); SolrRequestHandler handler = core.getRequestHandler("spellCheckCompRH"); SolrQueryResponse rsp = new SolrQueryResponse(); rsp.add("responseHeader", new SimpleOrderedMap()); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); NamedList values = rsp.getValues(); NamedList spellCheck = (NamedList) values.get("spellcheck"); NamedList suggestions = (NamedList) spellCheck.get("suggestions"); String collation = (String) suggestions.get("collation"); assertEquals("document", collation); params.remove(CommonParams.Q); params.add(CommonParams.Q, "documemt lowerfilt:broen^4"); handler = core.getRequestHandler("spellCheckCompRH"); rsp = new SolrQueryResponse(); rsp.add("responseHeader", new SimpleOrderedMap()); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); values = rsp.getValues(); spellCheck = (NamedList) values.get("spellcheck"); suggestions = (NamedList) spellCheck.get("suggestions"); collation = (String) suggestions.get("collation"); assertEquals("document lowerfilt:brown^4", collation); params.remove(CommonParams.Q); params.add(CommonParams.Q, "documemtsss broens"); handler = core.getRequestHandler("spellCheckCompRH"); rsp = new SolrQueryResponse(); rsp.add("responseHeader", new SimpleOrderedMap()); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); values = rsp.getValues(); spellCheck = (NamedList) values.get("spellcheck"); suggestions = (NamedList) spellCheck.get("suggestions"); collation = (String) suggestions.get("collation"); assertEquals("document brown",collation); } @Test public void testCollate2() throws Exception { SolrCore core = h.getCore(); SearchComponent speller = core.getSearchComponent("spellcheck"); assertTrue("speller is null and it shouldn't be", speller != null); ModifiableSolrParams params = new ModifiableSolrParams(); params.add(CommonParams.QT, "spellCheckCompRH"); params.add(SpellCheckComponent.SPELLCHECK_BUILD, "true"); params.add(CommonParams.Q, "pixma-a-b-c-d-e-f-g"); params.add(SpellCheckComponent.COMPONENT_NAME, "true"); params.add(SpellCheckComponent.SPELLCHECK_COLLATE, "true"); SolrRequestHandler handler = core.getRequestHandler("spellCheckCompRH"); SolrQueryResponse rsp = new SolrQueryResponse(); rsp.add("responseHeader", new SimpleOrderedMap()); handler.handleRequest(new LocalSolrQueryRequest(core, params), rsp); NamedList values = rsp.getValues(); NamedList spellCheck = (NamedList) values.get("spellcheck"); NamedList suggestions = (NamedList) spellCheck.get("suggestions"); String collation = (String) suggestions.get("collation"); assertEquals("pixmaa", collation); } @Test public void testCorrectSpelling() throws Exception { SolrCore core = h.getCore(); Map<String, String> args = new HashMap<String, String>(); args.put(CommonParams.Q, "lowerfilt:lazy lowerfilt:brown"); args.put(CommonParams.QT, "spellCheckCompRH"); args.put(SpellCheckComponent.SPELLCHECK_BUILD, "true"); args.put(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS, "true"); args.put(SpellCheckComponent.COMPONENT_NAME, "true"); SolrQueryRequest req = new LocalSolrQueryRequest(core, new MapSolrParams( args)); assertQ("Make sure correct spellings are signalled in the response", req, "//*[@numFound='1']", "//result/doc[1]/int[@name='id'][.='1']", "//*/lst[@name='suggestions']"); args = new HashMap<String, String>(); args.put(CommonParams.Q, "lakkle"); args.put(CommonParams.QT, "spellCheckCompRH"); args.put(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS, "true"); args.put(SpellCheckComponent.COMPONENT_NAME, "true"); req = new LocalSolrQueryRequest(core, new MapSolrParams( args)); assertQ("Make sure correct spellings are signalled in the response", req, "//*[@numFound='0']", "//*/lst[@name='suggestions']", "//*/bool[@name='correctlySpelled'][.='false']"); args = new HashMap<String, String>(); args.put(CommonParams.Q, "lowerfilt:lazy"); args.put(CommonParams.QT, "spellCheckCompRH"); args.put(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS, "true"); args.put(SpellCheckComponent.COMPONENT_NAME, "true"); req = new LocalSolrQueryRequest(core, new MapSolrParams( args)); assertQ("Make sure correct spellings are signalled in the response", req, "//*[@numFound='1']", "//*/lst[@name='suggestions']", "//*/bool[@name='correctlySpelled'][.='true']"); } @Test public void testInit() throws Exception { SolrCore core = h.getCore(); SpellCheckComponent scc = new SpellCheckComponent(); NamedList args = new NamedList(); NamedList spellchecker = new NamedList(); spellchecker.add("classname", IndexBasedSpellChecker.class.getName()); spellchecker.add("name", "default"); spellchecker.add("field", "lowerfilt"); spellchecker.add("spellcheckIndexDir", "./spellchecker"); args.add("spellchecker", spellchecker); NamedList altSC = new NamedList(); altSC.add("classname", IndexBasedSpellChecker.class.getName()); altSC.add("name", "alternate"); altSC.add("field", "lowerfilt"); altSC.add("spellcheckIndexDir", "./spellchecker"); args.add("spellchecker", altSC); args.add("queryAnalyzerFieldType", "lowerfilt"); NamedList defaults = new NamedList(); defaults.add(SpellCheckComponent.SPELLCHECK_COLLATE, true); defaults.add(SpellCheckComponent.SPELLCHECK_EXTENDED_RESULTS, false); defaults.add(SpellCheckComponent.SPELLCHECK_COUNT, 2); args.add("defaults", defaults); scc.init(args); scc.inform(core); //hmm, not sure what to assert here... //add the sc again and then init again, we should get an exception args.add("spellchecker", spellchecker); scc = new SpellCheckComponent(); scc.init(args); try { scc.inform(core); assertTrue(false); } catch (Exception e) { } } @SuppressWarnings("unchecked") @Test public void testRelativeIndexDirLocation() throws Exception { SolrCore core = h.getCore(); Map<String, String> args = new HashMap<String, String>(); args.put(CommonParams.Q, "test"); args.put(CommonParams.QT, "spellCheckCompRH"); args.put(SpellCheckComponent.SPELLCHECK_BUILD, "true"); args.put(SpellCheckComponent.COMPONENT_NAME, "true"); SolrQueryRequest req = new LocalSolrQueryRequest(core, new MapSolrParams( args)); File indexDir = new File(core.getDataDir() + File.separator + "spellchecker1"); assertTrue( "spellcheckerIndexDir was not created inside the configured value for dataDir folder as configured in solrconfig.xml", indexDir.exists()); indexDir = new File(core.getDataDir() + File.separator + "spellchecker2"); assertTrue( "spellcheckerIndexDir was not created inside the configured value for dataDir folder as configured in solrconfig.xml", indexDir.exists()); indexDir = new File(core.getDataDir() + File.separator + "spellchecker3"); assertTrue( "spellcheckerIndexDir was not created inside the configured value for dataDir folder as configured in solrconfig.xml", indexDir.exists()); } @Test 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"); } } @SuppressWarnings("unchecked") @Test 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 }