最新的稳定版本请使用 Spring Data Elasticsearch 5.3.1! |
最新的稳定版本请使用 Spring Data Elasticsearch 5.3.1! |
Spring Data Elasticsearch 支持脚本字段和运行时字段。 有关详细信息,请参阅有关脚本 (www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html) 和运行时字段 (www.elastic.co/guide/en/elasticsearch/reference/8.9/runtime.html) 的 Elasticsearch 文档。 在 Spring Data Elasticsearch 的上下文中,您可以使用
-
脚本化字段,用于返回在结果文档上计算并添加到返回文档中的字段。
-
在存储的文档上计算的运行时字段,可在查询中使用和/或在搜索结果中返回。
以下代码片段将显示您可以执行的操作(这些代码片段显示命令式代码,但响应式实现的工作方式类似)。
人员实体
这些示例中使用的 enity 是一个实体。
此实体具有 和 属性。
虽然出生日期是固定的,但年龄取决于发出查询的时间,需要动态计算。Person
birthDate
age
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.lang.Nullable;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
import java.lang.Integer;
@Document(indexName = "persons")
public record Person(
@Id
@Nullable
String id,
@Field(type = Text)
String lastName,
@Field(type = Text)
String firstName,
@Field(type = Keyword)
String gender,
@Field(type = Date, format = DateFormat.basic_date)
LocalDate birthDate,
@Nullable
@ScriptedField Integer age (1)
) {
public Person(String id,String lastName, String firstName, String gender, String birthDate) {
this(id, (2)
lastName,
firstName,
LocalDate.parse(birthDate, DateTimeFormatter.ISO_LOCAL_DATE),
gender,
null);
}
}
1 | 该属性将被计算并填写在搜索结果中。age |
2 | 用于设置测试数据的便捷构造函数。 |
请注意,该属性用 .
这将禁止在索引映射中写入相应的条目,并将属性标记为目标,以便从搜索响应中放置计算字段。age
@ScriptedField
1 | 该属性将被计算并填写在搜索结果中。age |
2 | 用于设置测试数据的便捷构造函数。 |
存储库接口
此示例中使用的存储库:
public interface PersonRepository extends ElasticsearchRepository<Person, String> {
SearchHits<Person> findAllBy(ScriptedField scriptedField);
SearchHits<Person> findByGenderAndAgeLessThanEqual(String gender, Integer age, RuntimeField runtimeField);
}
服务类
服务类注入了一个存储库和一个实例,用于显示填充和使用该属性的几种方法。
我们将代码分成不同的部分来说明ElasticsearchOperations
age
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.RuntimeField;
import org.springframework.data.elasticsearch.core.query.ScriptData;
import org.springframework.data.elasticsearch.core.query.ScriptType;
import org.springframework.data.elasticsearch.core.query.ScriptedField;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class PersonService {
private final ElasticsearchOperations operations;
private final PersonRepository repository;
public PersonService(ElasticsearchOperations operations, SaRPersonRepository repository) {
this.operations = operations;
this.repository = repository;
}
public void save() { (1)
List<Person> persons = List.of(
new Person("1", "Smith", "Mary", "f", "1987-05-03"),
new Person("2", "Smith", "Joshua", "m", "1982-11-17"),
new Person("3", "Smith", "Joanna", "f", "2018-03-27"),
new Person("4", "Smith", "Alex", "m", "2020-08-01"),
new Person("5", "McNeill", "Fiona", "f", "1989-04-07"),
new Person("6", "McNeill", "Michael", "m", "1984-10-20"),
new Person("7", "McNeill", "Geraldine", "f", "2020-03-02"),
new Person("8", "McNeill", "Patrick", "m", "2022-07-04"));
repository.saveAll(persons);
}
1 | 一种在 Elasticsearch 中存储某些数据的实用程序方法。 |
脚本字段
下一篇文章展示了如何使用脚本字段来计算和返回人员的年龄。 脚本字段只能向返回的数据添加某些内容,不能在查询中使用 age(请参阅运行时字段)。
public SearchHits<Person> findAllWithAge() {
var scriptedField = ScriptedField.of("age", (1)
ScriptData.of(b -> b
.withType(ScriptType.INLINE)
.withScript("""
Instant currentDate = Instant.ofEpochMilli(new Date().getTime());
Instant startDate = doc['birth-date'].value.toInstant();
return (ChronoUnit.DAYS.between(startDate, currentDate) / 365);
""")));
// version 1: use a direct query
var query = new StringQuery("""
{ "match_all": {} }
""");
query.addScriptedField(scriptedField); (2)
query.addSourceFilter(FetchSourceFilter.of(b -> b.withIncludes("*"))); (3)
var result1 = operations.search(query, Person.class); (4)
// version 2: use the repository
var result2 = repository.findAllBy(scriptedField); (5)
return result1;
}
1 | 定义计算一个人的年龄。ScriptedField |
2 | 使用 时,将脚本字段添加到查询中。Query |
3 | 将脚本字段添加到 时,还需要一个额外的源过滤器来从文档源中检索普通字段。Query |
4 | 获取实体现在在其属性中设置了值的数据。Person age |
5 | 使用存储库时,只需将脚本字段添加为方法参数即可。 |
运行时字段
使用运行时字段时,可以在查询本身中使用计算值。 在下面的代码中,这用于对给定的性别和最大年龄的人运行查询:
public SearchHits<Person> findWithGenderAndMaxAge(String gender, Integer maxAge) {
var runtimeField = new RuntimeField("age", "long", """ (1)
Instant currentDate = Instant.ofEpochMilli(new Date().getTime());
Instant startDate = doc['birth-date'].value.toInstant();
emit (ChronoUnit.DAYS.between(startDate, currentDate) / 365);
""");
// variant 1 : use a direct query
var query = CriteriaQuery.builder(Criteria
.where("gender").is(gender)
.and("age").lessThanEqual(maxAge))
.withRuntimeFields(List.of(runtimeField)) (2)
.withFields("age") (3)
.withSourceFilter(FetchSourceFilter.of(b -> b.withIncludes("*"))) (4)
.build();
var result1 = operations.search(query, Person.class); (5)
// variant 2: use the repository (6)
var result2 = repository.findByGenderAndAgeLessThanEqual(gender, maxAge, runtimeField);
return result1;
}
}
1 | 定义用于计算人员年龄的运行时字段。有关内置属性,请参阅 asciidoctor.org/docs/user-manual/#builtin-attributes。 |
2 | 使用 时,添加运行时字段。Query |
3 | 将脚本化字段添加到 时,需要额外的字段参数才能返回计算值。Query |
4 | 将脚本字段添加到 时,还需要一个额外的源过滤器来从文档源中检索普通字段。Query |
5 | 获取使用查询筛选的数据,以及返回的 entites 设置了 age 属性的位置。 |
6 | 使用存储库时,只需将运行时字段添加为方法参数即可。 |
除了在查询上定义运行时字段外,还可以通过将批注的属性设置为指向包含运行时字段定义的 JSON 文件,在索引中定义这些字段。runtimeFieldsPath
@Mapping
1 | 一种在 Elasticsearch 中存储某些数据的实用程序方法。 |
1 | 定义计算一个人的年龄。ScriptedField |
2 | 使用 时,将脚本字段添加到查询中。Query |
3 | 将脚本字段添加到 时,还需要一个额外的源过滤器来从文档源中检索普通字段。Query |
4 | 获取实体现在在其属性中设置了值的数据。Person age |
5 | 使用存储库时,只需将脚本字段添加为方法参数即可。 |
1 | 定义用于计算人员年龄的运行时字段。有关内置属性,请参阅 asciidoctor.org/docs/user-manual/#builtin-attributes。 |
2 | 使用 时,添加运行时字段。Query |
3 | 将脚本化字段添加到 时,需要额外的字段参数才能返回计算值。Query |
4 | 将脚本字段添加到 时,还需要一个额外的源过滤器来从文档源中检索普通字段。Query |
5 | 获取使用查询筛选的数据,以及返回的 entites 设置了 age 属性的位置。 |
6 | 使用存储库时,只需将运行时字段添加为方法参数即可。 |