Reputation: 12205
I'm trying to create two documents, one build a child of the other, using the Elastic Search Java API.
My code looks something like this:
public void createRecord(Road road, Car car) throws Exception{
ObjectMapper objectMapper = new ObjectMapper();
String roadJson = objectMapper.writeValueAsString(road);
String carJson = objectMapper.writeValueAsString(car);
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
IndexResponse response = client.prepareIndex("myIndex", "roadType").setSource(roadJson).get();
client.prepareIndex("myIndex", "carType").setParent(response.getId()).setSource(carJson).get();
}
This code successfully creates a road document but when it goes to create a car document I get the error:
java.lang.IllegalArgumentException: Can't specify parent if no parent field has been configured
How can I properly create two Elastic documents that form a parent / child relationship with the ES Java API?
Upvotes: 3
Views: 3992
Reputation: 12205
I had to create a custom mapper for the parent / child relationship. This still preserves the dynamic mapping that can happen on document creation.
public void createRecord(Road road, Car car) throws Exception{
ObjectMapper objectMapper = new ObjectMapper();
String roadJson = objectMapper.writeValueAsString(road);
String carJson = objectMapper.writeValueAsString(car);
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
if(!client.admin().indices().prepareExists("myIndex").get().isExists()){
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject().startObject("roadType").endObject().endObject();
XContentBuilder xContentBuilder2 = XContentFactory.jsonBuilder().startObject().startObject("carType").startObject("_parent").field("type", "roadType").endObject().endObject().endObject();
client.admin().indices().create(new CreateIndexRequest("myIndex")).get();
client.admin().indices().preparePutMapping("myIndex").setType("carType").setSource(xContentBuilder2).get();
client.admin().indices().preparePutMapping("myIndex").setType("roadType").setSource(xContentBuilder).get();
}
IndexResponse response = client.prepareIndex("myIndex", "roadType").setSource(roadJson).get();
client.prepareIndex("myIndex", "carType").setParent(response.getId()).setSource(carJson).get();
}
This creates a custom mapper that sets up the parent child relationship between roadType and carType while still allowing you to dynamically map additional properties. Make sure you add the child mapping first or it won't work.
Upvotes: 0
Reputation: 3041
It looks like you are not configuring your "carType" mapping to specify "roadType" as a parent.
"mappings": {
"roadType": {
"properties": {
}
},
"carType": {
"_parent": {
"type": "roadType"
},
"properties": {
"make": {
"type": "string"
},
"model": {
"type": "string"
}
}
}
}
For more info, see here: https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child-mapping.html
Upvotes: 2