Relevant Tags Only

Spatialized founder Jozef Sorocin
Jozef Soročin
Book a consultation ↗
7 min read  •  Updated 07/13/2025

An interesting application of partial text matching is an autocomplete with a dropdown:

Courtesy of Ant Design

People are unlikely to input the whole tag and will want only the tags that contain their input. These days we even expect auto-correct and natural language understanding but that's a topic for a different chapter — maybe even a whole new (hand)book 😉 .

Each of my documents contains an array of tags:

{
  ...
  "tags": ["Race", "Racing", "Mountain Bike", "Horizontal"],
  ...
},
{
  ...
  "tags": ["Tracey Chapman", "Silverfish", "Blue"],
  ...
},
{
  ...
  "tags": ["Surfing", "Race", "Disgrace"],
  ...
}

If the user types race, I only want to return Race, Tracey Chapman, and Disgrace — i.e. only the tags that contain my query string. What's more, I want this to be as fast as possible because it's fed through an autocomplete.

Since there's no dedicated array data type in ES, we'll apply a simple keyword mapping:

PUT tags_index
{
  "mappings": {
    "properties": {
      "tags": {
        "type": "keyword"
      }
    }
  }
}

and then index the above docs:

POST tags_index/_doc
{"tags":["Race","Racing","Mountain Bike","Horizontal"]}

POST tags_index/_doc
{"tags":["Tracey Chapman","Silverfish","Blue"]}

POST tags_index/_doc
{"tags":["Surfing","Race","Disgrace"]}

Now, extracting and grouping the contents of textual arrays is usually done through a terms aggregation :

POST tags_index/_search
{
  "size": 0,
  "aggs": {
    "topics": {
      "terms": {
        "field": "tags",
        "size": 10
      }
    }
  }
}

This'll give us all tags separately. But we want to filter them and luckily, there's the include parameter which supports regex :

POST tags_index/_search
{
  "size": 0,
  "aggs": {
    "topics": {
      "terms": {
        "field": "tags",
        "include": ".*[Rr][Aa][Cc][Ee].*",
        "size": 10
      }
    }
  }
}

There are two problems with this regex-based approach though:

  1. it's awfully slow
  2. and, more importantly, the regex needs to be dynamically constructed at query time.

That's suboptimal.

To mitigate all this complexity we could take a look at the wildcard field type . But it's only available through the X-Pack paid subscription and is better suited for querying much "longer" strings like logs .

Join 200+ developers who've mastered this! Get Lifetime Access — $5
Already a member? Sign in here