我有一个关于使用弹簧数据的弹性搜索的问题。
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "my_es_index")
public class MyEsIndex {
private String id;
private Long counter;
private Long timestamp;
}
和存储库
public interface MyEsIndexRepository extends ElasticsearchRepository<MyEsIndex, String> {
Optional<MyEsIndex> findFirstByIdOrderByTimestampDesc(String id);
}
所以我有一个服务,我必须首先搜索前一个保存的记录以检索以前的值,始终按时间戳排序进行搜索。
@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);
}
}
以及尝试进行操作接收时{"error":{"root_cause":[{"type":"query_shard_exception","reason":"No mapping found for [timestamp] in order to sort on","index":"my_es_index"}
是否可以在空索引上对 Elasticsearch 中的字段进行初始化? 因为 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);
}
}
是否可以将此解决方案委托给 Spring?我没有找到任何
当使用 Spring Data Elasticsearch 存储库时 -就像你所做的那样 - 正常行为是在应用程序启动时创建索引后将映射写入 Elasticsearch,而索引尚不存在。
代码中的问题是,您没有定义实体的属性应映射到哪些类型;您需要添加@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;
}
未使用@Field
注释注释的属性不会写入映射,而是留给 Elasticsearch 自动映射,这就是排序不起作用的原因。由于没有写入索引的文档,Elasticsearch 不知道它是什么类型以及如何对其进行排序。
在您的代码中,还有另一件事可能与所需的应用程序逻辑不匹配。在Spring Data Elasticsearch中,实体需要有一个id属性,该属性将在Elasticsearch中用作文档的id。这通常是通过使用@Id
注释属性来定义的,如果缺少 - 就像您的情况一样 - 使用名称为"id"或"document"的属性。因此,在您的情况下,将使用属性id
。
文档的 id 在 Elasticsearch 中是唯一的,如果您将新文档存储在现有 ID 下,则之前的内容将被覆盖。如果这是您想要的,则应将@Id
注释添加到您的属性中,以明确这是唯一 id。但是在这种情况下,您的代码findFirstByIdOrderByTimestamp
没有意义,因为按 id 查找将始终最多返回一个文档,因此顺序无关紧要,您只需使用findById()
即可。我假设id
应该是唯一的,因为您使用 UUID 初始化它。
如果id
不是唯一的,并且有多个具有相同 ID 和不同时间戳的文档,则需要向实体添加新的唯一属性,并使用@Id
对其进行批注,以防止id
用作唯一标识符。