'Implement the Customized class for SOLR Spellcheker

We are tryin to extend the current solr.DirectSpellchecker with our own class. The reason to customize is to expand the 'maxEdits' to more than 2 characters.

Below is our implementation config (solrconfig.xml)


<lst name="spellchecker">
    <str name="name">en_US</str>
    <str name="field">spellcheck_en_us</str>
    <!-- <str name="classname">solr.DirectSolrSpellChecker</str>-->
    <str name="classname">com.solr.spelling.CustomDirectSolrSpellChecker</str> 
    <str name="distanceMeasure">internal</str>
    <float name="accuracy">0.5</float>
    <int name="maxEdits">2</int>
    <int name="minPrefix">0</int>
    <int name="maxInspections">8</int>
    <int name="minQueryLength">3</int>
    <float name="maxQueryFrequency">0.0001</float>
    <float name="thresholdTokenFrequency">.0001</float>
    </lst>

we are able to create a Jar file and able to place it in one of the Lib which SOLR can read.

restarted the solr after above steps. Didn't see any issues as the class has been accepted.

Problem

while calling the spellcheck query like below, we are getting NULLPOINTER error

Query

/spell?&spellcheck=true&spellcheck.q=acesaries&spellcheck.dictionary=en_US&spellcheck.collate=true&wt=xml

Error

java.lang.NullPointerException at 
org.apache.solr.handler.component.SpellCheckComponent.getTokens(SpellCheckComponent.java:581) 
at org.apache.solr.handler.component.SpellCheckComponent.process(SpellCheckComponent.java:149) 
at org.apache.solr.handler.component.SearchHandler.handleRequestBody(SearchHandler.java:331) at 
org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:214) 
at org.apache.solr.core.SolrCore.execute(SolrCore.java:2606) at org.apache.solr.servlet.HttpSolrCall.execute(HttpSolrCall.java:815) 
at org.apache.solr.servlet.HttpSolrCall.call(HttpSolrCall.java:588) 
at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:415) 
at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:345) 
at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:201) 
at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1609) 
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:561) 
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) 
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:602) 
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) 
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) 
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1612) 
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) 
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434) 
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) 
t org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501) 
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1582) 
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) 
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349) 
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) 
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:191) 
at org.eclipse.jetty.server.handler.InetAccessHandler.handle(InetAccessHandler.java:177) at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905) at java.base/java.lang.Thread.run(Thread.java:834) 

Unable to initiate Spellcheck Component as per the error and not sure which step we are missing here.

Our Custom changes are below

  1. CustomDirectSolrSpellChecker extends org.apache.solr.spelling.DirectSolrSpellChecker
  2. CustomDirectSpellChecker extends org.apache.lucene.search.spell.DirectSpellChecker
  3. 1st class overriden the init method of DirectSolrSpellChecker and replaced below line
private DirectSpellChecker checker = new DirectSpellChecker();

with new line

private CustomDirectSpellChecker checker = new CustomDirectSpellChecker();
  1. CustomDirectSpellChecker overriden the 'setMaxEdits' method to allow more than 2 edits.

solr logs

o.a.s.h.c.SpellCheckComponent Loading spell index for spellchecker: null
o.a.s.h.c.SpellCheckComponent Loading spell index for spellchecker: null

Update(03/12/2022)

Tried other way to Override the out of the box class rather than extending it. So I took the jar's lucene-core-8.6.3.jar, lucene-suggest-8.6.3.jar and updated the below classes with new code (only one liner change where updating maxEdits to 4 from 2)

  1. DirectSpellChecker.java
  2. FuzzyAutomatonBuilder.java
  3. FuzzyQuery.java

After updating the existing jars and replacing them with above new class files, I got the below error

java.lang.NullPointerException at org.apache.lucene.util.automaton.CompiledAutomaton.<init>(CompiledAutomaton.java:154) 
at org.apache.lucene.util.automaton.CompiledAutomaton.<init>(CompiledAutomaton.java:140) 
at org.apache.lucene.search.FuzzyAutomatonBuilder.buildAutomatonSet(FuzzyAutomationBuilder.java:41) 
at org.apache.lucene.search.FuzzyTermsEnum$AutomatonAttributeImpl.init(FuzzyTermsEnum.java:365) 
at org.apache.lucene.search.FuzzyTermsEnum.<init>(FuzzyTermsEnum.java:125) 
at org.apache.lucene.search.FuzzyTermsEnum.<init>(FuzzyTermsEnum.java:92) at org.apache.lucene.search.spell.DirectSpellChecker.suggestSimilar(DirectSpellChecker.java:208) 
at org.apache.lucene.search.spell.DirectSpellChecker.suggestSimilar(DirectSpellChecker.java:179) 
at org.apache.solr.spelling.DirectSolrSpellChecker.getSuggestions(DirectSolrSpellChecker.java:197)
 at org.apache.solr.handler.component.SpellCheckComponent.process(SpellCheckComponent.java:194)
 at org.apache.solr.handler.component.SearchHandler.handleRequestBody(SearchHandler.java:331) 
at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:214) 
at org.apache.solr.core.SolrCore.execute(SolrCore.java:2606) 
at org.apache.solr.servlet.HttpSolrCall.execute(HttpSolrCall.java:815) at org.apache.solr.servlet.HttpSolrCall.call(HttpSolrCall.java:588) at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:415) at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:345) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:201) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1609) at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:561) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:602) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235) at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1612) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1434) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188) at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501) at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1582) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1349) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:191) at org.eclipse.jetty.server.handler.InetAccessHandler.handle(InetAccessHandler.java:177) at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127) at org.eclipse.jetty.server.Server.handle(Server.java:516) at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383) at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105) at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:135) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:773) at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:905) at java.base/java.lang.Thread.run(Thread.java:834)

If i give maxEdits as 2 in the solrconfig.xml, everything working and the above error is coming when i change it to more than 2.

Can some one please help on this.

Any help on making this execute will be great help. we are using solr 8.6

Thanks In advance.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source