Get response from custom Solr requestHandler with .NET

This is a follow-up to my previous post: Configuring Solr to provide search suggestions

So everything is set up in Solr, but now we need to get the response in our .NET code.

Assuming the following:

[code language=”csharp”]
using Newtonsoft.Json.Linq;
using SolrNet.Impl;
[/code]

[code language=”csharp”]
var solrRoot = "http://localhost:3664/solr";
var suggestIndexName = "suggest_index";
var requestHandlerName = "/suggest";
var suggestUrl = string.Format("/{0}{1}", suggestIndexName, requestHandlerName);
[/code]

All we need to do is set up the querystring parameters, instantiate the SolrConnection and do a GET.

[code language=”csharp”]
var query = new SuggestQuery
{
SuggestTerm = "partial string to get suggestions for",
PageSize = 10
};
var parameters = new Dictionary<string, string>
{
{"q", query.SuggestTerm}, // the string we’re getting suggestions for
{"wt", "json"} // the response format, can also be "xml"
}
var solrConnection = new SolrConnection(solrRoot);

var response = solrConnection.Get(suggestUrl, parameters);
[/code]

In this case the response is a json string. I used Newtonsoft.Json to parse the response into a JObject. Then I can traverse the fields/nodes and finally cast the suggestions into a concrete type.

Since I have two suggesters set up (a Fuzzy suggester and an Infix suggester), I’ll get two sets of suggestions. My SolrSuggest Suggestion type is set up with overrides for Equals and GetHashCode to facilitate the comparing of these items. This way I can do a .Union on the two lists to remove duplicate terms, then it can be ordered and truncated (page size or max count).

[code language=”csharp”]
var response = new SolrSuggest(); // custom type defined below

var responseHeader = JObject.Parse(solrSuggestReponse); // Newtonsoft.JObject
var suggestions = responseHeader["suggest"];

var infixSuggester = suggestions["infixSuggester"];
var infixTermSuggestions = infixSuggester[query.SuggestTerm]; // this field will have the name of the term that was searched.

var infix = jsDeserializer.Deserialize<SolrSuggest>(infixTermSuggestions.ToString()); // Deserialize to custom Type

var fuzzySuggester = suggestions["fuzzySuggester"];
var fuzzyTermSuggestions = fuzzySuggester[query.SuggestTerm]; // this field will have the name of the term that was searched.

var fuzzy = jsDeserializer.Deserialize<SolrSuggest>(fuzzyTermSuggestions.ToString());

// .Union will add items from the second list to the first list while comparing them to prevent the addition of duplicate items
response.suggestions = infix.suggestions.Union(fuzzy.suggestions).OrderByDescending(s => s.weight).Take(query.PageSize).ToList();

response.numFound = response.suggestions.Count;

return response;
[/code]

And this is the structure I used to deserialize the TermSuggestions to C# objects:

[code language=”csharp”]
public class Suggestion
{
public string term { get; set; }
public int weight { get; set; }
public string NormalizedTerm
{
// The infix suggester will wrap the suggest term within the suggestions in <b> tags
get { return term.Replace("<b>", string.Empty).Replace("</b>", string.Empty); }
}

public override bool Equals(object otherSuggestion)
{
var other = (Suggestion)otherSuggestion;
return other != null && other.NormalizedTerm == NormalizedTerm;
}

public override int GetHashCode()
{
return NormalizedTerm.GetHashCode();
}
}

public class SolrSuggest
{
public int numFound { get; set; }
public List<Suggestion> suggestions { get; set; }
public SolrSuggest()
{
suggestions = new List<Suggestion>();
}
}
[/code]

Thanks for reading, I hope this helps someone out there.