This content is archived. See latest version here.

Last updated: Feb 23 2015

Highlighting is used to visually distinguish fragments that match keywords within search results. Highlighted fragments are surrounded by an HTML tag. Using the fluent API, you can request highlighting as part of a projection expression passed to the Select method. To do so, invoke the AsHighlighted extension method on a string property.

Assume you indexed instances of a BlogPost class with a Title and Content property. Search for blog posts and retrieve the Title and a highlight from the Content property like this:

C#
searchResult = client.Search<BlogPost>()
  .For("Bacon")
  .Select(x => new { 
    Title = x.Title, 
    Content = x.Content.AsHighlighted() 
   })
  .GetResult();

Overwriting default styling

By default, highlighted keywords are wrapped in <em> tags. To overwrite this styling, pass to the AsHighlighted method an instance of the HighlightSpec class, and set its PreTag and PostTag properties.

C#
searchResult = client.Search<BlogPost>()
  .For("Bacon")
  .Select(x => new { 
    Title = x.Title, 
    Content = x.Content.AsHighlighted(
      new HighlightSpec 
      { 
        PreTag = "<strong>", 
        PostTag = "</strong>"
      }) 
   })
  .GetResult();

Controlling the number and length of fragments

By default, the entire field is highlighted and retrieved. This is usually desired for shorter fields, but for longer fields, you probably want to extract one or a few fragments instead. To achieve this, set the NumberOfFragments property on the HighlightSpec instance.

You can also control the length of fragments by setting the FragmentSize property. If you do not, the server default value of 100 is used. Note do not set the FragmentSize property to a value lower than 18.

As an example, the following code retrieves a single fragment that is 200 characters long (excluding HTML tags used to wrap keywords) for the Content field.

C#
searchResult = client.Search<BlogPost>()
  .For("Bacon")
  .Select(x => new { 
    Title = x.Title, 
    Content = x.Content.AsHighlighted(
      new HighlightSpec 
      { 
        NumberOfFragments = 1, 
        FragmentSize = 200
      }) 
   })
  .GetResult();

Determining the character separating concatenated fragments

If you set NumberOfFragments to a value greater than one, multiple fragments are passed from the server. The fragments are automatically concatenated with a space ( ) between them. To override this, pass in a Func<IEnumerable<string>, string> to the HighlightSpec Concatenation method.

C#
searchResult = client.Search<BlogPost>()
  .For("Bacon")
  .Select(x => new { 
    Title = x.Title, 
    Content = x.Content.AsHighlighted(
      new HighlightSpec 
      { 
        NumberOfFragments = 3, 
        Concatenation = fragments => fragments.Concatenate(" ... ")
      }) 
   })
  .GetResult();

The above example uses an extension method that concatenates fragments and places three dots between each. You can perform more complex operations.

Ensuring the projected property is not an empty string

If there are no highlights for the requested field, the projected property is an empty string. To ensure that the property value is not empty, use an if statement.

C#
searchResults = client.Search<BlogPost>()
  .For("Bacon")
  .Select(x => 
    !string.IsNullOrEmpty(x.Title.AsHighlighted()) 
      ? x.Title.AsHighlighted() 
      : x.Title)
  .GetResult();

Note that the if statement is executed in memory. So, in the above example, the highlight and the Title property are retrieved from the server, which means that more data is sent over the wire. That is usually not a problem, but something to be aware of.

Highlighting and encoding when using "typed search" [New in 9.1]

 "Typed" search provides different ways to implement the highlighting and encoding of search results. An example is below.

Example

// register a convention to remove html tags and decode any html encoded values
client.Conventions
    .ForInstancesOf<BlogPost>()
    .Field(x => x.Content)
    .StripHtml();

// create a blog post
var blogPost = new BlogPost();
blogPost.Title = "This is a great story about apples";
blogPost.Content = "This is a great story about <strong>apples</strong>...";
client.Index(blogPost);

// register string extensions to encode the string but preserve the highlight tags
public static class StringExtensions
{
    public static string EncodeAndPreserveHighlightTags(this string highlightedString)
    {
        return highlightedString.EncodeAndPreserveHighlightTags(null, null);
    }

    public static string EncodeAndPreserveHighlightTags(this string highlightedString,
        string preTag, string postTag)
    {
        preTag = preTag ?? HighlightSpec.DefaultPreTag;
        postTag = postTag ?? HighlightSpec.DefaultPostTag;

        const string preTagMarker = "|pre|";
        const string postTagMarker = "|post|";

        var taggedHighlightedString = highlightedString
            .Replace(preTag, preTagMarker)
            .Replace(postTag, postTagMarker);

        var encodedTaggedHighlightedString = HttpUtility.HtmlEncode(taggedHighlightedString);

        return encodedTaggedHighlightedString
            .Replace(preTagMarker, preTag)
            .Replace(postTagMarker, postTag);
    }
}

// issue query and request the content as encoded but with preserved highlight tags
result = client.Search<BlogPost>()
    .For("apples")
    .Select(x => x.Content.AsHighlighted().EncodeAndPreserveHighlightTags())
    .GetResult();

// the result text is encoded and highlighted
//result.First() => "This is a great story about <em>apples</em>..."

Highlighting and encoding with Unified Search

When using Unified Search, HTML encoding is enabled by default for the "title" and "excerpt" fields. The text is encoded before the HTML tags that surround highlighted content are added. You can disable default HTML encoding. Refer to Unified Search for details.

Comments