Monthly Archives: April 2015

Typeahead.js, Elasticsearch and Rails!

Recently for a project I was required to take a list of keywords and make an auto suggest feature. Typically, this can be achieved through some simple but crude sql.

Since the project already required Elasticsearch, all the records were already neatly indexed for me. (minus the keywords) Additionally, the project was developed in Rails so I already had the benefit of the elasticsearch-rails project. With that in mind I got started…

Creating an Analyzer

The first step was to create an analyzer in Elasticsearch for our typeahead column. Creating new analyzers is pretty straightforward with the elasticsearch-rails gem. The “keyword” data we were getting was not checked for errors, so in our case we wanted the analyzer to lowercase everything to reduce the suggestions later. Example if there were searches for “Cats” and “cats” in our keywords we didn’t want to return two suggestions.

Creating a mapping

Now that the analyzer is setup, a mapping can be created. Within the mapping an index is created that uses the keyword info, but this is where it get’s kinda goofy. Elasticsearch wants this data to be structured in a hash with the key of “input” which in turn contains an array of the different keywords. See the example below for more details. The final thing to note is that the index is assigned our “typeahead” analyzer that was created above for both index analysis and search analysis.

Querying suggestions

Now that both the analyzer and mapping are setup, the data can be re-indexed and a query can be run. The following will run a “suggestion” query within the elasticsearch-rails gem. Note: the “text” key is the search term, while the “field” that is being searched on is the keyword_suggest field that was defined in the mapping above.

If all goes according to plan, our model should be returning keyword results in the format below…

Controller time

The controller to return json from the model is dead simple.

Displaying the results

Now that the controller is returning suggestions as json, it’s time to wire that up to a user interface. The project was using the popular Bootstrap framework. With version 2.3.2 there was a JavaScript plugin for typeahead functionality. However, this plugin has been removed as of 3.x in favor of using the typeahead.js library from twitter. It turns out, with a little effort typeahead isn’t that much more complicated to setup than the old bootstrap plugin.

First, an input tag is defined. Make sure that the autocomplete attribute is set to “off” so the native browser doesn’t kick in with it’s suggestions.

Typeahead.js uses an engine called bloodhound to make ajax calls as you type. It has some intelligent caching features and makes consuming that data pretty hands off. Once a new bloodhound object is created, the initialize() method must be called to finish the process.

Now that the bloodhound engine is setup, the input tag can be selected and typeahead will wire everything together. One thing to note, the “displayKey” setting is telling typeahead which key to use from our hash values within the array. In this case “text” is the key that should be used.

Going out with style

The last thing that I did was add a bit of custom styling to the typeahead box.

Overall I was pretty impressed by the solution. It look less than a couple hours to setup and was pretty fast and responsive. When considering a typeahead option for your next project give Elasticsearch a spin!