11

I have a few elasticsearch fields that I don't want to analyze before indexing. I have read that the right way to do this is by altering the index mapping. Right now my mapping looks like this:

{
  "test" : {
   "general" : {
      "properties" : {
        "message" : {
          "type" : "string"
        },
        "source" : {
          "type" : "string"
        }
      }
    }
  }
}

And I would like it to look like this:

{
  "test" : {
   "general" : {
      "properties" : {
        "message" : {
          "type" : "string",
          "index" : "not_analyzed"
        },
        "source" : {
          "type" : "string"
        }
      }
    }
  }
}

I have been trying to change the settings via

client.admin().indices().prepareCreate("test")
        .setSettings(getGrantSettings());

Where getGrantSettings() looks like:

static Settings getGrantSettings(){
    JSONObject settingSource = new JSONObject();
    try{
        settingSource.put("mapping", new JSONObject()
        .put("message", new JSONObject()
            .put("type", "string")
            .put("index", "not_analyzed")
        ));
    } catch (JSONException e){
        e.printStackTrace();
    }


    Settings set = ImmutableSettings.settingsBuilder()
            .loadFromSource(settingSource.toString()).build();
    return set;
}
user3618259
  • 121
  • 1
  • 1
  • 3

4 Answers4

20

I have successfully applied mappings to an Elasticsearch index using the Java API like the following:

 XContentBuilder mapping = jsonBuilder()
                              .startObject()
                                   .startObject("general")
                                        .startObject("properties")
                                            .startObject("message")
                                                .field("type", "string")
                                                .field("index", "not_analyzed")
                                             .endObject()
                                             .startObject("source")
                                                .field("type","string")
                                             .endObject()
                                        .endObject()
                                    .endObject()
                                 .endObject();

  PutMappingResponse putMappingResponse = client.admin().indices()
                .preparePutMapping("test")
                .setType("general")
                .setSource(mapping)
                .execute().actionGet();

Hope this helps.

Paige Cook
  • 22,415
  • 3
  • 57
  • 68
  • 3
    Just to clarify: jsonBuilder() is a static method in org.elasticsearch.common.xcontent.XContentFactory – padilo Jan 15 '15 at 12:54
  • 1
    add this line if your index does not exists before mapping client.admin().indices().create(new CreateIndexRequest("indexname")).actionGet(); prior to applying mapping otherwise indexMissingException will be thrown – swaheed Jun 17 '15 at 12:08
11

Adding this for future readers. Please note you need to perform mapping prior to create the actual index or you will get an exception. See following code.

client.admin().indices().create(new CreateIndexRequest("indexname")).actionGet();

PutMappingResponse putMappingResponse = client.admin().indices()
    .preparePutMapping("indexname")
    .setType("indextype")
    .setSource(jsonBuilder().prettyPrint()
                .startObject()
                    .startObject("indextype")
                        .startObject("properties")
                            .startObject("country").field("type", "string").field("index", "not_analyzed").endObject()
                        .endObject()
                    .endObject()
                .endObject())
    .execute().actionGet();

IndexResponse response1 = client.prepareIndex("indexname", "indextype")
    .setSource(buildIndex())
    .execute()
    .actionGet();   

// Now "Sri Lanka" considered to be a single country :) 
SearchResponse response = client.prepareSearch("indexname"
    ).addAggregation(AggregationBuilders.terms("countryfacet").field("country")).setSize(30).execute().actionGet(); 
Charith De Silva
  • 3,650
  • 4
  • 43
  • 47
  • thanks alot i was getting the indexmissingexception after following the code provided in the accepted answer this line client.admin().indices().create(new CreateIndexRequest("indexname")).actionGet(); solved my problem – swaheed Jun 17 '15 at 12:06
0

Just read the Definitive Guide carefully:

Although you can add to an existing mapping, you can’t change existing field mappings. If a mapping already exists for a field, data from that field has probably been indexed. If you were to change the field mapping, the indexed data would be wrong and would not be properly searchable.

Source: https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping-intro.html#updating-a-mapping

So you just have to do it when you create the field. Thats why the code from this answer works without problems.

Community
  • 1
  • 1
neun24
  • 222
  • 2
  • 10
0

So, turns out elasticsearch docs are way outdated on that topic. not_analyzed does not exist anymore and string is now text. After some trial and error I came up with this:

CreateIndexRequest createIndexRequest = new CreateIndexRequest("yourIndexName");
XContentBuilder mapping = jsonBuilder()
                .startObject()
                  .startObject("properties")
                    .startObject("yourProperty")
                      .field("type", "keyword")
                    .endObject()
                  .endObject()
                .endObject();
createIndexRequest.mapping("yourEntityName", mapping);
client.indices().create(createIndexRequest);

Now yourProperty can be queried for exact value only with term query.

bAZtARd
  • 22
  • 1
  • 5