Build an Autocomplete widget with React and Elastic Search

RC
Bits and Pieces
Published in
5 min readSep 21, 2018

--

This post is a compilation of opinionated technical decisions related to building an auto-suggest search widget with the following requirements:

  1. Build a search bar to quickly search for a customer by first or last name or a unique short code.
  2. Should support type-ahead search with results being refined with more keystrokes
  3. Search should be possible by first, middle or last name or full name.
  4. If there are two or more customers with same name, order them by their created time with the most recent one at the top

There are two parts to building this Autocomplete widget. Let’s talk about the design for the backend first.

Tip: When working with React components, you can use Bit to easily organize and share components across projects and team members, and build faster.

ElasticSearch API

Though many of the RDBMs already support full-text search, we would prefer ElasticSearch essentially for its superior scoring algorithm and performance. There are two ways to build the ElasticSearch index to power our auto-suggest functionality:

  1. Completion Suggester

The completion suggester is a so-called prefix suggester. It does not do spell correction like the term or phrase suggesters but allows basic auto-complete functionality. If performance is the primary concern, it is recommended that you go with completion suggester.

2. Edge n-grams Tokenizer

Reading through our requirements, the results should show up even if the user types part of the middle of the customer’s name. This is not possible with completion suggester, so let’s use the NGram Tokenizer.

If the user types chandler or muriel or bing or chand bing we are suppose to return Chandler Muriel Bing as the result!

The edge_ngram tokenizer first breaks a name down into words whenever it encounters one of a list of specified characters, then it emits N-grams of each word where the start of the N-gram is anchored to the beginning of the word. This is perfect when the index will have to match when full or partial keywords from the name are entered.

If you are interested in spinning up a local docker image to boot up elastic search to play with the code in this blog, go here. The code here complies with ES v.6.4 which is the LTS version at the time of writing this blog.

Let’s go ahead and create our index with name and short_code fields:

PUT API to create new index (ElasticSearch v.6.4)

Read through the Edge NGram docs to know more about min_gram and max_gram parameters.

Also note that, we create a single field called fullName to merge the customer’s first and last names. Storing the name together as one field offers us a lot of flexibility in terms on analyzing as well querying.

Customer Data

Assuming we have the above customer data as sample, we can insert them into the Elastic Search index using the following command:

Repeat the above command for all customer records and we can start testing our index against our auto-suggest use cases:

Now, let’s start building our query API one step at a time.

The above query will return two records Ross and Monica. Let’s sort them by created date. But, we don’t want to skew order by only listing most recent items at the top pushing relevant results to bottom. So, the right way to do that would be sort by score and then relevancy

Remember for that for each record, based on the match query fired, elastic search assigns a _score based on relevancy of match and sorting by that gives us the most accurate search results.

Now, the last requirement to add to our implementation is to search by fullName as well as shortCode to make the query work for both input fields.

The multi_match query matches the given query keyword against both the fields and returns the result accordingly.

React UI for auto-suggesting

Let’s catch a quick glimpse of the UI widget that we are building so that it is easy for you to visualize and follow:

The main AutoComplete widget where the most of the action happens is listed below.

Quickly walking through the code:

  • we use react-autosuggest to make the core suggestion feature work
  • axios to make the REST api call to elastic search
  • as the user types, we would like to wait on keystrokes and then call elastic search to make the user experience smooth and not call the search api for every word cumulatively typed. We use debounce function onSuggestionFetchRequested function to achieve that
  • the renderSuggestion helper will allow you to design the search result items as you wish to show. We have included the customer’s name and short code in the result

The code for the complete UI project is available here for reference: https://github.com/rcdexta/react-autocomplete-demo

Note that the UI app and ElasticSearch are running on different ports, so by default you will get a CORS error on the browser. For the sake of testing and development, use the following docker command to bypass it:

$ docker run -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "http.cors.enabled=true" -e "http.cors.allow-origin=*" docker.elastic.co/elasticsearch/elasticsearch:6.4.0

If you find the blog post useful, follow this blog, follow me on Twitter and please feel free to comment and ask anything below! thanks :)

--

--

Full Stack Engineer @ Pro.com , Ex-ThoughtWorker • Ruby,JavaScript, iOS, Frontend, Devops https://rcdexta.com