Search code examples
spring-dataspring-data-elasticsearch

ElasticsearchRestTemplate can't save multiple documents to different index


I have a test domain class

public class TestDocument {

    private final String id;

    private final String strField;

    private final Integer intField;

    public TestDocument(final String id, final String strField, final Integer intField) {
        this.id = id;
        this.strField = strField;
        this.intField = intField;
    }


}

now I invoke ElasticsearchRestTemplate.save method with 3 documents and want to save into 3 different indices.

@Service
public class TestEsService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @PostConstruct
    public void testSave() {
        final TestDocument d1 = new TestDocument("id_1", "str1", 1);
        final TestDocument d2 = new TestDocument("id_2", "str2", 2);
        final TestDocument d3 = new TestDocument("id_3", "str3", 3);

        this.save(List.of(d1, d2, d3));
    }

    public void save(final List<TestDocument> documents) {

        final IndexCoordinates indexCoordinates = IndexCoordinates.of("index_1", "index_2", "index_3");
       
        this.elasticsearchRestTemplate.save(documents, indexCoordinates);

    }

}

After executed above code. I check my local elasticsearch. curl -H 'Content-Type: application/json' 'http://localhost:9200/_cat/indices?pretty' -s

I got only one index in my ES. yellow open index_1 17ppJ9vJRUGIVHYBKKxXog 1 1 3 0 5.5kb 5.5kb

and check the data of this index_1 index:

curl 'http://localhost:9200/index_1/_search?pretty'
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "index_1",
        "_type" : "_doc",
        "_id" : "id_1",
        "_score" : 1.0,
        "_source" : {
          "_class" : "com.test.entity.TestDocument",
          "id" : "id_1",
          "strField" : "str1",
          "intField" : 1
        }
      },
      {
        "_index" : "index_1",
        "_type" : "_doc",
        "_id" : "id_2",
        "_score" : 1.0,
        "_source" : {
          "_class" : "com.test.entity.TestDocument",
          "id" : "id_2",
          "strField" : "str2",
          "intField" : 2
        }
      },
      {
        "_index" : "index_1",
        "_type" : "_doc",
        "_id" : "id_3",
        "_score" : 1.0,
        "_source" : {
          "_class" : "com.test.entity.TestDocument",
          "id" : "id_3",
          "strField" : "str3",
          "intField" : 3
        }
      }
    ]
  }
}

after dive into the code:

I found a clue within RequestFactory.bulkRequest:

queries.forEach(query -> {

            if (query instanceof IndexQuery) {
                bulkRequest.add(indexRequest((IndexQuery) query, index));
            } else if (query instanceof UpdateQuery) {
                bulkRequest.add(updateRequest((UpdateQuery) query, index));
            }
        });

actually IndexRequest() gets index name via index.getIndexName(); method:

public IndexRequest indexRequest(IndexQuery query, IndexCoordinates index) {

        String indexName = index.getIndexName();
        IndexRequest indexRequest;

where IndexCoordinates.getIndexName() return the first index name only.


    public String getIndexName() {
        return indexNames[0];
    }

Is it a bug? Should I report to spring-data-elasticsearch Github issue?


Solution

  • Multiple names in IndexCoordinates are used when accessing an Elasticsearch API that uses multiple index names, for example when searching data in multiple indices, but not for writing access.

    If you want to save the 3 entities to 3 indices, you need 3 calls with different IndexCoordinates - each of these having one index name.