Spring Data Elasticsearch,ACID 查询和部分更新

huangapple go评论91阅读模式
英文:

Spring Data Elasticsearch, ACID query and partial update

问题

我面临Spring Data和Elasticsearch的问题。我需要对实体执行查询和部分添加或更新操作,并最终确定是否已完成。

模型示例如下:

public class Entity{
  @Id private String id;
  private String country;
  private String city;
  private boolean completed;
  // 其他字段...
}

在我的应用程序中,有4个字段(例如countrycity)以异步方式到达(请注意随机顺序、竞争条件等)。

我需要填充completed字段,并在所有字段都设置为不完整时发送通知。

在SQL中,查询和修改的朴素实现是可行的,根据ID查询,设置字段,检查是否所有字段都填充,设置completed,然后在一个事务中保存实体(使用@Transactional)。

我如何使用Elasticsearch来处理这个问题?

我尝试设置一个CRUD操作的存储库,如下所示:

public interface EntityRepository extends ElasticsearchRepository<Entity, String> {
}

但这不会起作用,因为在查询、保存和更新之间,数据会发生变化,字段会变得不完整。

从搜索其他答案中,我看到也许可以使用ElasticsearchTemplate来执行部分更新,这似乎是一个更好的方法,例如,在city字段到达时仅更新它。

https://stackoverflow.com/questions/40742327/partial-update-with-spring-data-elasticsearch-repository

但是,我如何能够设置completed字段呢?稍后再查询吗?我认为这不会起作用。

假设我收到city,更新它,但在查询之前,country到达并设置,那么在这两次更新之后,查询都会带来一个已完成的entity,并发送两个通知,或者类似的情况。

英文:

I am facing a problem with Spring Data and Elasticsearch. I need to do a query and partial add or update to an entity and in the end figure out if its completed.

The model is a sample as below

public class Entity{
  @Id private String id;
  private String country;
  private String city
  private boolean completed;
  ....
}
  • 4 fields like country and city arrive asynchronously in my application. (beware of random order, race conditions, etc)
  • I need to fill the completed field and send a notification when all fields are set incomplete.

In SQL the naive implementation of query and modify is doable, query based on id, set the fields, check if all are filled, set the completed save the entity in one transaction @Transactional.

How can I approach this with Elasticsearch?

I tried setting a repository like below for CRUD operations

public interface EntityRepository
  extends ElasticsearchRepository&lt;Entity, String&gt; {
}

but this will not work, between query and save and update, the data changes and the fields are incomplete.

From search other answers I saw that maybe I could do a partial update using ElasticsearchTemplate which seems a a better approach, eg update only city field when it arrives

https://stackoverflow.com/questions/40742327/partial-update-with-spring-data-elasticsearch-repository

But how will I be able to set the completed field ? Query later? It will not work I believe.

Lets say I receive city, update it, but before query, the country arrives and is set, so after both updates, the queries will both bring a completed entity and send two notifications, or.. something like that

答案1

得分: 1

在Elasticsearch中,单文档操作是原子的,因此考虑到你所描述的情况

假设我收到城市信息并进行更新,但在查询之前,国家信息到达并设置,因此在两次更新之后,查询将带回一个已完成的实体并发送两个通知,或者类似这样的情况

你不必担心数据竞态问题,因为即使你异步执行两个更新操作如下:

POST /myindex/_update/id
{
    "enity" : {
       "city": "smth"
    }
}

POST /myindex/_update/id
{
    "enity" : {
       "country": "smth"
    }
}

它们不会存在竞态条件。

在每次更新后,ES索引只会处于两种状态之一:

  • 更新了一个字段
  • 更新了两个字段

因此,从索引查询将返回一致状态的实体。

现在考虑到这一点,在两次更新之后,只需添加一个按ID返回实体的查询,并进行设置标志和通知的检查:

Entity e = entityRepository.findById(id);
if (!e.isCompleted() && e.getCity() != null && e.getCountry() != null) {
  updateCompletedFlag(e);
  notifyAboutCompletion(e);
}
英文:

In Elasticsearch single-document operations are atomic, so considering the case you've described

> Lets say I receive city, update it, but before query, the country arrives and is set, so after both updates, the queries will both bring a completed entity and send two notifications, or.. something like that

you shouldn't worry about data races, because even if you asynchronously execute two updates as:

POST /myindex/_update/id
{
    &quot;enity&quot; : {
       &quot;city&quot;: &quot;smth&quot;
    }
}

and

POST /myindex/_update/id
{
    &quot;enity&quot; : {
       &quot;country&quot;: &quot;smth&quot;
    }
}

they won't be racy.

After each update ES index can be only in two states:

  • one field is updated
  • both fields are updated

So the query from index will return you the entity of consistent state.

Now having this in mind after both updates just add a query returning the entity by id and do the check for setting flag and notification

Entity e = entityRepository.findById(id);
if (!e.isCompleted() &amp;&amp; e.getCity() != null &amp;&amp; e.getCountry() != null) {
  updateCompletedFlag(e);
  notifyAboutCompletion(e);
}

huangapple
  • 本文由 发表于 2023年7月6日 16:49:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76627068.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定