MVC searching with Elasticsearch Highlighting

This article shows how to use Elasticsearch highlighting in a MVC application for search results. The application does a simple Elasticsearch Fuzzy Query and the highlighted results are displayed in a Razor view.

Code: https://github.com/damienbod/MVCSearchHighlightingElasticsearch

Other Tutorials:

Part 1: ElasticsearchCRUD introduction
Part 2: MVC application search with simple documents using autocomplete, jQuery and jTable
Part 3: MVC Elasticsearch CRUD with nested documents
Part 4: Data Transfer from MS SQL Server using Entity Framework to Elasticsearch
Part 5: MVC Elasticsearch with child, parent documents
Part 6: MVC application with Entity Framework and Elasticsearch
Part 7: Live Reindex in Elasticsearch
Part 8: CSV export using Elasticsearch and Web API
Part 9: Elasticsearch Parent, Child, Grandchild Documents and Routing
Part 10: Elasticsearch Type mappings with ElasticsearchCRUD
Part 11: Elasticsearch Synonym Analyzer using ElasticsearchCRUD
Part 12: Using Elasticsearch German Analyzer
Part 13: MVC google maps search using Elasticsearch
Part 14: Search Queries and Filters with ElasticsearchCRUD
Part 15: Elasticsearch Bulk Insert
Part 16: Elasticsearch Aggregations With ElasticsearchCRUD
Part 17: Searching Multiple Indices and Types in Elasticsearch
Part 18: MVC searching with Elasticsearch Highlighting
Part 19: Index Warmers with ElasticsearchCRUD

Before the search with the highlighting request can be sent to Elasticsearch, an index needs to be created. The FastestAnimal class is used for this.

public class FastestAnimal
{
	public long Id { get; set; }
	public string AnimalName { get; set; }
	public string Speed { get; set; }
	public string SpeedMph { get; set; }
	public string SpeedKmh { get; set; }
	public string Data { get; set; }
}

The CreateIndexWithDataIfItDoesNotExist is added to the global application Startup method. This is called every time the web application is started in IIS. The method checks if the index does not already exists.

var searchProvider = new SearchProvider();
searchProvider.CreateIndexWithDataIfItDoesNotExist();

If no index exists, a new index is created using the IndexCreate method. This creates per default a fastestanimals index and a fastestanimal type. This can be changed if required. Then some data is created and the index is filled with documents.

_context.IndexCreate<FastestAnimal>();

// create a animals list and add some items...

foreach (var animal in animals)
{
	_context.AddUpdateDocument(animal, animal.Id);
}

_context.SaveChanges();

The search method uses a Fuzzy Query to search for the data. The term is searched using the data field. The Highlight property is configured to highlight on the data field using custom pre and post tags. The class mycolor is used to style highlights. The method returns just the highlighted results. This could be changed to return the hit results as well or the Id so that a search link could be created.

public IEnumerable<string> Search(string searchTerm)
{
	var search = new Search
	{
		Query = new Query(new FuzzyQuery("data", searchTerm)),
		Highlight = new Highlight(
			new List<HighlightField>
			{
				new HighlightField("data")
				{
					PreTags= new List<string>{"<b class=\"mycolor\">"}, 
					PostTags = new List<string>{"</b>"}
				}
			})
	};
	
	var hits = _context.Search<FastestAnimal>(search, new SearchUrlParameters { Pretty = true });

	return hits.PayloadResult.Hits.HitsResult.Select(t => t.Highlights["data"].FirstOrDefault());
}

The MVC controller implements an action method which is called from the view. This method calls the search provider and returns the list as a Json array.

public JsonResult Search(string term)
{
	var searchResults = new SearchResults { Results = _searchProvider.Search(term).ToList() };
	return Json(searchResults.Results, "highlights", JsonRequestBehavior.AllowGet);
}

The view sends an ajax form post request to the MVC controller using jQuery.

<h3>Add your text and click enter for the fuzzy search in Elasticsearch with highlighting</h3>
<div class="row"> 
    <form id="termsearch" action="/home/search" method="post">
        <input id="termInput" name="termInput" type="text" style="width:500px" />
    </form>
</div>

<br/>

<div id="results">
    No results  
</div>

@section scripts
{
  
<script type="text/javascript">
    var frm = $('#termsearch');
    frm.submit(function (ev) {
        $.ajax({
            type: frm.attr('method'),
            url: frm.attr('action'),
            data: 'term=' + $("#termInput").val(),
            success: function (data) {
 
                var divItem = $("#results");
                divItem.empty();
                var arr = $.parseJSON(data);

                for (i = 0; i < arr.length; i++) {
                    $('<div/>', {
                        'html': arr[i] + '<br/><hr>'
                    }).appendTo(divItem);
                }
            }
        });

        ev.preventDefault();
    });
</script>
}

The request is sent to Elasticsearch as follows:

POST http://localhost:9200/fastestanimals/fastestanimal/_search?&pretty=true HTTP/1.1
Content-Type: application/json
Host: localhost:9200
Content-Length: 136
Expect: 100-continue

{
	"query": {
		"fuzzy": {
			"data": {
				"value": "mph"
			}
		}
	},
	"highlight": {
		"fields": {
			"data": {
				"pre_tags": ["<b class=\"mycolor\">"],
				"post_tags": ["</b>"]
			}
		}
	}
}

And the results are then displayed with the required highlighting.

ElHighlighting_01

Other search examples with highlighting can be found in the tests in ElasticsearchCRUD.

Links:

https://github.com/damienbod/ElasticsearchCRUD/blob/master/ElasticsearchCRUD.Integration.Test/SearchHighlightAndRescoreTests.cs

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-highlighting.html

http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/highlighting-intro.html

http://exploringelasticsearch.com/searching_a_book.html

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.