Highlighting Usage

edit

Allows to highlight search results on one or more fields. The implementation uses either the lucene highlighter or fast-vector-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(HighlighterEncoder.Html)
    .HighlightQuery(q => q
        .Match(m => m
            .Field(f => f.Name.Suffix("standard"))
            .Query("Upton Sons Shield Rice Rowe Roberts")
        )
    )
    .Fields(
        fs => fs
            .Field(p => p.Name.Suffix("standard"))
            .Type("plain")
            .ForceSource()
            .FragmentSize(150)
            .Fragmenter(HighlighterFragmenter.Span)
            .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.Unified)
            .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 = HighlighterEncoder.Html,
        HighlightQuery = new MatchQuery
        {
            Query = "Upton Sons Shield Rice Rowe Roberts",
            Field = "name.standard"
        },
        Fields = new Dictionary<Field, IHighlightField>
        {
            {
                "name.standard", new HighlightField
                {
                    Type = HighlighterType.Plain,
                    ForceSource = true,
                    FragmentSize = 150,
                    Fragmenter = HighlighterFragmenter.Span,
                    NumberOfFragments = 3,
                    NoMatchSize = 150
                }
            },
            {
                "leadDeveloper.firstName", new HighlightField
                {
                    Type = "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.Unified,
                    PreTags = new[] { "<name>" },
                    PostTags = new[] { "</name>" },
                    HighlightQuery = new MatchQuery
                    {
                        Field = "leadDeveloper.lastName",
                        Query = LastNameSearch
                    }
                }
            }
        }
    }
}

Example json output.

{
  "query": {
    "match": {
      "name.standard": {
        "query": "Upton Sons Shield Rice Rowe Roberts"
      }
    }
  },
  "highlight": {
    "pre_tags": [
      "<tag1>"
    ],
    "post_tags": [
      "</tag1>"
    ],
    "encoder": "html",
    "highlight_query": {
      "match": {
        "name.standard": {
          "query": "Upton Sons Shield Rice Rowe Roberts"
        }
      }
    },
    "fields": {
      "name.standard": {
        "type": "plain",
        "force_source": true,
        "fragment_size": 150,
        "fragmenter": "span",
        "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": "unified",
        "pre_tags": [
          "<name>"
        ],
        "post_tags": [
          "</name>"
        ],
        "highlight_query": {
          "match": {
            "leadDeveloper.lastName": {
              "query": "Stokes"
            }
          }
        }
      }
    }
  }
}

Handling Responses

edit
response.ShouldBeValid();

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