前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring认证中国教育管理中心-Spring Data Elasticsearch教程六

Spring认证中国教育管理中心-Spring Data Elasticsearch教程六

原创
作者头像
IT胶囊
发布2022-01-17 14:55:38
1K0
发布2022-01-17 14:55:38
举报
文章被收录于专栏:IT技能应用

原标题:Spring认证中国教育管理中心-Spring Data Elasticsearch教程六(Spring中国教育管理中心)

12. 路由值

当 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上面的类):

代码语言:javascript
复制
@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的属性

如果routing注解的规范是纯字符串而不是 SpEL 表达式,则将其解释为实体的属性名称,在示例中为路由属性。然后,此属性的值将用作使用该实体的所有请求的路由值。

我们也可以在@Document注释中使用 SpEL 表达式,如下所示:

代码语言:javascript
复制
@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实例上设置:

代码语言:javascript
复制
RoutingResolver resolver = ...;

ElasticsearchOperations customOperations= operations.withRouting(resolver);

这些函数返回带有自定义路由集withRouting()的原始实例的副本。ElasticsearchOperations

当实体存储在 Elasticsearch 中时,如果在实体上定义了路由,则在执行获取删除操作时必须提供相同的值。对于不使用实体的方法 - 比如get(ID)或delete(ID) -ElasticsearchOperations.withRouting(RoutingResolver)可以像这样使用该方法:

代码语言:javascript
复制
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) 返回一个解析器,它只返回给定的字符串。

13. 其他 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 文档以了解可能的字段类型和值):

代码语言:javascript
复制
@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元素数匹配

13.2.索引映射

当 Spring Data Elasticsearch 使用 IndexOperations.createMapping()方法创建索引映射时,它使用Mapping Annotation Overview中描述的注解,尤其是@Field注解。除此之外,还可以将@Mapping注释添加到类中。此注解具有以下属性:

  • mappingPathJSON 格式的类路径资源;如果它不为空,则用作映射,则不进行其他映射处理。
  • enabled 当设置为 false 时,此标志将写入映射并且不进行进一步处理。
  • dateDetection并numericDetection在未设置为时设置映射中的相应属性DEFAULT。
  • dynamicDateFormats 当这个 String 数组不为空时,它定义了用于自动日期检测的日期格式。
  • runtimeFieldsPath JSON 格式的类路径资源,包含写入索引映射的运行时字段的定义,例如:
代码语言:javascript
复制
{
  "day_of_week": {
    "type": "keyword",
    "script": {
      "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
    }
  }
}

13.3.过滤器生成器

Filter Builder 提高了查询速度。

代码语言:javascript
复制
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)方法的实现。

代码语言:javascript
复制
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可以使用以下方法:

代码语言:javascript
复制
@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 中的滚动方法。

代码语言:javascript
复制
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/en/elasticsearch/reference/7.15/sort-search-results.html)。

还有一个 org.springframework.data.elasticsearch.core.query.GeoDistanceOrder类可用于按地理距离排序搜索操作的结果。

如果要检索的类具有GeoPoint名为location的属性,则以下Sort将按到给定点的距离对结果进行排序:

代码语言:javascript
复制
Sort.by(new GeoDistanceOrder("location", new GeoPoint(48.137154, 11.5761247)))

13.6运行时字段

从 Elasticsearch 的 7.12 版本开始,添加了运行时字段的功能( https://www.elastic.co/guide/en/elasticsearch/reference/7.12/runtime.html)。Spring Data Elasticsearch 通过两种方式支持这一点:

13.6.1.索引映射中的运行时字段定义

定义运行时字段的第一种方法是将定义添加到索引映射中(请参阅 https://www.elastic.co/guide/en/elasticsearch/reference/7.12/runtime-mapping-fields.html)。要在 Spring Data Elasticsearch 中使用这种方法,用户必须提供一个包含相应定义的 JSON 文件,例如:

示例 93.runtime-fields.json

代码语言:javascript
复制
{
  "day_of_week": {
    "type": "keyword",
    "script": {
      "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
    }
  }
}

此 JSON 文件的路径必须存在于类路径中,然后必须在@Mapping实体的注释中设置:

代码语言:javascript
复制
@Document(indexName = "runtime-fields")
@Mapping(runtimeFieldsPath = "/runtime-fields.json")
public class RuntimeFieldEntity {
	// properties, getter, setter,...
}

13.6.2.在查询上设置的运行时字段定义

定义运行时字段的第二种方法是将定义添加到搜索查询(请参阅 https://www.elastic.co/guide/en/elasticsearch/reference/7.12/runtime-search-request.html)。以下代码示例显示了如何使用 Spring Data Elasticsearch 执行此操作:

使用的实体是一个具有price属性的简单对象:

代码语言:javascript
复制
@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高于或等于给定值的所有实体:

代码语言:javascript
复制
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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 12. 路由值
  • 12.1.连接类型的路由
  • 12.2.自定义路由值
  • 13. 其他 Elasticsearch 操作支持
  • 13.1.索引设置
  • 13.2.索引映射
  • 13.3.过滤器生成器
  • 13.4.使用滚动获取大结果集
  • 13.5排序选项
  • 13.6运行时字段
  • 13.6.1.索引映射中的运行时字段定义
  • 13.6.2.在查询上设置的运行时字段定义
相关产品与服务
Elasticsearch Service
腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档