Highlighting Usage

edit

Allows to highlight search results on one or more fields. The implementation uses either the lucene highlighter, fast-vector-highlighter or postings-highlighter.

See the Elasticsearch documentation on highlighting for more detail.

Fluent DSL example

edit
s => s
.Query(q => q
    .Match(m => m
        .Field(f => f.Name.Suffix("standard"))
        .Query("Upton Sons Shield Rice Rowe Roberts")
    )
)
.Highlight(h => h
    .PreTags("<tag1>")
    .PostTags("</tag1>")
    .Encoder("html")
    .Fields(
        fs => fs
            .Field(p => p.Name.Suffix("standard"))
            .Type("plain")
            .ForceSource()
            .FragmentSize(150)
            .NumberOfFragments(3)
            .NoMatchSize(150),
        fs => fs
            .Field(p => p.LeadDeveloper.FirstName)
            .Type(HighlighterType.Fvh)
            .PreTags("<name>")
            .PostTags("</name>")
            .BoundaryMaxScan(50)
            .PhraseLimit(10)
            .HighlightQuery(q => q
                .Match(m => m
                    .Field(p => p.LeadDeveloper.FirstName)
                    .Query("Kurt Edgardo Naomi Dariana Justice Felton")
                )
            ),
        fs => fs
            .Field(p => p.LeadDeveloper.LastName)
            .Type(HighlighterType.Postings)
            .PreTags("<name>")
            .PostTags("</name>")
            .HighlightQuery(q => q
                .Match(m => m
                    .Field(p => p.LeadDeveloper.LastName)
                    .Query(LastNameSearch)
                    )
                )
            )
)

Object Initializer syntax example

edit
new SearchRequest<Project>
{
    Query = new MatchQuery
    {
        Query = "Upton Sons Shield Rice Rowe Roberts",
        Field = "name.standard"
    },
    Highlight = new Highlight
    {
        PreTags = new[] { "<tag1>" },
        PostTags = new[] { "</tag1>" },
        Encoder = "html",
        Fields = new Dictionary<Field, IHighlightField>
        {
            { "name.standard", new HighlightField
                {
                    Type = HighlighterType.Plain,
                    ForceSource = true,
                    FragmentSize = 150,
                    NumberOfFragments = 3,
                    NoMatchSize = 150
                }
            },
            { "leadDeveloper.firstName", new HighlightField
                {
                    CustomType = "fvh", 
                    PhraseLimit = 10,
                    BoundaryMaxScan = 50,
                    PreTags = new[] { "<name>"},
                    PostTags = new[] { "</name>"},
                    HighlightQuery = new MatchQuery
                    {
                        Field = "leadDeveloper.firstName",
                        Query = "Kurt Edgardo Naomi Dariana Justice Felton"
                    }
                }
            },
            { "leadDeveloper.lastName", new HighlightField
                {
                    Type = HighlighterType.Postings,
                    PreTags = new[] { "<name>"},
                    PostTags = new[] { "</name>"},
                    HighlightQuery = new MatchQuery
                    {
                        Field = "leadDeveloper.lastName",
                        Query = LastNameSearch
                    }
                }
            }
        }
    }
}

CustomType can be used to define a custom highlighter

Example json output.

{
  "query": {
    "match": {
      "name.standard": {
        "query": "Upton Sons Shield Rice Rowe Roberts"
      }
    }
  },
  "highlight": {
    "pre_tags": [
      "<tag1>"
    ],
    "post_tags": [
      "</tag1>"
    ],
    "encoder": "html",
    "fields": {
      "name.standard": {
        "type": "plain",
        "force_source": true,
        "fragment_size": 150,
        "number_of_fragments": 3,
        "no_match_size": 150
      },
      "leadDeveloper.firstName": {
        "type": "fvh",
        "phrase_limit": 10,
        "boundary_max_scan": 50,
        "pre_tags": [
          "<name>"
        ],
        "post_tags": [
          "</name>"
        ],
        "highlight_query": {
          "match": {
            "leadDeveloper.firstName": {
              "query": "Kurt Edgardo Naomi Dariana Justice Felton"
            }
          }
        }
      },
      "leadDeveloper.lastName": {
        "type": "postings",
        "pre_tags": [
          "<name>"
        ],
        "post_tags": [
          "</name>"
        ],
        "highlight_query": {
          "match": {
            "leadDeveloper.lastName": {
              "query": "Stokes"
            }
          }
        }
      }
    }
  }
}

Handling Responses

edit
response.ShouldBeValid();

foreach (var highlightsByDocumentId in response.Highlights)
{
    foreach (var highlightHit in highlightsByDocumentId.Value)
    {
        if (highlightHit.Key == "name.standard")
        {
            foreach (var highlight in highlightHit.Value.Highlights)
            {
                highlight.Should().Contain("<tag1>");
                highlight.Should().Contain("</tag1>");
            }
        }
        else if (highlightHit.Key == "leadDeveloper.firstName")
        {
            foreach (var highlight in highlightHit.Value.Highlights)
            {
                highlight.Should().Contain("<name>");
                highlight.Should().Contain("</name>");
            }
        }
        else if (highlightHit.Key == "leadDeveloper.lastName")
        {
            foreach (var highlight in highlightHit.Value.Highlights)
            {
                highlight.Should().Contain("<name>");
                highlight.Should().Contain("</name>");
            }
        }
        else
        {
            Assert.True(false, $"highlights contains unexpected key {highlightHit.Key}");
        }
    }
}