Elasticsearch and spring data (optimistic locking)

141 Views Asked by At

I have a question about some automation implementation it via elastic spring boot data.

@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "super_test_index")
public class TestIndex {

    @Field(type = FieldType.Keyword)
    private String id;

    @Field(type = FieldType.Text)
    private String text;

    @CreatedDate
    private Instant createDate;

    @LastModifiedDate
    private Instant updateDate;

    @Version
    private Long indexVersion;
}

added repository

@Repository
public interface TestRepository extends ElasticsearchRepository<TestIndex, String> {
}

and implemented simple code

@Service
@RequiredArgsConstructor
public class TestService {

    private final TestRepository testRepository;


    public TestIndex save() {
        TestIndex testIndex = TestIndex.builder()
                .id(UUID.randomUUID().toString())
                .text("test")
                .build();
        return testRepository.save(testIndex);
    }

    public TestIndex update(String id, String text) {
        TestIndex testIndex = testRepository.findById(id).orElseThrow();
        testIndex.setText(text);
        return testRepository.save(testIndex);
    }

}

and call it via controller

@RestController
@RequiredArgsConstructor
public class TestController {

    private final TestService testService;


    @PostMapping("/api/test/save")
    public TestIndex save() {
        return testService.save();
    }

    @PostMapping("/api/test/update")
    public TestIndex update(@RequestParam("id") String id, @RequestParam("text") String text) {
        return testService.update(id, text);
    }

}

on create I got updated document

{
  "id": "9a16210a-3ab7-4d52-bcd2-ec87f46cc403",
  "text": "test",
  "createDate": null,
  "updateDate": null,
  "indexVersion": 1
}

but on updating it

  "exception": "Elasticsearch exception [type=version_conflict_engine_exception, reason=[9a16210a-3ab7-4d52-bcd2-ec87f46cc403]: version conflict, current version [1] is higher or equal to the one provided [1]]; nested exception is [super_test_index/e03tZCuoRzeJB2SpVQIefQ][[super_test_index][0]] ElasticsearchStatusException[Elasticsearch exception [type=version_conflict_engine_exception, reason=[9a16210a-3ab7-4d52-bcd2-ec87f46cc403]: version conflict, current version [1] is higher or equal to the one provided [1]]]"

receiving the error message. So I have a few questions:

  1. Is it event possible to configure optimistic locking via spring data elastic?
  2. How to configure creation date/updating date for the fields, or i have to do it manually?

I just found some information about i have to configure the version controlling like 'external version' but I didn't get it how to do it via spring boot. I did the same as for a jpa repositories/entities, but never done for elastic.

2

There are 2 best solutions below

1
P.J.Meisch On

how to do it via spring boot

Spring Data Elasticsearch is not Spring Boot.

The versioning management of an index can be defined with versionType property of the@Document annotation.

Note that the current version of the Elasticsearch documentation (https://www.elastic.co/guide/en/elasticsearch/reference/8.11/optimistic-concurrency-control.html) only describes optimistic locking using _seq_no and _primary_term (which is supported by Spring Data Elasticsearch as well). Using a version field was the previous way to do this, you might better migrate.

Another thing: Please annotate your id property with @Id instead of relying it to be detetced by the name, you can omit the @Field annotation on the id field then.

0
Yegor Saliev On

Found problem here How to fix ElasticSearch conflicts on the same key when two process writing at the same time , and the solution is just increment by yourself the version, spring data elastic can't do it "on fly"

  public TestIndex update(String id, String text) {
        TestIndex testIndex = testRepository.findById(id).orElseThrow();
        testIndex.setText(text);
        testIndex.setIndexVersion(testIndex.getIndexVersion() + 1);
        return testRepository.save(testIndex);
    }

elastic checking if version is upgraded, and throwing optimistic lock if it is less or equal current version [1] is higher or equal to the one provided [1] the message was a little bit confused with the equal, but now working well