2

I am trying to use the Elasticsearch Java API to dynamically create mappings. This is important because I don't want to have to change compiled code to change the mapping.

Almost all of the examples out there are using XContentBuilder to do this, but I want to use a JSON string from a file.

Code:

client.admin().indices().preparePutMapping(indexName)
    .setType("test")
    .setSource(indexMapping)
    .execute().actionGet();

File String:

{
"test": {
    "dynamic": "strict",
    "_id": {
        "path": "id"
    },
    "properties": {
        "address": {
            "index_analyzer": "ip4-pattern-analyzer",
            "store": true,
            "type": "string",
            "fields": {
                "raw": {
                    "index": "not_analyzed",
                    "type": "string"
                }
            }
        }
    }
}

}

Error thrown from Elasticsearch PutMappingRequest.class:

failed to generate simplified mapping definition

The same JSON defined using XContentbuilder works perfectly.

String type = "test";
XContentBuilder jb = XContentFactory.jsonBuilder().
      startObject().
         startObject(type).
            field("dynamic", "strict").
            startObject("_id").
                 field("path", "id").
            endObject().
            startObject("_all").
                 field("enabled", "true").
            endObject().
            startObject("properties").
                 startObject("address").
                    field("type", "string").
                    field("store", "yes"). 
                    field("index_analyzer", "ip4-pattern-analyzer").
                    startObject("fields").
                        startObject("raw").
                            field("type","string").
                            field("index","not_analyzed").
                        endObject().
                    endObject().
                 endObject().
            endObject().
        endObject().
    endObject();

3 Answers 3

2

Try something like the following:

in applicationContext.xml have something like:

<bean id="indexMapping" class="org.apache.commons.io.IOUtils" factory-method="toString">
        <constructor-arg value="classpath:test.json" type="java.io.InputStream" />
</bean>

and then you could do

   @Autowired
    private String indexMapping;
    .
    .

to apply the mapping during index creation try:

CreateIndexResponse indexResponse = admin.prepareCreate(indexName).setSource(indexMapping).execute().actionGet();

if you want to apply the mapping after then try:

PutMappingRequest putRequest = new PutMappingRequest(indexName); 
    putRequest.source(indexMapping); 
    putRequest.type("test"); 
    try {
        PutMappingResponse response = admin.putMapping(putRequest).actionGet(); 

    } catch (Exception e) {
        log.warn("Failed to add mapping", e);
        throw new RuntimeException(e);
    }
Sign up to request clarification or add additional context in comments.

4 Comments

Are you suggesting that I have to create the mapping at the time the index is created? The issue is the json string/format is throwing an error.
yep that is what the above does
That is not the issue. Adding the mapping after the index is created works if you use XContentBuilder.
Thanks for the comments, but I don't think you understand the issue. Mapping using a string fails with error "failed to generate simplified mapping definition". Same mapping created using XContentBuilder is successful.
2

I couldn't ever get it to work using anything other than an XContentBuilder. I decided to convert the json to a map using Jackson, then map the object using the XContentFactory.jsonBuilder(). I then pass the XContentBuilder directly to the putMapping call.

public static XContentBuilder builderFromJson(String json) throws JsonParseException, JsonMappingException, IOException{
    Map<String, Object> map = new ObjectMapper().readValue(json, new TypeReference<Map<String, Object>>(){});
    return XContentFactory.jsonBuilder().map(map);
}

1 Comment

Did you find any concrete work around apart from above solution?
1

You could use Jackson Library for this. This example makes use of elasticsearchTemplate. For example:

ObjectMapper mapper = new ObjectMapper();
    URL url = this.getClass().getResource("/yourmapping.json");
    JsonNode tree = mapper.readTree(new File(url.getFile()));
    elasticsearchTemplate.putMapping("index_name", "index_type", tree.toString());

and maven dependency:

    ...
     <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>LATEST</version>
    </dependency>
    ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.