Gonfi den Tschal
Gonfi den Tschal

Reputation: 1764

Make ElasticSearch fail on configuration error

I'm playing with the current ES 2.3.4 from Java and it is silent on errors on my side. It's very difficult to track down the cause of problems.

QUESTION: How do I configure ES to be non-lenient, and fail early, instead of trying to do magic?


Case 1: creating an index with the Java API

A correct example is in the answers of Define custom ElasticSearch Analyzer using Java API and How to add analyzer settings in ElasticSearch?

Unfortunately I had an additional settings object around the analysis as in the question of the 2nd link.

Running the prepareCreate() doesn't mind, there's no error, just the acknowledgement.

Case 2: referencing an analyzer in a mapping that does not exist

In the same call to prepareCreate() I define my mappings. I define field("analyzer", "myanalyzer") which does not exist (since the boxing of objects was wrong) and again it does not mind.

The way I finally figured it out was by running a prepareSearch() with an explicit QueryBuilders.matchQuery("myfield", myvalue).analyzer("myanalyzer") and there it complained that there is no such analyzer.


Update 1

I'm still confused regarding the settings section. This example https://www.elastic.co/guide/en/elasticsearch/guide/current/ngrams-compound-words.html uses the settings section as a sibling of the mappings section, and does not directly start with the analysis section.

So I'm doing the same in Java and here is my exact code:

        xContentBuilder = XContentFactory.jsonBuilder().prettyPrint()
                .startObject() //root

                .startObject("settings")
                .startObject("analysis")
                .startObject("filter")
                .startObject("trigrams_filter").field("type", "ngram").field("min_gram", "3").field("max_gram", "3").endObject()
                .endObject() //filter
                .startObject("analyzer")
                .startObject("trigrams")
                    .field("type", "custom")
                    .field("tokenizer", "standard")
                    .field("filter", new String[]{"lowercase", "trigrams_filter"})
                .endObject()
                .endObject() //analyzer
                .endObject() //settings

                .startObject("mappings")
                .startObject(typeName)
                .startObject("properties")
                .startObject("myfield1").field("type", "string").field("analyzer", "trigrams").endObject()
                .endObject() //properties
                .endObject() //typeName
                .endObject() //mappings

                .endObject(); //root

I create the fresh index, and there is no failure callback, no abort:

    ListenableActionFuture<CreateIndexResponse> execute = this.node.client().admin().indices().prepareCreate(indexName)
            .setSettings(xContentBuilder)
            .execute();

    execute.addListener(new ActionListener<CreateIndexResponse>() {
        @Override
        public void onResponse(CreateIndexResponse createIndexResponse) {
            System.out.println(createIndexResponse);
        }

        @Override
        public void onFailure(Throwable e) {
            e.printStackTrace();
        }
    });

    CreateIndexResponse createIndexResponse = execute.actionGet();

Then I query, and this query goes through:

boolQuery.must(QueryBuilders.matchQuery("myfield1", parsedStreetName.getBase()));

Whereas this one does not:

boolQuery.must(QueryBuilders.matchQuery("myfield1", parsedStreetName.getBase()).analyzer("trigrams").minimumShouldMatch("40%"));

It says:

Caused by: [streetindex] QueryParsingException[[match] analyzer [trigrams] not found] at org.elasticsearch.index.query.MatchQueryParser.parse(MatchQueryParser.java:101)

If I leave out the settings start and end object then the trigrams analyzer gets created (search does not complain).

But:

I can create other invalid configuration, and it happily creates the index. An example:

        xContentBuilder = XContentFactory.jsonBuilder().prettyPrint()
                .startObject() //root

                .startObject("asdf")
                .startObject("nana")
                .startObject("foobar").field("dada", "dudu").endObject()
                .endObject()
                .endObject()

                .endObject(); //root

I also had a missing endObject() once and the code did not throw.

I'm confused.

Upvotes: 4

Views: 301

Answers (1)

Gonfi den Tschal
Gonfi den Tschal

Reputation: 1764

The correct Java API method for my use case is setSource(), not setSettings().

The Java code examples I had linked from SO only set settings, not also mappings at the same time. That's why those don't have the settings in the hierarchy.

The Javadoc of the setSource() method says:

Sets the settings and mappings as a single source.

So that's that. All clear now.

However, I really don't understand why the setSettings() accepts any kind of content.

Upvotes: 1

Related Questions