Implement 'did you mean' - BloomReach Experience - Open Source CMS

Implement 'did you mean'

By default, Solr support 'did you mean'. For this, you need to configure in the solrconfig.xml a SpellCheckComponent. Assume you want a spellchecker index based on the text solr field.

You then need to configure in your solrconfig.xml :

<searchComponent name="spellcheck" class="solr.SpellCheckComponent">
    <str name="queryAnalyzerFieldType">textSpell</str>

    <!-- Multiple "Spell Checkers" can be declared and used by this
         component
      -->
    <!-- a spellchecker built from a field of the main index, and
         written to disk
      -->
    <lst name="spellchecker">
      <str name="name">default</str>
      <str name="field">text</str>
      <!-- original below -->
      <!--str name="field">name</str-->
      <str name="spellcheckIndexDir">spellchecker</str>
      <!-- uncomment this to require terms to occur in 1% of the
         documents in order to be included in the dictionary
       <float name="thresholdTokenFrequency">.01</float>
      -->

      <str name="comparatorClass">freq</str>
      <str name="buildOnCommit">true</str>
    </lst>
  </searchComponent>

and make sure that the default search requestHandler includes the spellcheck component as last component. For example

  <requestHandler name="search" class="solr.SearchHandler" default="true">
    <!-- default values for query parameters can be specified, these
         will be overridden by parameters in the request
      -->
    <lst name="defaults">
      <str name="echoParams">explicit</str>
      <int name="rows">10</int>
    </lst>

    <!-- ************ ONLY INCLUDE WHEN SPELLCHECKER NEEDED ************ -->
    <!-- assume spellchecker needed: Added by Hippo -->
    <lst name="appends">
      <str name="spellcheck.onlyMorePopular">true</str>
      <str name="spellcheck.extendedResults">false</str>
      <str name="spellcheck.count">100</str>
      <str name="spellcheck.collate">true</str>
    </lst>
    <arr name="last-components">
      <str>spellcheck</str>
    </arr>
</requestHandler>

Note you do not need an extra requestHandler, unless you want to expose the spellcheck component directly below, say, /solr/spell

Now, you have configured the solrconfig, you can use the spellchecker. The spellchecker shows suggestions per term if there are no search results.

In your java class you include spellcheck through:

HippoSolrClient solrClient =
      HstServices.getComponentManager().getComponent(
               HippoSolrClient.class.getName(), "org.hippoecm.hst.solr");
HippoQuery hippoQuery = solrClient.createQuery(query);
hippoQuery.getSolrQuery().add("spellcheck", "true");
// we only want to spellcheck and return the query input field,
// not localParams add such, hence, below set spellcheck.q = query
hippoQuery.getSolrQuery().add("spellcheck.q", query);
hippoQuery.getSolrQuery().add("spellcheck.extendedResults", "true");
hippoQuery.getSolrQuery().add("spellcheck.collateExtendedResults", "true");
HippoQueryResult result = hippoQuery.execute();
request.setAttribute("result", result);

Now, when there are no search hits because of typos, eg "hiippo wordl dominaton", you can show the suggestions through for example the following JSP snippet:

<c:choose>
  <c:when test="${requestScope.result.size > 0}">
    ....
  </c:when>
  <c:otherwise>
    <p></p>
    <p>No results for <b>${requestScope.query}</b>.</p>
    <c:if test="${requestScope.result.queryResponse.spellCheckResponse != null}">
      Did you mean '<b>
          ${requestScope.result.queryResponse.spellCheckResponse.collatedResult}</b>' ?
      <br/><br/>
      Corrections: <br/>
      <div>
        <c:forEach var="collation"
           items=
              "${requestScope.result.queryResponse.spellCheckResponse.collatedResults}" >
          <c:forEach var="correction"
             items="${collation.misspellingsAndCorrections}">
            <i>${correction.original}</i> --> <b>
                                   ${correction.correction}</b><br/>
          </c:forEach>
        </c:forEach>
      </div>

      <br/><br/>
      <p>
        Or did you mean one of these below? <br/>
        <div>
          <c:forEach var="suggestion"
                     items=
                  "${requestScope.result.queryResponse.spellCheckResponse.suggestions}">
            <i>${suggestion.token}</i><br/>
            <c:forEach var="alternative" items="${suggestion.alternatives}"
                                         varStatus="counter">
              <c:if test="${counter.index < 7}">
                &nbsp;&nbsp;&nbsp;${alternative}<br/>
              </c:if>
            </c:forEach>
          </c:forEach>
        </div>
      </p>
    </c:if>
  </c:otherwise>
Did you find this page helpful?
How could this documentation serve you better?
On this page
    Did you find this page helpful?
    How could this documentation serve you better?