简体   繁体   English

具有空索引的 Elasticsearch 和 spring 数据

[英]Elasticsearch and spring data with empty index

I have a question about elasticsearch with spring data.我有一个关于 elasticsearch with spring data 的问题。

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "my_es_index")
public class MyEsIndex {

    private String id;

    private Long counter;

    private Long timestamp;
}

and repository和存储库

public interface MyEsIndexRepository extends ElasticsearchRepository<MyEsIndex, String> {

    Optional<MyEsIndex> findFirstByIdOrderByTimestampDesc(String id);
}

so I have a service where I have to search first for previous one saved record to retrieve previous value, always doing search ordered by timestamp.所以我有一项服务,我必须首先搜索以前保存的记录以检索以前的值,总是按时间戳顺序进行搜索。

@Service
@RequiredArgsConstructor
public class MyEsService {

private final MyEsIndexRepository repository;

  public MyEsIndex insert(String previousId) {
    Long previousCounter = 
repository.findFirstByIdOrderByTimestampDesc(previousId).map(MyEsIndex::getCounter).orElse(0L);
    var index = new MyEsIndex(UUID.randomUUID().toString(), ++previousCounter, 
    Instant.now().toEpochMilli());
    return repository.save(index);
  }
}

and when trying to do the operation receiving {"error":{"root_cause":[{"type":"query_shard_exception","reason":"No mapping found for [timestamp] in order to sort on","index":"my_es_index"}并且在尝试执行接收操作时{"error":{"root_cause":[{"type":"query_shard_exception","reason":"No mapping found for [timestamp] in order to sort on","index":"my_es_index"}

is it possible to do initialization for fields in elasticsearch on empty index?是否可以在空索引上对 elasticsearch 中的字段进行初始化? because the solution of init config is not that clear because it will be used only once when starting working with empty index where never saved a record因为 init config 的解决方案不是那么清楚,因为它只会在开始使用从未保存记录的空索引时使用一次

@Configuration
public class InitElasticsearchConfig {

private final MyEsIndexRepository repository;

  @EventListener(ApplicationReadyEvent.class)
  public void initIndex() {
  if (repository.findAll(PageRequest.of(0, 1)).isEmpty()) {
    var initIndex = new MyEsIndex("initId", 0L, 0L);
    repository.save(initIndex);
    repository.delete(initIndex);
  }
}

is it possible to delegate this solution to spring?是否可以将此解决方案委托给 spring? I didn't find any我没找到

When using Spring Data Elasticsearch repositories - as you do - the normal behaviour is that the mapping is written to Elasticsearch after index creation on application startup when the index does not yet exist.当使用 Spring Data Elasticsearch 存储库时 - 正如您所做的那样 - 正常行为是在索引尚不存在时在应用程序启动时创建索引后将映射写入 Elasticsearch。

The problem in your code is that you do not define to what types the properties of your entity should be mapped;您的代码中的问题是您没有定义实体的属性应该映射到什么类型; you need to add @Field annotations to do that:你需要添加@Field注释来做到这一点:

@Document(indexName = "my_es_index")
public class MyEsIndex {

    private String id;

    @Field(type = FieldType.Long)
    private Long counter;

    @Field(type = FieldType.Long)
    private Long timestamp;
}

Properties that are not annotated with a @Field annotation are not written to the mapping but left for automatic mapping by Elasticsearch, that's the cause for the sort not working.未使用@Field注释进行注释的属性不会写入映射,而是留给 Elasticsearch 自动映射,这就是排序不起作用的原因。 As there is no document written to the index, Elasticsearch does not know what type it is and how to sort on that.由于没有文档写入索引,Elasticsearch 不知道它是什么类型以及如何对其进行排序。

In your code there is another thing that might probably not match your desired application logic.在您的代码中还有另一件事可能与您所需的应用程序逻辑不匹配。 In Spring Data Elasticsearch an entity needs to have an id property, that's the property that will be used as the document's id in Elasticsearch.在 Spring Data Elasticsearch 中,一个实体需要有一个id属性,该属性将在 Elasticsearch 中用作文档的 id。 This is normally defined by annotating the property with @Id , if that is missing - as in your case - a property with the name of "id" or "document" is used.这通常是通过使用@Id注释属性来定义的,如果缺少 - 就像您的情况一样 - 使用名称为“id”或“document”的属性。 So in your case the property id is used.因此,在您的情况下,使用了属性id

A document's id is unique in Elasticsearch, if you store a new document under an existing id, the previous content will be overwritten.一个文档的id在Elasticsearch中是唯一的,如果你用一个已有的id存储一个新的文档,之前的内容将被覆盖。 If that's what you want, the you should add the @Id annotation to your property to make it clear that this is the unique id.如果那是您想要的,您应该将@Id注释添加到您的属性以明确这是唯一的 ID。 But in this case then your code findFirstByIdOrderByTimestamp does not make sense, as a find by id will always return at most one document, so the order by is irrelevant, you could just use a findById() then.但是在这种情况下,您的代码findFirstByIdOrderByTimestamp没有意义,因为按 id 查找将始终返回最多一个文档,因此顺序无关紧要,您可以只使用findById()然后。 I assume that the id should be unique as you initialize it with a UUID.我假设id在您使用 UUID 初始化它时应该是唯一的。

If your id is not unique and you have multiple documents with the same id and different timestamps, the you'll need to add a new unique property to your entity and annotate that with @Id to prevent id to be used as a unique identifier.如果您的id不是唯一的,并且您有多个具有相同 id 和不同时间戳的文档,则您需要向您的实体添加一个新的唯一属性并使用@Id对其进行注释以防止将id用作唯一标识符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM