Elasticsearch highlighting

(Mark Evans) #1

im using elasticsearch within a C# project using the NEST API. i want to show the searched terms as highlights in the results page but dont know how i handle the display of them. All the docs tell me how to set up the highlight feature in the search query but i cannot find any help on how i make these highlights appear on the page of results...

my query is as follows

result = client.Search(s => s
.Query(a =>

        a.Match(m => m.OnField("_all").Query(m_strSearchQuery))

        .Highlight(h => h
        .PreTags("<b style='color:orange'>")
        .OnFields(f => f
        .OnField(e => e.Title)
        .OnField(e => e.Content)

Then i set my results to a variable that is the data for my repeater

var documents = result.Hits.Select(h => h.Source);

this.rptSearch.DataSource = documents;
this.rptSearch.Visible = true;
i dont see any of the terms highlighted in my results nor do i see the terms wrapped in the highlight tags...

i did notice on debug my results have a hits and a highlights array though the highlights value doesnt seem to show the complete text returned as i see in the hits.source...

anyone help on this?

(Nik Everett) #2

I don't know nest but I know highlighting.

First thing's first you should wrap multiline code in fenced blocks like:

result = client.Search(s => s.Query(a =>
        a.Match(m => m.OnField("_all").Query(m_strSearchQuery))

That'll preserve the spaces.

Secondly I think [this link](http://nest.azurewebsites.net/nest/search/highlighting.html) has what you need.

(Mark Evans) #3


ive seen that link and have that .highlight in the search query for the fields i want to use...

thats all done, what i cant see is how i get the highlighted words appearing in the text... they are not wrapped in the highlight tags...

the hits.source has the original text but the .highlights element has the highlighted snippet so i presume i need to do some sort of replace on the source text from the highlight text?

(Nik Everett) #4

Highlighting's second job is snipping the text to the most "interesting" parts. If you just want the whole text back with the highlights there then set fragment_size to something large - 10k or something.

(Mark Evans) #5

Do i need to do something in my index / mapping to make highlighting work?

maybe thats what im not doing?

(Mark Evans) #6

ok thanks i will try that but regardless how do i get the actual highlighted text in my search results page..

currently i use

var documents = result.Hits.Select(h => h.Source); (this doesnt have the highlight tags at all)

i tried using result.Highlights.ToString() but that didnt work...

(Nik Everett) #7

Highlighting works fine without making any changes to the index but you can make changes to the index to make highlighting faster - its all on the highlightings docs.

That is the trouble - I don't know the client so I can't explain it. If you go from the client to curl I could be more helpful.

(Mark Evans) #8

ok no problem

looks like ill have to leave it out for now...

its just that previously they used solr and it supported highlighted terms and its a requirement for elasticsearch now which has replaced it

(Mark Harwood) #9

The default for the highlighter is to highlight fields using only terms from the query that were explicitly targeted at those fields (so a search for forename:mark won't highlight any "mark" tokens found in a surname field).

However, when searching the _all field this is precisely what you want to do - search one (indexed) field but highlight another (stored) field. Try set require_field_match to false.
See https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html#field-match

(Mark Evans) #10

i can see the highlights when i step through with debug... these are set against just one field in my index...

im currently getting the results into my page by loading them from the source which is getting both the title and body fields returned from the search

var documents = result.Hits.Select(h => h.Source);

but if there are highlights for the hit i want the body field to be the highlight value. i can grab the highlight value but am unable to overwrite the body content or know how to populate the body field with the highlight and keep the other fields as they were....

(Mark Evans) #11

im trying to do this when i loop through each hit of the results, but the field value is never replaced it just stays as it was before the replace...

if (!hit.Highlights.Any()) continue;

                foreach (KeyValuePair<string, Highlight> item in hit.Highlights)
                    hit.Source.ContentBody.Replace(hit.Source.ContentBody, item.Value.Highlights.FirstOrDefault());

(Martijn Laarman) #12

Replace on string returns a new string with the replacement result, it does not mutate the original string try:

hit.Source.ContentBody = hit.Source.ContentBody
    .Replace(hit.Source.ContentBody, item.Value.Highlights.FirstOrDefault());

However it looks like you just want the first highlight result as the ContentBody inside your Source document so you can simply call:

hit.Source.ContentBody = item.Value.Highlights.FirstOrDefault();

(Mark Evans) #13


thanks i get this working now to the extent that the contentbody has the new highlight snippet at this point and i see it in the source fields when the documents variable is assigned.

however i do not see the highlights in the page and view source reveals the pre and post tags are not there so need to find out why.

maybe they are lost when bound to the repeater?

(system) #14