Adding mapping to a type from Java - how do I do it? Adding mapping to a type from Java - how do I do it? elasticsearch elasticsearch

Adding mapping to a type from Java - how do I do it?


Finally a day of googling paid off. Frankly the Java API docs for elasticsearch could use some end-to-end examples, not to mention JavaDoc...

Here's a running example. You must have a node running on localhost for this to work!

package foo;import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;import java.io.IOException;import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;import org.elasticsearch.action.get.GetRequestBuilder;import org.elasticsearch.action.get.GetResponse;import org.elasticsearch.action.index.IndexRequestBuilder;import org.elasticsearch.client.Client;import org.elasticsearch.client.transport.TransportClient;import org.elasticsearch.common.settings.ImmutableSettings;import org.elasticsearch.common.transport.InetSocketTransportAddress;import org.elasticsearch.common.xcontent.XContentBuilder;public class MyTestClass {    private static final String ID_NOT_FOUND = "<ID NOT FOUND>";    private static Client getClient() {        final ImmutableSettings.Builder settings = ImmutableSettings.settingsBuilder();        TransportClient transportClient = new TransportClient(settings);        transportClient = transportClient.addTransportAddress(new InetSocketTransportAddress("localhost", 9300));        return transportClient;    }    public static void main(final String[] args) throws IOException, InterruptedException {        final Client client = getClient();        // Create Index and set settings and mappings        final String indexName = "test";        final String documentType = "tweet";        final String documentId = "1";        final String fieldName = "foo";        final String value = "bar";        final IndicesExistsResponse res = client.admin().indices().prepareExists(indexName).execute().actionGet();        if (res.isExists()) {            final DeleteIndexRequestBuilder delIdx = client.admin().indices().prepareDelete(indexName);            delIdx.execute().actionGet();        }        final CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName);        // MAPPING GOES HERE        final XContentBuilder mappingBuilder = jsonBuilder().startObject().startObject(documentType)                .startObject("_ttl").field("enabled", "true").field("default", "1s").endObject().endObject()                .endObject();        System.out.println(mappingBuilder.string());        createIndexRequestBuilder.addMapping(documentType, mappingBuilder);        // MAPPING DONE        createIndexRequestBuilder.execute().actionGet();        // Add documents        final IndexRequestBuilder indexRequestBuilder = client.prepareIndex(indexName, documentType, documentId);        // build json object        final XContentBuilder contentBuilder = jsonBuilder().startObject().prettyPrint();        contentBuilder.field(fieldName, value);        indexRequestBuilder.setSource(contentBuilder);        indexRequestBuilder.execute().actionGet();        // Get document        System.out.println(getValue(client, indexName, documentType, documentId, fieldName));        int idx = 0;        while (true) {            Thread.sleep(10000L);            idx++;            System.out.println(idx * 10 + " seconds passed");            final String name = getValue(client, indexName, documentType, documentId, fieldName);            if (ID_NOT_FOUND.equals(name)) {                break;            } else {                // Try again                System.out.println(name);            }        }        System.out.println("Document was garbage collected");    }    protected static String getValue(final Client client, final String indexName, final String documentType,            final String documentId, final String fieldName) {        final GetRequestBuilder getRequestBuilder = client.prepareGet(indexName, documentType, documentId);        getRequestBuilder.setFields(new String[] { fieldName });        final GetResponse response2 = getRequestBuilder.execute().actionGet();        if (response2.isExists()) {            final String name = response2.getField(fieldName).getValue().toString();            return name;        } else {            return ID_NOT_FOUND;        }    }}


I am actually going to add another answer here because frankly speaking, the above answers gave a start to my implementation but didn't answer the actual question 100% (updating not just the root level properties, but the ACTUAL field/properties). Took me almost 2 days to figure this out (Documentation is a bit light for ES Java APIs). My "Mapping" class is not 100% yet, but more fields could be added to it ("format" etc) later.

I hope this helps everyone else who is trying to use update mappings!

GET/RETRIEVE MAPPINGS

ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> indexMappings = response.getMappings();                    ImmutableOpenMap<String, MappingMetaData> typeMappings = indexMappings.get(indexName);                    MappingMetaData mapping = typeMappings.get(type);                    Map<String, Mapping> mappingAsMap = new HashMap<>();                    try {                        Object properties = mapping.sourceAsMap().get("properties");                        mappingAsMap = (Map<String, Mapping>) gson.fromJson(gson.toJson(properties), _elasticsearch_type_mapping_map_type);                        return mappingAsMap;                    }

UPDATE MAPPINGS

PutMappingRequest mappingRequest = new PutMappingRequest(indexName);            Map<String, Object> properties = new HashMap<>();            Map<String, Object> mappingsMap = (Map<String, Object>) gson.fromJson(gson.toJson(mapping), Json._obj_map_type);            properties.put("properties", mappingsMap);            mappingRequest = mappingRequest.ignoreConflicts(true).type(type).source(properties).actionGet();

My GSON mapping types

public static final Type _obj_map_type = new TypeToken<LinkedHashMap<String, Object>>(){}.getType();public static final Type _elasticsearch_type_mapping_map_type = new TypeToken<LinkedHashMap<String, Mapping>>(){}.getType();

My Mapping Class

public class Mapping {    private String type;    private String index;    private String analyzer;    public String getType() {        return type;    }    public void setType(String type) {        this.type = type;    }    public String getIndex() {        return index;    }    public void setIndex(String index) {        this.index = index;    }    public String getAnalyzer() {        return analyzer;    }    public void setAnalyzer(String analyzer) {        this.analyzer = analyzer;    }}


An alternative solution would be to use a feature called dynamic templates. The idea is very well described within this article http://joelabrahamsson.com/dynamic-mappings-and-dates-in-elasticsearch/

So this case uses a regular expression declaring any field that starts with tikaprop_ to be of type String.

curl -XPUT "http://localhost:9200/myindex" -d'    {       "mappings": {          "_default_": {             "date_detection": true,             "dynamic_templates": [                {                   "tikaprops": {                      "match": "tikaprop_.*",                      "match_pattern": "regex",                      "mapping": {                         "type": "string"                      }                   }                }             ]          }       }    }'

or if you'd rather prefer to do it via the Elasticsearch Java API

CreateIndexRequestBuilder cirb = this.client.admin().indices().prepareCreate(INDEX_NAME).addMapping("_default_", getIndexFieldMapping());CreateIndexResponse createIndexResponse = cirb.execute().actionGet();private String getIndexFieldMapping() {return IOUtils.toString(getClass().getClassLoader().getResourceAsStream("elasticsearch_dynamic_templates_config.json"));}

with elasticsearch_dynamic_templates_config.json beein:

{     "date_detection": true,     "dynamic_templates": [        {           "tikaprops": {              "match": "tikaprop_.*",              "match_pattern": "regex",              "mapping": {                 "type": "string"              }           }        }     ]   }