Elasticsearch Suggesters with Chewy

Posted on 28 May 2015 by Eric Oestrich

We recently started migrating a page with filtering over to elasticsearch. One of the filtering options allows you to search for someone’s name, to make this a nicer experience we added autocompletion for that name. To help with this we used the chewy gem.

Before we get started, this is a prefix autocompletion. So if you search for compl it will suggest complete and not autocomplete.

PersonIndex
class PersonIndex < Chewey::Index
  define_type Person do
    field :first_name
    field :last_name
    field :name_autocomplete, {
      value: -> {
        {
          input: [first_name, last_name],
          output: full_name,
          context: {
            group_id: group.id,
          },
        }
      },
      type: "completion",
      context: {
        group_id: {
          type: "category",
        },
      },
    }
  end
end

First we need to set up the index. With chewy we define PersonIndex and fill in fields we want the index to have.

To create a completion field we give it a special value that contains the input to match against and the output elasticsearch will give after matching. We can also specify a context because we wanted to limit the completion to certain groupings and not suggest everything.

We also define type as completion and let elasticsearch know that this field has a context of group_id.

Suggestions
PersonIndex.suggest({
  suggest: {
    text: "Eri",
    completion: {
      field: "name_autocomplete",
      context: {
        group_id: group.id,
      },
    },
  },
}).suggest

In order to get suggestions out of elasticsearch we use the .suggest method off of the index. The top level key is required and can be anything you want. It will match up with the output key.

Inside the top level key you pass in the text you want to complete against along with what field and any context. Elasticsearch will return JSON similar to below:

Suggestion JSON
{
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "suggest": [
      {
         "text": "Eri",
         "offset": 0,
         "length": 3,
         "options": [
            {
               "text": "Eric Oestrich",
               "score": 1
            }
         ]
      }
   ]
}

The options array will contain any records that matched against your text. The text inside of options will be the output you specified when creating the value for that record.

If you don’t want to use chewy for suggestions, after setting up the index you can query elasticsearch with the _suggest route off of your index:

GET person/_suggest
{
  "suggest": {
    "text": "Eri",
    "completion": {
      "field": "name_autocomplete",
      "context": {
        "group_id": 1
      }
    }
  }
}
comments powered by Disqus
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.