You are currently browsing legacy 4.1 version of documentation. Click here to switch to the newest 4.2 version.

We can help you with migration to the latest RavenDB

Contact Us Now
see on GitHub

Querying: Highlighting

Another feature called Highlighting has been added to RavenDB to enhance the search UX.

Setup

public class BlogPost
{
	public string Id { get; set; }

	public string Title { get; set; }

	public string Category { get; set; }

	public string Content { get; set; }

	public DateTime PublishedAt { get; set; }

	public string[] Tags { get; set; }

	public BlogComment[] Comments { get; set; }
}
public class BlogComment
{
	public string Title { get; set; }

	public string Content { get; set; }
}

public class BlogPosts_ByContent : AbstractIndexCreationTask<BlogPost>
{
    public class Result
    {
        public string Content { get; set; }
    }

    public BlogPosts_ByContent()
    {
        Map = posts => from post in posts
                       select new
                       {
                           post.Content
                       };

        Index(x => x.Content, FieldIndexing.Search);
        Store(x => x.Content, FieldStorage.Yes);
        TermVector(x => x.Content, FieldTermVector.WithPositionsAndOffsets);
    }
}

Important

Each of the fields on which we want to use Highlighting needs to have:

  • FieldIndexing set to Search
  • FieldStorage set to Yes
  • FieldTermVector set to WithPositionsAndOffsets

Usage

To use Highlighting we just need to use one of the Highlight query methods. The basic usage can be as simple as:

BlogPost[] results = session
    .Advanced
    .DocumentQuery<BlogPost, BlogPosts_ByContent>()
    .Highlight("Content", 128, 1, out Highlightings highlightings)
    .Search("Content", "raven")
    .ToArray();

StringBuilder builder = new StringBuilder()
    .AppendLine("<ul>");

foreach (BlogPost result in results)
{
    string[] fragments = highlightings.GetFragments(result.Id);
    builder.AppendLine($"<li>{fragments.First()}</li>");
}

string ul = builder
    .AppendLine("</ul>")
    .ToString();

This will return the list of results and for each result we will be displaying first found fragment with the length up to 128 characters.

Highlighting + Projections

Highlighting can also be done when projections are performed.

BlogPosts_ByContent.Result[] results = session
    .Query<BlogPosts_ByContent.Result, BlogPosts_ByContent>()
    .Highlight("Content", 128, 1, new HighlightingOptions
    {
        PreTags = new[] { "**" },
        PostTags = new[] { "**" }
    }, out Highlightings highlightings)
    .Search(x => x.Content, "raven")
    .ProjectInto<BlogPosts_ByContent.Result>()
    .ToArray();
BlogPosts_ByContent.Result[] results = session
    .Advanced
    .DocumentQuery<BlogPost, BlogPosts_ByContent>()
    .Highlight("Content", 128, 1, new HighlightingOptions
    {
        PreTags = new[] { "**" },
        PostTags = new[] { "**" }
    }, out Highlightings highlightings)
    .Search("Content", "raven")
    .SelectFields<BlogPosts_ByContent.Result>()
    .ToArray();
public class BlogPosts_ByContent : AbstractIndexCreationTask<BlogPost>
{
    public class Result
    {
        public string Content { get; set; }
    }

    public BlogPosts_ByContent()
    {
        Map = posts => from post in posts
                       select new
                       {
                           post.Content
                       };

        Index(x => x.Content, FieldIndexing.Search);
        Store(x => x.Content, FieldStorage.Yes);
        TermVector(x => x.Content, FieldTermVector.WithPositionsAndOffsets);
    }
}

Highlighting + Map-Reduce

Highlighting can be performed when executing queries on map-reduce indexes.

// highlighting 'Content', but marking 'Category' as key
BlogPosts_ByCategory_Content.Result[] results = session
    .Query<BlogPosts_ByCategory_Content.Result, BlogPosts_ByCategory_Content>()
    .Highlight("Content", 128, 1, new HighlightingOptions
    {
        PreTags = new[] { "**" },
        PostTags = new[] { "**" },
        GroupKey = "Category"
    }, out Highlightings highlightings)
    .Search(x => x.Content, "raven")
    .ToArray();

// get fragments for 'News' category
var newsHighlightings = highlightings.GetFragments("News");
// highlighting 'Content', but marking 'Category' as key
BlogPosts_ByCategory_Content.Result[] results = session
    .Advanced
    .DocumentQuery<BlogPosts_ByCategory_Content.Result, BlogPosts_ByCategory_Content>()
    .Highlight("Content", 128, 1, new HighlightingOptions
    {
        PreTags = new[] { "**" },
        PostTags = new[] { "**" },
        GroupKey = "Category"
    }, out Highlightings highlightings)
    .Search("Content", "raven")
    .ToArray();

// get fragments for 'News' category
var newsHighlightings = highlightings.GetFragments("News");
public class BlogPosts_ByCategory_Content : AbstractIndexCreationTask<BlogPost, BlogPosts_ByCategory_Content.Result>
{
    public class Result
    {
        public string Category { get; set; }

        public string Content { get; set; }
    }

    public BlogPosts_ByCategory_Content()
    {
        Map = posts => from post in posts
                       select new
                       {
                           post.Category,
                           post.Content
                       };

        Reduce = results => from result in results
                            group result by result.Category into g
                            select new
                            {
                                Category = g.Key,
                                Content = string.Join(" ", g.Select(r => r.Content))
                            };

        Index(x => x.Content, FieldIndexing.Search);
        Store(x => x.Content, FieldStorage.Yes);
        TermVector(x => x.Content, FieldTermVector.WithPositionsAndOffsets);
    }
}

Remarks

Note

Default <b></b> tags are coloured and colours are returned in following order:

  •  yellow,
  •  lawngreen,
  •  aquamarine,
  •  magenta,
  •  palegreen,
  •  coral,
  •  wheat,
  •  khaki,
  •  lime,
  •  deepskyblue,
  •  deeppink,
  •  salmon,
  •  peachpuff,
  •  violet,
  •  mediumpurple,
  •  palegoldenrod,
  •  darkkhaki,
  •  springgreen,
  •  turquoise,
  •  powderblue