ReFocus
ReFocus

Reputation: 1521

NEST (ElasticSearch) matching Highlights to documents

I'm using C# NEST with ElasticSearch. I'm able to query an index of Products and look in their Name and CategoryName fields for matches. I can also extend the query using Highlights.

Now in my IQueryResponse response I have two collections: (1) .Documents and (2) .Highlights.

e.g.: Consider the search for: "cat" which has 3 document results:

{
   { Name: "Cat product", CategoryName: "Category1" },
   { Name: "Some product", CategoryName: "Category2" },
   { Name: "Some product2", CategoryName: "Category3" }
}

But now I have 4 highlight results:

{
   { Field: "name", Highlights: ['"<u>Cat</u> product"'] },
   { Field: "categoryName", Highlights: ['"<u>Cat</u>egory1"'] },
   { Field: "categoryName", Highlights: ['"<u>Cat</u>egory2"'] },
   { Field: "categoryName", Highlights: ['"<u>Cat</u>egory3"'] }
}

They seem to be in no way related to each other. How do I know which Highlight item belongs to which Document item?

Upvotes: 1

Views: 2442

Answers (2)

authentic Sailor
authentic Sailor

Reputation: 1

here is an updated answer for version 7.x. You receive two collections as before, .Documents and .Hits . Within .Hits each one has an .Id that matches the _id of the index in elasticsearch. Note: if you request more than one highlighting .NumberofFragments in your query, you will just keep overwriting the result.title and result.content in the code below, so take this as a loose example to indicate how you can match the highlight result to the correct document result, and then overwrite the document field with the one containing the highlighting.

if (response.Documents.Count > 0)
{
    foreach (MyResultClass result in response.Documents) //cycle through your results
    {
         foreach (var hit in response.Hits) // cycle through your hits to look for match
         {
              if (hit.Id == result.id) //you found the hit that matches your document
              {
                    foreach (var highlightField in hit.Highlight)
                    {
                           if (highlightField.Key == "title")
                           {
                                foreach (var highlight in highlightField.Value)
                                {
                                    result.title = highlight.ToString();
                                }
                           }
                           else if (highlightField.Key == "content")
                           {
                                foreach (var highlight in highlightField.Value)
                                {
                                    result.content = highlight.ToString();
                                }
                           }
                   }
             }
      }
}

Upvotes: 0

Martijn Laarman
Martijn Laarman

Reputation: 13536

IQueryResponse also exposes .DocumentsWithMetaData of type IEnumerable<IHit<T>> where T is the type of your document

This is basically the unwrapped view of the results as return by elasticsearch IHit<T> has many useful properties such as the Highlights.

I've added a DocumentId result to the highlight class Highlight so that no matter how you get to the highlight you can relate it back easily to the hit.

So use .DocumentsWithMetaData for now, the next release will have a more logical API for highlights.

Upvotes: 3

Related Questions