Skip to content

Instantly share code, notes, and snippets.

@jacobjones
Last active February 13, 2020 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jacobjones/5b3667339c42c0139e4ef16649cf71c5 to your computer and use it in GitHub Desktop.
Save jacobjones/5b3667339c42c0139e4ef16649cf71c5 to your computer and use it in GitHub Desktop.
Episerver Find Explain
using System;
using System.IO;
using System.Net;
using System.Text;
using EPiServer.Find;
using EPiServer.Find.Api;
using EPiServer.Find.Connection;
using EPiServer.Find.Helpers;
using EPiServer.Find.Json;
using Newtonsoft.Json.Linq;
namespace EPiServer.Reference.Commerce.Site.Explain
{
public class ExplainCommand : Command
{
private readonly string _index;
public ExplainCommand(ICommandContext commandContext, string index) : base(commandContext)
{
_index = index;
}
public ExplainSearchResult Explain(ISearch search)
{
var request = CommandContext.RequestFactory.CreateRequest(GetUrl(), HttpVerbs.Post, ExplicitRequestTimeout);
try
{
var context = new SearchContext();
search.ApplyActions(context);
var requestBody = CommandContext.Serializer.Serialize(context.RequestBody);
var jObject = JObject.Parse(requestBody);
jObject.Add("explain", true);
request.WriteBody(jObject.ToString());
return GetResponse<ExplainSearchResult>(request);
}
catch (WebException ex)
{
var message = ex.Message;
if (!ex.Response.IsNotNull())
{
throw new WebException(message, ex);
}
var end = new StreamReader(ex.Response.GetResponseStream(), Encoding.UTF8).ReadToEnd();
message = message + Environment.NewLine + end;
throw new WebException(message, ex);
}
}
private string GetUrl()
{
return $"{GetServerUrl()}{_index}/_search";
}
}
}
using System.Collections.Generic;
using Newtonsoft.Json;
namespace EPiServer.Reference.Commerce.Site.Explain
{
public class ExplainHitCollection
{
[JsonProperty("hits")]
public virtual List<ExplainSearchHit> Hits { get; set; }
[JsonProperty("total")]
public int Total { get; set; }
}
}
using EPiServer.Find;
namespace EPiServer.Reference.Commerce.Site.Explain
{
public static class ExplainSearchExtensions
{
public static ExplainSearchResult GetExplainResult(this ISearch search)
{
return search.Client.NewCommand(context => new ExplainCommand(context, search.Client.DefaultIndex))
.Explain(search);
}
}
}
using EPiServer.Find.Api;
using Newtonsoft.Json;
namespace EPiServer.Reference.Commerce.Site.Explain
{
[JsonConverter(typeof(ExplainSearchHitConverter))]
public class ExplainSearchHit : SearchHit
{
[JsonProperty("_explanation")]
public Explanation Explanation { get; set; }
[JsonIgnore]
public virtual string DocumentName { get; set; }
}
}
using System;
using System.Reflection;
using EPiServer.Find.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace EPiServer.Reference.Commerce.Site.Explain
{
internal class ExplainSearchHitConverter : IgnoredPropertiesHandlingConverterBase
{
public override bool CanConvert(Type objectType)
{
return true;
}
protected override void PopulateProperty(JsonReader reader, JsonSerializer serializer, Type objectType, string propertyName, object item)
{
if (propertyName == "fields" || propertyName == "_source")
{
PopulateDocumentNameProperty(reader, serializer, objectType, item);
return;
}
if (propertyName == "_explanation")
{
PopulateExplanationProperty(reader, serializer, objectType, item);
}
}
private static void PopulateDocumentNameProperty(JsonReader reader, JsonSerializer serializer, Type objectType, object item)
{
var obj = serializer.Deserialize<JObject>(reader);
var documentName = obj["_Name"].Value<string>();
objectType.InvokeMember("DocumentName",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, null, item,
new object[] {documentName});
}
private static void PopulateExplanationProperty(JsonReader reader, JsonSerializer serializer, Type objectType, object item)
{
var obj = serializer.Deserialize<Explanation>(reader);
objectType.InvokeMember("Explanation",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, null, item,
new object[] {obj});
}
}
}
using Newtonsoft.Json;
namespace EPiServer.Reference.Commerce.Site.Explain
{
public class ExplainSearchResult
{
[JsonProperty("hits")]
public ExplainHitCollection Hits { get; set; }
}
}
using System.Collections.Generic;
using Newtonsoft.Json;
namespace EPiServer.Reference.Commerce.Site.Explain
{
public class Explanation
{
[JsonProperty("value", NullValueHandling = NullValueHandling.Ignore)]
public double Value { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("details")]
public List<Explanation> Details { get; set; }
}
}
@jacobjones
Copy link
Author

Example usage:

var result = _client.Search<IContent>().For(query).GetExplainResult();

Please note: this functionality doesn't work on Episerver Find demo indexes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment