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:
- how do I make it fail?
- does the Java API differ here from the REST? Is that on purpose?
- search does not find anything with the trigrams.
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.