How to get the suggester component working in Solr

2020-02-26 01:43发布

问题:

I have configured my solrconfig.xml and schema.xml to query for the suggestions.

I am able to get the suggestions from the url

http://localhost:8080/solr/collection1/suggest?q=ha&wt=xml

My SolrConfig.xml looks like

Curently, My solr query looks like

<fields>
    <!-- declare fields of entity class -->
    <!-- type will specify the table name -->
    <field name="type" type="string" indexed="true" stored="true"  />

    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
    <field name="name" type="text_general" indexed="true" stored="true" omitNorms="true"/>

    <field name="text" type="text_general" indexed="true" stored="false" multiValued="true"/>
    <field name="_version_" type="long" indexed="true" stored="true"/>

    <!-- unique field -->
    <field name="uid" type="uuid" indexed="true" stored="true" />

  </fields>

  <uniqueKey>uid</uniqueKey>

  <copyField source="name" dest="text"/>

  <types>
    <fieldType name="uuid" class="solr.UUIDField" indexed="true" />
    <fieldType name="string" class="solr.StrField" sortMissingLast="true" />
    <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>

    <fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
    .....
    </types>

And my schema.xml looks like this

<searchComponent name="suggest" class="solr.SpellCheckComponent">
    <!-- a spellchecker built from a field of the main index -->
    <lst name="spellchecker">
      <str name="name">suggest</str>
      <str name="field">name</str>
      <str name="classname">org.apache.solr.spelling.suggest.Suggester</str>
      <str name="lookupImpl">org.apache.solr.spelling.suggest.tst.TSTLookup</str>
      <str name="buildOnCommit">true</str>          
      <str name="distanceMeasure">internal</str>
      <float name="accuracy">0.5</float>
      <int name="maxEdits">2</int>
      int name="minPrefix">1</int>
      <int name="maxInspections">5</int>
      <int name="minQueryLength">4</int>
      <float name="maxQueryFrequency">0.01</float>
       <float name="thresholdTokenFrequency">.01</float>      
    </lst>

    <!-- a spellchecker that can break or combine words.  See "/spell" handler below for usage -->
    <lst name="spellchecker">
      <str name="name">wordbreak</str>
      <str name="classname">solr.WordBreakSolrSpellChecker</str>
      <str name="field">name</str>
      <str name="combineWords">true</str>
      <str name="breakWords">true</str>
      <int name="maxChanges">10</int>
    </lst>
</searchComponent>

<requestHandler name="/suggest" class="solr.SearchHandler" startup="lazy">
    <lst name="defaults">
      <str name="df">text</str>
      <!-- Solr will use suggestions from both the 'default' spellchecker
           and from the 'wordbreak' spellchecker and combine them.
           collations (re-written queries) can include a combination of
           corrections from both spellcheckers -->
      <str name="spellcheck">true</str>
      <str name="spellcheck.dictionary">suggest</str>
      <!--<str name="spellcheck.dictionary">wordbreak</str>-->
      <str name="spellcheck">on</str>
      <str name="spellcheck.extendedResults">true</str>       
      <str name="spellcheck.count">10</str>
      <str name="spellcheck.alternativeTermCount">5</str>
      <str name="spellcheck.maxResultsForSuggest">5</str>       
      <str name="spellcheck.collate">true</str>
      <str name="spellcheck.collateExtendedResults">true</str>  
      <str name="spellcheck.maxCollationTries">10</str>
      <str name="spellcheck.maxCollations">5</str>         
    </lst>
    <arr name="last-components">
      <str>spellcheck</str>
    </arr>
  </requestHandler>

My code to call the SolrNet API looks as below

new SolrBaseRepository.Instance<T>().Start();
        var solr = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
        var options = new QueryOptions
        {
            FilterQueries = new ISolrQuery[] { new SolrQueryByField("type", type) }
        };
        var results = solr.Query(keyword, options);
        return results;

However, I am not getting any data. results count is zero. And also the spellcheck in the results is also zero.

I also dont see the suggestion list inside the results.

Please help

回答1:

I had the exact same requirement but could not find any way to easily handle Suggester results with SolrNet. Unfortunately, SolrNet seems to be built around the default /select request handler and does not currently support any other handler including /suggest for object type mappings (T). It expects all mappings to occur with indexed Solr document results and not suggester results.

Hence, @Paige Cook's answer did not work for me. T type with mappings is not compatible with a suggester results response. All the standard plumbing code from initializing the request (Startup.Init<T>()) to querying (ISolrQueryResults<T> results = solr.Query()) needs a mapped Solr document type and not a simple array of strings which the suggester provides.

Therefore, (similar to @dfay) I went with making a web request and parsing out the suggested results from the XML web response. The SolrConnection class was used for this:

string searchTerm = "ha";
string solrUrl = "http://localhost:8080/solr/collection1";
string relativeUrl = "/suggest";
var parameters = new Dictionary<string, string>
                {
                    {"q", searchTerm},
                    {"wt", "xml"},
                };

var solrConnection = new SolrConnection(solrUrl);
string response = solrConnection.Get(relativeUrl, parameters);
// then use your favorite XML parser to extract 
// suggestions from the reponse string

Alternatively, instead of XML, the request can return a JSON response using the wt=json parameter:

var parameters = new Dictionary<string, string>
                {
                    {"q", searchTerm},
                    {"wt", "json"}, // change this!
                };
// then use your favorite JSON parser


回答2:

In order to execute your query against the /suggest request handler that you have setup, you will need to set the qt Solr parameter using the ExtraParameters in your SolrNet QueryOptions like below:

 new SolrBaseRepository.Instance<T>().Start();
 var solr = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
 var options = new QueryOptions
 {
     FilterQueries = new ISolrQuery[] { new SolrQueryByField("type", type) },
     ExtraParams = new Dictionary<string, string>{{"qt", "suggest"}},
 };
 var results = solr.Query(keyword, options);
 return results;

Otherwise your query is still executing against the standard /select request handler (or whatever you have defined as the default in your solrconfig.xml).



回答3:

See http://wiki.apache.org/solr/SolrRequestHandler, particularly the section on the old handleSelect=true behavior. If you are running against a newer Solr server, this is most likely your problem. (i.e. setting "qt" has no effect and either the default handler in SolrNet must be changed or the Solr config needs to set handleSelect=true.) Here's how I solved this problem in my case:

ISolrConnection connection = ServiceLocator.Current.GetInstance<ISolrConnection>();
List<KeyValuePair<string, string>> termsParams = new List<KeyValuePair<string, string>>();
termsParams.Add(new KeyValuePair<string, string>("terms.fl", "name"));
termsParams.Add(new KeyValuePair<string, string>("terms.prefix", mySearchString));
termsParams.Add(new KeyValuePair<string, string>("terms.sort", "count"));
string xml = connection.Get("/terms", termsParams);

ISolrAbstractResponseParser<Document> parser = ServiceLocator.Current.GetInstance<ISolrAbstractResponseParser<Document>>();
SolrQueryResults<Document> results = new SolrQueryResults<Document>();
parser.Parse(System.Xml.Linq.XDocument.Parse(xml), results);

TermsResults termResults = results.Terms;
foreach (TermsResult result in termResults)
{
    foreach (KeyValuePair<string, int> kvp in result.Terms)
    {
        //... do something with keys
    }
}

Basically I use the SolrNet parser and the connection code but not the query stuff. Hope this helps.



回答4:

Passing the qt parameter does NOT work, at least not in Solr 4.7 even with handleSelect=true in SolrConfig. You can verify by specifying a custom handler that's very dissimilar from the default /select, say make yours use edismax and send debugQuery = true in ExtraParams and catch the results in Fiddler.

Also if you read the explanation on the handleSelect flag it says "if the request uses "/select" but there is no request handler by that name".

You don't want to touch or disable the /select handler because Solr uses it itself.

I ended up using ExtraParams to pass all the values I defined in my custom handler, there weren't that many. Seemed better than just using part of SolrNET and then doing the result parsing.