Search as you type with Java API


#1

2 Questions.

What is the equivalent of match_phrase_prefix in the Java API? I'm unable to find any classes that implement QueryBuilder that correspond to this?

I'm trying to set a custom analyzer for an index to also try search as you type during index time, but I'm having issues. I'm unable to change the analyzer setting for my index. Right now I'm giving it a json object with the settings, but it isn't going through. Could anyone provide an example on how to do it? I've copied this template: http://stackoverflow.com/questions/6275727/define-custom-elasticsearch-analyzer-using-java-api but it doesn't appear to work.

Thanks.


(Colin Goodheart-Smithe) #2

For Question 1:

Try this:

org.elasticsearch.index.query.QueryBuilders.matchPhrasePrefixQuery(String name, Object text)

Where name is the field name and text is query text (to be analyzed).

For Question 2:

Can you paste a code snippet of the exact code you are using? Also when you say:

What do you mean? Are you getting an error in the response or in the Elasticsearch logs? If so, what is this error?


#3

Thank you.

I'm creating an index like this. Using the settings from https://www.elastic.co/guide/en/elasticsearch/guide/current/_index_time_search_as_you_type.html

            client.admin().indices().prepareCreate(indexName)
                .setSettings(ImmutableSettings.settingsBuilder().loadFromSource(jsonBuilder()
                        .startObject()
                        .startObject("analysis")
                        .startObject("analyzer")
                        .startObject("autocomplete")
                        .field("type", "custom")
                        .field("tokenizer", "standard")
                        .field("filter", new String[]{"lowercase", "autocomplete_filter"})
                        .endObject()
                        .endObject()
                        .startObject("filter")
                        .startObject("autocomplete_filter")
                        .field("type", "edge_ngram")
                        .field("min_gram", "1")
                        .field("max_gram", "20")
                        .endObject()
                        .endObject()
                        .endObject()
                        .endObject().string()))
                .execute().actionGet();

Adding a document

        String json = "{" +
            "\"user\":\"kimchy\"," +
            "\"postDate\":\"2013-01-30\"," +
            "\"message\":\"trying out Elasticsearch\"" +
            "}";

    client.prepareIndex(indexName, "tweet", "1")
            .setSource(json)
            .execute()
            .actionGet();

And I check the tokens for the analyzer

    AnalyzeResponse analyzeResponse = client.admin().indices().prepareAnalyze("trying out").execute().actionGet();
    for (AnalyzeResponse.AnalyzeToken analyzeToken : analyzeResponse.getTokens()) {
        System.out.println(analyzeToken.getTerm());
    }

I'm expecting to receive
t
tr
try
tryi
tryin
trying
o
ou
out

but all I receive as tokens are "trying" and "out." I can't figure out how to setup the analyzer correctly.

I'm also wondering how I can do fuzzy queries with matchPhrasePrefixQuery. It seems like the fuzziness parameter doesn't work. Do I have to modify the search analyzer such that for every letter typed it tokenizes the current token with some degree of fuzziness?
Or would it be better to break down the words at index time using the above analyzer and use a fuzzy multimatchquery?

Thanks again for the help!


(Colin Goodheart-Smithe) #4

Have you set the field(s) in your mapping to use the analyzer autocomplete?

In your analyze code you haven't specified the analyzer to use so it will use the standard analyzer. try the following

    AnalyzeResponse analyzeResponse = client.admin().indices().prepareAnalyze("trying out").setAnalyzer("autocomplete").execute().actionGet();
    for (AnalyzeResponse.AnalyzeToken analyzeToken : analyzeResponse.getTokens()) {
        System.out.println(analyzeToken.getTerm());
    }

#5

That seemed to work. Thanks.

Is there a way to map it to all fields and types in the index by default?


(Colin Goodheart-Smithe) #6

Take a look at: https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-root-object-type.html#_dynamic_templates

You can use dynamic templates in your mapping to set rules for fields so based on the fields name pattern and/or type it gets a particular mapping


#7

Thank you for the help, but I was unable to get that working.

What I'm doing at the moment is

           client.admin().indices().preparePutMapping(indexName)
                //set all the types in the index to adhere to this mapping, "_default_"
                .setType("_default_")
                .setSource(jsonBuilder()

                        //apply analyzer to all fields in the type. This is deprecated
                        .startObject()
                        .field("index_analyzer", "autocomplete")
                        .field("search_analyzer", "standard")
                        .endObject())

But I am reading that doing it like this is deprecated.

I tried this but was unable to get it to work. Could anything go wrong with using that specific deprecated feature? For all intents and purposes, it's working fine at the moment.

            client.admin().indices().preparePutMapping(indexName)
                //set all the types in the index to adhere to this mapping, "_default_"
                .setType("_default_")
                .setSource(jsonBuilder()

                                                            .startObject()
                                                            .startObject("dynamic_templates")
                                                            .startArray()
                                                            .startObject("template1")
                                                            .startObject()
                                                            .field("match", "*")
                                                            .startObject("mapping")
                                                            .field("type", "string")
                                                            .field("index_analyzer", "autocomplete")
                                                            .field("search_analyzer", "standard")
                                                            .endObject()
                                                            .endObject()
                                                            .endObject()
                                                            .endArray()
                                                            .endObject()
                                                            .endObject())

(Colin Goodheart-Smithe) #8

The documentation indicates that the body of the request should start with the type name. Try this instead:

client.admin().indices().preparePutMapping(indexName)
                //set all the types in the index to adhere to this mapping, "_default_"
                .setType("_default_")
                .setSource(jsonBuilder()

                                                            .startObject()
                                                            .startObject("_default_")
                                                            .startObject("dynamic_templates")
                                                            .startArray()
                                                            .startObject("template1")
                                                            .startObject()
                                                            .field("match", "*")
                                                            .startObject("mapping")
                                                            .field("type", "string")
                                                            .field("index_analyzer", "autocomplete")
                                                            .field("search_analyzer", "standard")
                                                            .endObject()
                                                            .endObject()
                                                            .endObject()
                                                            .endArray()
                                                            .endObject()
                                                            .endObject()
                                                            .endObject())

(system) #9