Tom_Mahy
(Tom Mahy)
March 25, 2016, 4:15pm
1
Hello,
I am unable to ingest content in an object field with the java client 2.2.0.
Please note that i have the same problem for nested objects but for String/long/arrays etc, it all works
Field creation
mappingSource
.startObject(ElasticLibrary.TYPE_CONTENT)
.startObject("properties")
.startObject("part")
.field(TYPE, TYPE_STRING)
.endObject()
.startObject("name")
.field(TYPE, TYPE_STRING)
.endObject()
.endObject()
.endObject();
The mapping is created fine.
This is how i try to ingest :
contentBuilder = XContentFactory.jsonBuilder();
contentBuilder.startObject().prettyPrint();
contentBuilder.field(ElasticLibrary.TYPE_CONTENT, new Content(text));
contentBuilder.endObject().prettyPrint().humanReadable(true);
indexRequestBuilder.setSource(contentBuilder);
indexRequestBuilder.execute().actionGet();
My content object :
public class Content implements Serializable{
private String part;
private String name;
If i run this i will get the error
org.elasticsearch.index.mapper.MapperParsingException: object mapping for [CONTENT] tried to parse field [CONTENT] as object, but found a concrete value
Does anyone know why i am getting this error ?
Thank you.
Looks to me like you're mapping a type, "content", with string properties "part" and "name", but then constructing an instance of Content by passing a single parameter called "text". Don't know what the single arg c'tor of your Content class does. Also don't know what the expected values for content.part and content.name would be, if all you have is "text".
I think what you want to do is something like
contentBuilder = XContentFactory.jsonBuilder()
.startObject().prettyPrint()
.startObject("content").field("part", part).field("name", name).endObject()
.endObject().prettyPrint().humanReadable(true);
indexRequestBuilder.setSource(contentBuilder);
indexRequestBuilder.execute().actionGet();
but, again, I can't tell from where the values for "part" and "name" should come.
Tom_Mahy
(Tom Mahy)
March 29, 2016, 8:00am
3
If i remove the type specification i get the following error
Caused by: MapperParsingException[No type specified for field [name]]
Here is a sample application that will reproduce the problem
private static String INDICE = "test";
private static String DOCUMENT_TYPE = "doc";
private static String FIELD_NAME = "content";
public static void main(String[] args) throws IOException {
Builder builder = Settings.builder().put("cluster.name", "elastic");
TransportClient transportClient = TransportClient.builder().settings(builder).build();
transportClient.addTransportAddress(new InetSocketTransportAddress(Inet4Address.getByName("localhost"), 9300));
Client client = (Client) transportClient;
IndicesAdminClient indicesAdminClient = client.admin().indices();
IndicesExistsRequest indicesExistsRequest = new IndicesExistsRequest(INDICE);
IndicesExistsResponse indicesExistsResponse = indicesAdminClient.exists(indicesExistsRequest).actionGet();
if (!indicesExistsResponse.isExists()) {
CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices()
.prepareCreate(INDICE).addMapping(DOCUMENT_TYPE, getDefaultMapping());
createIndexRequestBuilder.execute().actionGet();
}
IndexRequestBuilder indexRequestBuilder = client.prepareIndex(INDICE, DOCUMENT_TYPE, UUID.randomUUID().toString());
XContentBuilder contentBuilder = null;
contentBuilder = XContentFactory.jsonBuilder();
contentBuilder.startObject().prettyPrint();
contentBuilder.field(FIELD_NAME, new Content("This is my name", "This is the part"));
contentBuilder.endObject().prettyPrint().humanReadable(true);
indexRequestBuilder.setSource(contentBuilder);
indexRequestBuilder.execute().actionGet();
}
private static XContentBuilder getDefaultMapping() throws IOException {
XContentBuilder mappingSource = XContentFactory.jsonBuilder();
mappingSource.startObject().startObject("properties");
mappingSource
.startObject(FIELD_NAME)
.startObject("properties")
.startObject("part")
.field("type", "String")
.endObject()
.startObject("name")
.field("type", "String")
.endObject()
.endObject()
.endObject();
mappingSource.endObject().endObject().prettyPrint();
return mappingSource;
}
And the content object
public class Content {
String name;
String part;
public Content(String name, String part) {
this.name = name;
this.part = part;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPart() {
return part;
}
public void setPart(String part) {
this.part = part;
}
}
Tom_Mahy
(Tom Mahy)
March 29, 2016, 8:11am
4
A quick look at the request shows that the content is
index {[test][doc][e04cc5f2-9b62-4543-94e5-25d0e6dc54b8], source[{
"content" : "org.elastic.elasticnested.Content@191cb49e"
}]}
So i decided to try to convert to JSON before passing it to the builder, this is the request
index {[test][doc][b6931a80-045f-4527-a0ca-b0bcf7d5925f], source[{
"content" : "{"name":"This is my name","part":"This is the part"}"
}]}
It still considered the content as a String.
Tom_Mahy
(Tom Mahy)
March 29, 2016, 8:19am
5
Found it by creating a map
Map<String, Object> map = new HashMap<>();
map.put("name", "This is my name");
map.put("part", "This is the part");
contentBuilder.field(FIELD_NAME, map);
Result
{
"took": 10,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "4b96664b-146a-45ad-99b6-e8e229d8de7c",
"_score": 1,
"_source": {
"content": {
"name": "This is my name",
"part": "This is the part"
}
}
}
]
}
}
Is there not a way to do this by passing the object directly ?
dadoonet
(David Pilato)
March 29, 2016, 8:35am
6
I don't understand why you can't just use the startObject helper as I showed.