Relevant Tags Only
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:
- it's awfully slow
- 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 .