Reputation: 552
I've been hitting the same problem with mappings on 6.4 over and over and I wonder what I've been doing wrong.
I'm simply creating a mapping to add to an index when creating it, but it always breaks my test with a java.lang.IllegalStateException: Failed to close the XContentBuilder
This is how I create the XContentBuilder object for my mapping
[UPDATE]: culprit spotted - mapping missing .endObject()
public XContentBuilder buildIndexMapping() throws IOException{
XContentBuilder mapping = XContentFactory.jsonBuilder()
.startObject()
.startObject("_doc")
.startObject("_routing")
.field( "required", true )
.endObject()
.startObject( "properties" )
.startObject( "launchCode" )
.field( "type", "text" )
.endObject()
.startObject( "tenant_id" )
.field("type", "keyword")
.endObject()
.startObject( "environment_id" )
.field( "type", "keyword" )
.endObject()
.startObject("app_id")
.field( "type", "keyword" )
.endObject() //Culprit
.startObject( "launch_id" )
.field( "type", "keyword" )
.endObject()
.startObject( "timestamp" )
.field( "type", "date" )
.endObject()
.startObject( "data" )
.startObject( "properties" )
.startObject( "changed" )
.field( "type", "boolean" )
.endObject()
.startObject( "census_groups" )
.field( "type", "object" )
.endObject()
.startObject( "local_member_id" )
.field( "type", "keyword" )
.endObject()
.startObject( "last_service_counter" )
.field( "type", "integer" )
.endObject()
.startObject( "last_election_counter" )
.field( "type", "integer" )
.endObject()
.startObject( "last_election_update_counter" )
.field( "type", "integer" )
.endObject()
.startObject( "last_membership_counter" )
.field( "type", "integer" )
.endObject()
.startObject( "last_service_config_counter" )
.field( "type", "integer" )
.endObject()
.startObject( "last_service_file_counter" )
.field( "type", "integer" )
.endObject()
.endObject() //properties
.endObject() //data
.endObject() //properties
.endObject() //doc
.endObject(); //root
return mapping;
}
And this is how I create the index request.
public CreateIndexRequest buildIndexRequest( String indexType, List<String> tenantList ) throws IOException{
SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" );
String date = format.format( new Date() );
String indexName = date + "-" + indexType;
CreateIndexRequest request = new CreateIndexRequest( indexName );
request.aliases( buildIndexAliases( tenantList, indexType ) );
request.settings( buildIndexSettings() );
request.mapping( "_doc", buildIndexMapping() ); //Test passes when commented out
return request;
}
And this is how I create the index.
public CreateIndexResponse createIndex( CreateIndexRequest request ){
CreateIndexResponse response = null;
try{
L.info( "Requesting creation of the index" );
response = client.indices().create( request, RequestOptions.DEFAULT );
if( response.isAcknowledged() ){
L.info( "Index created" );
}
else{
L.warn( "Index not created: request not acknowledged" );
}
}
catch( IOException e ){
L.error( "Could not create Index" );
}
return response;
}
And this is my unit test.
@Test
public void createIndexTest() {
try{
CreateIndexRequest request = client.buildIndexRequest( "census", this.tenantList );
CreateIndexResponse response = client.createIndex( request );
if (!response.isAcknowledged()) {
fail();
}
}
catch( IOException e ){
fail();
}
}
And this is the body of an index request that successfully creates the index with the mapping when using PUT /index
through Postman.
{
"aliases": {
"census-tenant-a": {
"filter": {
"term": {
"_routing": "tenant-a"
}
},
"index_routing": "tenant-a",
"search_routing": "tenant-a"
},
"census-tenant-b": {
"filter": {
"term": {
"_routing": "tenant-b"
}
},
"index_routing": "tenant-b",
"search_routing": "tenant-b"
},
"census-tenant-c": {
"filter": {
"term": {
"_routing": "tenant-c"
}
},
"index_routing": "tenant-c",
"search_routing": "tenant-c"
}
},
"mappings": {
"_doc": {
"_routing": {
"required": true
},
"properties": {
"launch_code": {
"type": "text"
},
"tenant_id": {
"type": "keyword"
},
"environment_id": {
"type": "keyword"
},
"app_id": {
"type": "keyword"
},
"launch_id": {
"type": "keyword"
},
"timestamp": {
"type": "date"
},
"data": {
"properties": {
"changed": {
"type": "boolean"
},
"census_groups": {
"type": "object"
},
"local_member_id": {
"type": "keyword"
},
"last_service_counter": {
"type": "integer"
},
"last_election_counter": {
"type": "integer"
},
"last_election_update_counter": {
"type": "integer"
},
"last_membership_counter": {
"type": "integer"
},
"last_service_config_counter": {
"type": "integer"
},
"last_service_file_counter": {
"type": "integer"
}
}
}
}
}
},
"settings": {
"index": {
"number_of_shards": "3",
"number_of_replicas": "1"
}
}
}
I really can't understand what is happening. I know the XContentBuilder
should be closed after used to avoid memory leaks.
However, I would like to get the index created first and later deal with the resource closure.
I am using the same logic to create aliases and settings, it only doesn't work with the mapping.
Moreover as mentioned, the JSON representation of my XContentBuilder
succeeds when I use the Index API with PUT /index
.
Thanks!
Upvotes: 0
Views: 1264
Reputation: 11
You probably want to end object started for "app_id" : startObject("app_id")
Upvotes: 1