2

I'm using elasticsearch and spring in my application. For each index type, I have a document mapping. Using @Document annotation I have specified the indexName and type of index. For eg: @Document(indexName = "myproject", type = "user"). But for writing unit tests, I would want to create indexes with a different indexName. Hence I want the indexName to be read from a properties file. How to do this in spring?

coder
  • 1,901
  • 5
  • 29
  • 44
  • I could not find an elegant solution for this. As a workaround, I just created a test class which extended the user class and specified the indexName for this test class separately. – coder Jul 04 '14 at 02:43

2 Answers2

0

You can solve this problem by just using SPeL. It allows you to set a expression that Spring will parse at compile time. Hence allowing the Annotations to be processed during the compilation.

@Document(collection = "#{@environment.getProperty('index.access-log')}")
public class AccessLog{
    ...
}

Before Spring 5.x:

Note that there is no @ in the SPeL.

@Document(collection = "#{environment.getProperty('index.access-log')}")
public class AccessLog{
    ...
}

Also I found that Spring also supports a much simpler Expression @Document(collection = "${index.access-log}") but I had mixed results with this.

After setting up the annotation as above you can use either

application.properties

index.access-log=index_access

or application.yaml

index  :
  access : index_access
-2

Just use ElasticSearchTemplate from your unit tests to create the index with a different name and then use the method "index" or "bulkIndex" to index a document into the new index you just created.

    esTemplate.createIndex(newIndexName, loadfromFromFile(settingsFileName));
    esTemplate.putMapping(newIndexName, "user", loadfromFromFile(userMappingFileName));

    List<IndexQuery> indexes = users.parallelStream().map(user -> {
        IndexQuery index = new IndexQuery();
        index.setIndexName(newIndexName);
        index.setType("user");
        index.setObject(user);
        index.setId(String.valueOf(user.getId()));
        return index;
    }).collect(Collectors.toList());
    esTemplate.bulkIndex(indexes);

    //Load file from src/java/resources or /src/test/resources
    public String loadfromFromFile(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();
    }

This should work as its working for me. Same scenario.

Thiago
  • 5,152
  • 11
  • 35
  • 44
  • Does your answer mean "just don't use the @Document annotation" or does it mean something else ? – Tristan Jul 22 '16 at 13:15
  • @Tristan correct. Dont use the Document annotation. – Thiago Jul 22 '16 at 16:39
  • Well, I think u should check : http://stackoverflow.com/questions/33069670/spring-data-elasticsearch-document-indexname-defined-at-runtime/38530650#38530650 – Tristan Jul 23 '16 at 08:06