Search code examples
elasticsearchelasticsearch-5search-suggestion

Get an output different from input with elasticsearch completion suggester


I recently upgraded from Elasticsearch 1.4 to 5.4 and I'm struggling to migrate my autocomplete queries efficiently. The problem is that I want to have a completion suggester where the output is different from the input.

The documents I store have a field for categories which is basically an array of strings with their URIs (because they form a tree). The last part of the URI, I call it label, is the input in the completion suggester, but as a response I would like to retrieve the full URI.

So let's say I have two documents:

{
    "name" : "Lord of The Rings",
    "categories" : ["Books/Genre/Fantasy", "Books/Language/English"]
}

and

{
    "name" : "Game of Thrones",
    "categories" : ["Series/Genre/Fantasy", "Series/Host/HBO"]
}

My input is "Fant" and I want to get as a response the URIs for the "Series/Genre/Fantasy" and "Books/Genre/Fantasy" categories.

Previously with ES 1.4, I was able to create a completion suggester with a different output for a given input, so I indexed my suggesters like this:

{
    "suggest" : {
        "input": [ "Fantasy"],
        "output": "Series/Genre/Fantasy"
    }
}

and

{
    "suggest" : {
        "input": [ "Fantasy"],
        "output": "Books/Genre/Fantasy"
    }
}

But in ES 5.4, the output property doesn't exist anymore for completion suggesters so all I get in the response is the input property of my suggest field, which is the label "Fantasy", but I want the URI.

Right now, my workaround is to look for the categories field of each document returned in the _source property of the response, and filter on the categories that have a label starting with the input "Fant". It is very inefficient since I need to map every category of every returned document into its label to check with the input.

Isn't there a more efficient way to do that with ES suggesters? What am I missing?


Solution

  • Elasticsearch's completion suggester have been changed from 5.0. The support for specifying output when indexing suggestion entries has been removed. Now suggestion result entry’s text is always the un-analyzed value of the suggestion’s input (same as not specifying output while indexing suggestions in pre-5.0 indices). So you need to add output as a sibling field of suggest key in the body.
    Here's how it should look like:

    Mapping:

    {
        "mappings": {
            "<type>" : {
                "properties" : {
                    "suggest" : {
                        "type" : "completion"
                    },
                    "output" : {
                        "type": "keyword"
                    }
                } 
            }
        }
    }
    

    Don't forget to replace <type> with your index type.

    Indexing:

    /<index_name>/<type_name>
    
    {
        "suggest" : {
            "input": ["Fantasy"],
            "weight" : 1
        },
        "output": "Series/Genre/Fantasy"
    }
    

    Here, the field name output can be replaced by anything, it's just meta-data of your document.

    Query:

    /<index_name>/_search
    
    {
        "suggest": {
            "show-suggest" : {
                "prefix" : "Fant",
                "completion" : {
                    "field" : "suggest"
                }
            }
        }
    }
    

    I hope this helps.