14

I have a use case where in need to create the indices per month in Elasticsearch. The idea is to create indices on the monthly bases so that they are easy to maintain and can be deleted when expired.For this to achieve i have used the spring-batch and have a monthly job which will create the indices on monthly bases For Elasticsearch-Java integration I have used the Spring-Data Elasticsearch implementation. The problem which i am facing now is, I am not able to figure out how to provide the dynamic-name to the index and mapping using the Entity object. My Current implementation is done keeping the Single Index in mind. Please find the below code which i am using to create indices

elasticsearchTemplate.createIndex(SingleChat.class);
elasticsearchTemplate.putMapping(SingleChat.class);
elasticsearchTemplate.refresh(SingleChat.class, true);

And SingleChat is my Entity Class

@Document(indexName="singlemsgtemp_#{jobParameters['MONTH']}",type="singlechat")
public class SingleChat {
    @org.springframework.data.annotation.Id
    String Id;
    @Field(type = FieldType.String)
    String conservationId;
    @Field(type = FieldType.String)
    String from;
    @Field(type = FieldType.String)
    String to;
    @Field(type = FieldType.String)
    String msgContent; 
    @Field(type = FieldType.String)
    String sessionId;
    @Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true, format = DateFormat.date_hour_minute_second_millis)
    Date postedDate;
    @Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true, format = DateFormat.date_hour_minute_second_millis)
    Date expireDate;
}   

But this is not working as expected. I am trying out some other things also. But i am open for suggestion. Also feel free to comment on my current approach, will it work or not. Please let me know if any more details are required.

sagar27
  • 3,121
  • 3
  • 27
  • 37

2 Answers2

10

What I am doing in my project , we are storing index name and type name in DB whenever it gets changed .

Now i m getting index and type Dynamically in this manner:

First Solution

  • 1)In configuration file ,create a Bean returning a value for someProperty . Here I injected the somePropertyValue with @Value annotation from DB or property file :-

    @Value("${config.somePropertyValue}")
    private String somePropertyValue;
    
    @Bean
    public String somePropertyValue(){
        return somePropertyValue;
    }
    
  • 2)After this , it is possible to inject the somePropertyValue into the @Document annotation like this :-

    @Document(index = "#{@somePropertyValue}")
    public class Foobar {
        //...
    }
    

Second Solution

  • 1) create getter setter in bean :-

    @Component
    public class config{
         @Value("${config.somePropertyValue}")
         private String somePropertyValue;
    
         public String getSomePropertyValue() {
           return somePropertyValue;
         }
        public void setSomePropertyValue(String somePropertyValue) {
           this.somePropertyValue = somePropertyValue;
        }
    }
    
  • 2)After this , it is possible to inject the somePropertyValue into the @Document annotation like this :-

    @Document(index = "#{config.somePropertyValue}")
    public class Foobar {
        //...
    }
    
Tony
  • 5,972
  • 2
  • 39
  • 58
Vijay
  • 4,694
  • 1
  • 30
  • 38
  • I had to add `spring-data-commons` into my project in order to use `org.springframework.data.spel.ExpressionDependencies`. This is not included in `spring-data-elasticsearch` – nonNumericalFloat Jan 25 '22 at 15:59
5

What I am doing on my application is that I use ElasticSearchTemplate to create my dynamic index name and then I point an alias to the new index I have created and then drop the old one.

esTemplate.createIndex(newIndexName, loadfromFromFile(settingsFileName));
esTemplate.putMapping(newIndexName, "MYTYPE", loadfromFromFile(mappingFileName));

I'm not using the mapping and settings from my class since I need it to be dynamic.

    protected String loadFromFile(String fileName) throws IllegalStateException {
       StringBuilder buffer = new StringBuilder(2048);
       try {
           InputStream is = getClass().getResourceAsStream(fileName);
           LineNumberReader reader = new LineNumberReader(new InputStreamReader(is));
           while (reader.ready()) {
               buffer.append(reader.readLine());
               buffer.append(' ');
           }
       } catch (Exception e) {
           throw new IllegalStateException("couldn't load file " + fileName, e);
       }
       return buffer.toString();
   }
Thiago
  • 5,152
  • 11
  • 35
  • 44
  • Thanks Thiago for reply, I will try out this one. Just to confirm loadFromFile(mapping/setting) will return String in JSON format right ? And also can u please share the code snippet for adding the Index to Alias. I am trying that using AliasQueryBuild and AliasQuery are you using the same thing or is there some other way to it. – sagar27 Nov 25 '15 at 04:04
  • @sagar27 the method is there now. – Thiago Nov 25 '15 at 04:50
  • That worked for me, Passing the JSON mapping file instead of the Model object. Also fetching the data using Alias is working as of now. Thanks Thiago. – sagar27 Nov 26 '15 at 10:08
  • @Thiago so I can define `@Document` annotation upon my entity without property `indexName`? Are there any configuration problems with this approach? – andPat Jan 15 '16 at 08:57
  • you can, you just dont have to use it. I did not experience any configuration problem – Thiago Jan 21 '16 at 19:38
  • Can I ask you smth? How do you load the json file? Which method is that? Could you update your post with it? – Carlos Vázquez Losada Feb 01 '18 at 20:12