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 Blog {
    private String id;
    private String title;
    private String category;
    private String content;
    private Date publishedAt;
    private String[] tags;
    private List<BlogComment> comments;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Date getPublishedAt() {
        return publishedAt;
    }

    public void setPublishedAt(Date publishedAt) {
        this.publishedAt = publishedAt;
    }

    public String[] getTags() {
        return tags;
    }

    public void setTags(String[] tags) {
        this.tags = tags;
    }

    public List<BlogComment> getComments() {
        return comments;
    }

    public void setComments(List<BlogComment> comments) {
        this.comments = comments;
    }
}
public class BlogComment {

    private String title;
    private String content;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

public static class BlogPosts_ByContent extends AbstractIndexCreationTask {
    public static class Result {
        private String content;

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

    public BlogPosts_ByContent() {
        map = "docs.Posts.Select(post => new { post.content })";
        index("content", FieldIndexing.SEARCH);
        store("content", FieldStorage.YES);
        termVector("content", FieldTermVector.WITH_POSITIONS_AND_OFFSETS);
    }
}

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 WITH_POSITIONS_AND_OFFSETS

Usage

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

Reference<Highlightings> highlightsRef = new Reference<>();
List<Blog> results = session
    .advanced()
    .documentQuery(Blog.class, BlogPosts_ByContent.class)
    .highlight("content", 128, 1, highlightsRef)
    .search("content", "raven")
    .toList();

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

for (Blog result : results) {
    String[] fragments = highlightsRef.value.getFragments(result.getId());
    builder.append("<li>")
        .append(fragments[0])
        .append("</li>");
}

builder.append("</ul>");
String ul = builder.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.

Reference<Highlightings> highlightsRef = new Reference<>();
HighlightingOptions highlightingOptions = new HighlightingOptions();
highlightingOptions.setPreTags(new String[] { "**" });
highlightingOptions.setPostTags(new String[] { "**" });
List<BlogPosts_ByContent.Result> results = session
    .query(BlogPosts_ByContent.class, BlogPosts_ByContent.class)
    .highlight("content", 128, 1, highlightingOptions, highlightsRef)
    .search("content", "raven")
    .selectFields(BlogPosts_ByContent.Result.class)
    .toList();
public static class BlogPosts_ByContent extends AbstractIndexCreationTask {
    public static class Result {
        private String content;

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

    public BlogPosts_ByContent() {
        map = "docs.Posts.Select(post => new { post.content })";
        index("content", FieldIndexing.SEARCH);
        store("content", FieldStorage.YES);
        termVector("content", FieldTermVector.WITH_POSITIONS_AND_OFFSETS);
    }
}

Highlighting + Map-Reduce

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

// highlighting 'content', but marking 'category' as key
Reference<Highlightings> highlightsRef = new Reference<>();
HighlightingOptions highlightingOptions = new HighlightingOptions();
highlightingOptions.setPreTags(new String[] { "**" });
highlightingOptions.setPostTags(new String[] { "**" });
highlightingOptions.setGroupKey("category");
List<BlogPosts_ByCategory_Content.Result> results = session
    .advanced()
    .documentQuery(BlogPosts_ByCategory_Content.Result.class, BlogPosts_ByCategory_Content.class)
    .highlight("content", 128, 1, highlightingOptions, highlightsRef)
    .search("content", "raven")
    .toList();

// get fragments for 'news' category
String[] newsHighlightings = highlightsRef.value.getFragments("news");
public static class BlogPosts_ByCategory_Content extends AbstractIndexCreationTask {
    public static class Result {
        private String category;
        private String content;

        public String getCategory() {
            return category;
        }

        public void setCategory(String category) {
            this.category = category;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }

    public BlogPosts_ByCategory_Content() {
        map = "docs.Posts.Select(post => new { post.category, post.content })";

        reduce = "results.GroupBy(result => result.Category).Select(g => new {" +
            " category = g.Key, " +
            " Content = string.Join(\" \", g.Select(r => r.content)) " +
            "}";

        index("content", FieldIndexing.SEARCH);
        store("content", FieldStorage.YES);
        termVector("content", FieldTermVector.WITH_POSITIONS_AND_OFFSETS);
    }
}

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