原题目:Spring 认证中国教育管理中心 -Spring Data Elasticsearch 教程六(Spring 中国教育管理中心)
Spring Data Elasticsearch 教程六
- 路由值
当 Elasticsearch 将文档存储在具备多个分片的索引中时,它会依据文档的 id 确定要应用的分片。有时须要事后定义多个文档应该在同一个分片上建设索引(连贯类型,更快地搜寻相干数据)。为此,Elasticsearch 提供了定义路由的可能性,这是应该用于计算分片而不是 id 的值。
Spring Data Elasticsearch 反对通过以下形式存储和检索数据的路由定义:
12.1. 连贯类型的路由
当应用 join-types(见 Join-Type implementation)时,Spring Data Elasticsearch 将主动应用 parent 实体属性的 JoinField 属性作为路由的值。
这对于父子关系只有一个级别的所有用例都是正确的。如果它更深一些,比方孩子 - 父母 - 祖父母的关系——就像下面的例子中的投票→答复→问题——那么须要应用下一节中形容的技术来明确指定路由(投票须要 question.id 作为路由值)。
12.2. 自定义路由值
为了为实体定义自定义路由,Spring Data Elasticsearch 提供了一个 @Routing 注解(重用 Statement 下面的类):
@Document(indexName = “statements”)
@Routing(“routing”)
public class Statement {
@Id
private String id;
@Field(type = FieldType.Text)
private String text;
@JoinTypeRelations(
relations =
{@JoinTypeRelation(parent = "question", children = {"answer", "comment"}),
@JoinTypeRelation(parent = "answer", children = "vote")
}
)
private JoinField<String> relation;
@Nullable
@Field(type = FieldType.Keyword)
private String routing;
// getter/setter...
}
这将“路由”定义为路由标准
一个名为 routing 的属性
Spring Data Elasticsearch 教程六
如果 routing 注解的标准是纯字符串而不是 SpEL 表达式,则将其解释为实体的属性名称,在示例中为路由属性。而后,此属性的值将用作应用该实体的所有申请的路由值。
咱们也能够在 @Document 正文中应用 SpEL 表达式,如下所示:
@Document(indexName = “statements”)
@Routing(“@myBean.getRouting(#entity)”)
public class Statement{
// all the needed stuff
}
在这种状况下,用户须要提供一个名称为 myBean 且具备办法的 bean String getRouting(Object)。援用实体“#entity”必须在 SpEL 表达式中应用,并且返回值必须是 null 或路由值作为 String。
如果一般属性的名称和 SpEL 表达式不足以自定义路由定义,则能够定义提供 RoutingResolver 接口的实现。而后能够在 ElasticOperations 实例上设置:
RoutingResolver resolver = …;
ElasticsearchOperations customOperations= operations.withRouting(resolver);
这些函数返回带有自定义路由集 withRouting()的原始实例的正本。ElasticsearchOperations
当实体存储在 Elasticsearch 中时,如果在实体上定义了路由,则在执行获取或删除操作时必须提供雷同的值。对于不应用实体的办法 – 比方 get(ID)或 delete(ID)
-ElasticsearchOperations.withRouting(RoutingResolver)能够像这样应用该办法:
String id = “someId”;
String routing = “theRoutingValue”;
// get an entity
Statement s = operations
.withRouting(RoutingResolver.just(routing))
.get(id, Statement.class);
// delete an entity
operations.withRouting(RoutingResolver.just(routing)).delete(id);
RoutingResolver.just(s) 返回一个解析器,它只返回给定的字符串。
- 其余 Elasticsearch 操作反对
本章介绍了对无奈通过存储库接口间接拜访的 Elasticsearch 操作的额定反对。倡议将这些操作增加为自定义实现,如 Spring Data Repositories 的自定义实现中所述。
13.1. 索引设置
应用 Spring Data Elasticsearch 创立 Elasticsearch 索引时,能够应用 @Setting 正文定义不同的索引设置。能够应用以下参数:
useServerConfiguration 不发送任何设置参数,因而 Elasticsearch 服务器配置确定它们。
settingPath 指的是一个 JSON 文件,它定义了必须在类门路中解析的设置
shards 要应用的分片数,默认为 1
replicas 正本数,默认为 1
refreshIntervall, 默认为 ”1s”
indexStoreType, 默认为 ”fs”
也能够定义索引排序(查看链接的 Elasticsearch 文档以理解可能的字段类型和值):
@Document(indexName = “entities”)
@Setting(
sortFields = {“secondField”, “firstField”},
sortModes = {Setting.SortMode.max, Setting.SortMode.min},
sortOrders = {Setting.SortOrder.desc, Setting.SortOrder.asc},
sortMissingValues = {Setting.SortMissing._last, Setting.SortMissing._first})
class Entity {
@Nullable
@Id private String id;
@Nullable
@Field(name = "first_field", type = FieldType.Keyword)
private String firstField;
@Nullable @Field(name = "second_field", type = FieldType.Keyword)
private String secondField;
// getter and setter...
}
定义排序字段时,应用 Java 属性的名称 (firstField),而不是可能为 Elasticsearch 定义的名称 (first_field)
sortModes,sortOrders 并且 sortMissingValues 是可选的,但如果设置了它们,则条目数必须与 sortFields 元素数匹配
Spring Data Elasticsearch 教程六
13.2. 索引映射
当 Spring Data Elasticsearch 应用
IndexOperations.createMapping() 办法创立索引映射时,它应用 Mapping Annotation Overview 中形容的注解,尤其是 @Field 注解。除此之外,还能够将 @Mapping 正文增加到类中。此注解具备以下属性:
mappingPathJSON 格局的类门路资源;如果它不为空,则用作映射,则不进行其余映射解决。
enabled 当设置为 false 时,此标记将写入映射并且不进行进一步解决。
dateDetection 并 numericDetection 在未设置为时设置映射中的相应属性 DEFAULT。
dynamicDateFormats 当这个 String 数组不为空时,它定义了用于主动日期检测的日期格局。
runtimeFieldsPath JSON 格局的类门路资源,蕴含写入索引映射的运行时字段的定义,例如:
{
“day_of_week”: {
"type": "keyword",
"script": {"source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
}
}
}
13.3. 过滤器生成器
Filter Builder 进步了查问速度。
private ElasticsearchOperations operations;
IndexCoordinates index = IndexCoordinates.of(“sample-index”);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter(“id”, documentId)))
.build();
Page<SampleEntity> sampleEntities = operations.searchForPage(searchQuery, SampleEntity.class, index);
13.4. 应用滚动获取大后果集
Elasticsearch 有一个滚动 API,用于获取大块的后果集。Spring Data Elasticsearch 在外部应用它来提供该 <T> SearchHitsIterator<T>
SearchOperations.searchForStream(Query query, Class<T> clazz, IndexCoordinates index) 办法的实现。
IndexCoordinates index = IndexCoordinates.of(“sample-index”);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFields(“message”)
.withPageable(PageRequest.of(0, 10))
.build();
SearchHitsIterator<SampleEntity> stream = elasticsearchTemplate.searchForStream(searchQuery, SampleEntity.class, index);
List<SampleEntity> sampleEntities = new ArrayList<>();
while (stream.hasNext()) {
sampleEntities.add(stream.next());
}
stream.close();
API 中没有 SearchOperations 拜访滚动 id 的办法,如果须要拜访它,ElasticsearchRestTemplate 能够应用以下办法:
@Autowired ElasticsearchRestTemplate template;
IndexCoordinates index = IndexCoordinates.of(“sample-index”);
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFields(“message”)
.withPageable(PageRequest.of(0, 10))
.build();
SearchScrollHits<SampleEntity> scroll = template.searchScrollStart(1000, searchQuery, SampleEntity.class, index);
String scrollId = scroll.getScrollId();
List<SampleEntity> sampleEntities = new ArrayList<>();
while (scroll.hasSearchHits()) {
sampleEntities.addAll(scroll.getSearchHits());
scrollId = scroll.getScrollId();
scroll = template.searchScrollContinue(scrollId, 1000, SampleEntity.class);
}
template.searchScrollClear(scrollId);
要将 Scroll API 与存储库办法一起应用,返回类型必须 Stream 在 Elasticsearch 存储库中定义。而后,该办法的实现将应用 ElasticsearchTemplate 中的滚动办法。
interface SampleEntityRepository extends Repository<SampleEntity, String> {
Stream<SampleEntity> findBy();
}
13.5 排序选项
除了分页和排序中形容的默认排序选项之外,Spring Data Elasticsearch 还提供了
org.springframework.data.elasticsearch.core.query.Order 派生自 org.springframework.data.domain.Sort.Order. 它提供了在指定后果排序时能够发送到 Elasticsearch 的其余参数(请参阅 https://www.elastic.co/guide/…)。
还有一个
org.springframework.data.elasticsearch.core.query.GeoDistanceOrder 类可用于按天文间隔排序搜寻操作的后果。
如果要检索的类具备 GeoPoint 名为 location 的属性,则以下 Sort 将按到给定点的间隔对后果进行排序:
Sort.by(new GeoDistanceOrder(“location”, new GeoPoint(48.137154, 11.5761247)))
13.6 运行时字段
从 Elasticsearch 的 7.12 版本开始,增加了运行时字段的性能(
https://www.elastic.co/guide/…)。Spring Data Elasticsearch 通过两种形式反对这一点:
13.6.1. 索引映射中的运行时字段定义
定义运行时字段的第一种办法是将定义增加到索引映射中(请参阅
https://www.elastic.co/guide/…)。要在 Spring Data Elasticsearch 中应用这种办法,用户必须提供一个蕴含相应定义的 JSON 文件,例如:
示例 93.runtime-fields.json
{
“day_of_week”: {
"type": "keyword",
"script": {"source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
}
}
}
此 JSON 文件的门路必须存在于类门路中,而后必须在 @Mapping 实体的正文中设置:
@Document(indexName = “runtime-fields”)
@Mapping(runtimeFieldsPath = “/runtime-fields.json”)
public class RuntimeFieldEntity {
// properties, getter, setter,...
}
13.6.2. 在查问上设置的运行时字段定义
定义运行时字段的第二种办法是将定义增加到搜寻查问(请参阅
https://www.elastic.co/guide/…)。以下代码示例显示了如何应用 Spring Data Elasticsearch 执行此操作:
应用的实体是一个具备 price 属性的简略对象:
@Document(indexName = “some_index_name”)
public class SomethingToBuy {
private @Id @Nullable String id;
@Nullable @Field(type = FieldType.Text) private String description;
@Nullable @Field(type = FieldType.Double) private Double price;
// getter and setter
}
以下查问应用一个运行时字段,该字段 priceWithTax 通过将 19% 加到价格来计算一个值,并在搜寻查问中应用此值来查找 priceWithTax 高于或等于给定值的所有实体:
RuntimeField runtimeField = new RuntimeField(“priceWithTax”, “double”, “emit(doc[‘price’].value * 1.19)”);
Query query = new CriteriaQuery(new Criteria(“priceWithTax”).greaterThanEqual(16.5));
query.addRuntimeField(runtimeField);
SearchHits<SomethingToBuy> searchHits = operations.search(query, SomethingToBuy.class);
这实用于 Query 接口的每个实现。:leveloffset: -1