Reputation: 1764
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
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