赞
踩
当使用Spring Data创建Elasticsearch索引时,可以使用@Setting注解定义不同的索引设置。以下参数可用:
也可以定义索引排序(查看链接的Elasticsearch文档中可能的字段类型和值):
@Document(indexName = "entities") @Setting( sortFields = { "secondField", "firstField" }, --------1 sortModes = { Setting.SortMode.max, Setting.SortMode.min }, --------2 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... } 1. 定义排序字段时,请使用Java属性的名称(firstField),而不是可能为Elasticsearch定义的名称(first_field) 2. sortModes、sortOrders和sortMissingValues是可选的,但如果设置了它们,则条目的数量必须与sortFields元素的数量相匹配
当Spring Data Elasticsearch使用IndexOperations.createMapping()方法创建索引映射时,它会使用Mapping Annotation Overview中描述的注解,尤其是@Field注解。除此之外,还可以将@Mapping注解添加到类中。此注解具有以下属性:
{
"day_of_week": {
"type": "keyword",
"script": {
"source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
}
}
}
Filter Builder提高查询速度。
private ElasticsearchOperations operations; IndexCoordinates index = IndexCoordinates.of("sample-index"); Query query = NativeQuery.builder() .withQuery(q -> q .matchAll(ma -> ma)) .withFilter( q -> q .bool(b -> b .must(m -> m .term(t -> t .field("id") .value(documentId)) ))) .build(); SearchHits<SampleEntity> sampleEntities = operations.search(query, SampleEntity.class, index);
Elasticsearch有一个滚动API,用于获取大块的结果集。Spring Data Elasticsearch内部使用它来提供<T> SearchHitsIterator<T> SearchOperations.searchForStream(Query query, Class<T> clazz, IndexCoordinates index)方法的实现。
IndexCoordinates index = IndexCoordinates.of("sample-index"); Query searchQuery = NativeQuery.builder() .withQuery(q -> q .matchAll(ma -> ma)) .withFields("message") .withPageable(PageRequest.of(0, 10)) .build(); SearchHitsIterator<SampleEntity> stream = elasticsearchOperations.searchForStream(searchQuery, SampleEntity.class, index); List<SampleEntity> sampleEntities = new ArrayList<>(); while (stream.hasNext()) { sampleEntities.add(stream.next()); } stream.close();
在SearchOperations API中没有方法来访问滚动id,如果有必要访问它,可以使用AbstractElasticsearchTemplate的以下方法(这是不同ElasticsearchOperations实现的基础实现):
@Autowired ElasticsearchOperations operations; AbstractElasticsearchTemplate template = (AbstractElasticsearchTemplate)operations; IndexCoordinates index = IndexCoordinates.of("sample-index"); Query query = NativeQuery.builder() .withQuery(q -> q .matchAll(ma -> ma)) .withFields("message") .withPageable(PageRequest.of(0, 10)) .build(); SearchScrollHits<SampleEntity> scroll = template.searchScrollStart(1000, query, 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与存储库方法一起使用,返回类型必须在Elasticsearch存储库中定义为Stream。然后,该方法的实现将使用ElasticsearchTemplate中的scroll方法。
interface SampleEntityRepository extends Repository<SampleEntity, String> {
Stream<SampleEntity> findBy();
}
除了分页和排序中描述的默认排序选项外,Spring Data Elasticsearch还提供了从“org.springframework.Data.domain.sort.Order”派生而来的类“org.springframework.Data.reasticsearch.core.query”。它提供了额外的参数,在指定结果排序时可以将这些参数发送到Elasticsearch(请参见这里)。
还有“org.springframework.data.aelasticsearch.core.query.GeoDistanceOrder”类,可用于按地理距离排序搜索操作的结果。
如果要检索的类具有名为location的GeoPoint属性,则以下排序将按到给定点的距离对结果进行排序:
Sort.by(new GeoDistanceOrder("location", new GeoPoint(48.137154, 11.5761247)))
从7.12版本开始,Elasticsearch增加了运行时字段的功能。Spring Data Elasticsearch通过两种方式支持这一点:
定义运行时字段的第一种方法是将定义添加到索引映射中(请参见这里)。要在Spring Data Elasticsearch中使用这种方法,用户必须提供一个包含相应定义的JSON文件,例如:
例1: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,...
}
定义运行时字段的第二种方法是将定义添加到搜索查询中(请参见这里)。以下代码示例展示了如何使用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
}
下面的查询使用一个运行时字段,该字段通过将价格添加19%来计算priceWithTax值,并在搜索查询中使用该值来查找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接口的每一个实现。
ElasticsearchOperations支持Elasticsearch的point in time API(请参见这里)。以下代码片段显示了如何将此功能与虚构的Person类一起使用:
ElasticsearchOperations operations; // autowired Duration tenSeconds = Duration.ofSeconds(10); String pit = operations.openPointInTime(IndexCoordinates.of("person"), tenSeconds); --------1 // create query for the pit Query query1 = new CriteriaQueryBuilder(Criteria.where("lastName").is("Smith")) .withPointInTime(new Query.PointInTime(pit, tenSeconds)) --------2 .build(); SearchHits<Person> searchHits1 = operations.search(query1, Person.class); // do something with the data // create 2nd query for the pit, use the id returned in the previous result Query query2 = new CriteriaQueryBuilder(Criteria.where("lastName").is("Miller")) .withPointInTime( new Query.PointInTime(searchHits1.getPointInTimeId(), tenSeconds)) --------3 .build(); SearchHits<Person> searchHits2 = operations.search(query2, Person.class); // do something with the data operations.closePointInTime(searchHits2.getPointInTimeId()); --------4 1. 为索引(可以是多个名称)和keep-alive持续时间创建一个point in time,并检索其id 2. 将该id传递到查询中,以便与下一个keep-alive一起进行搜索 3. 对于下一个查询,使用上一次搜索返回的id 4. 完成后,使用最后返回的id关闭point in time
支持使用搜索模板Template API。要使用它,首先需要创建一个存储的脚本。ElasticsearchOperations接口扩展了提供必要功能的ScriptOperations。这里使用的示例假设我们有一个名为firstName的属性的Person实体。搜索模板脚本可以这样保存:
operations.putScript( --------1 Script.builder() .withId("person-firstname") --------2 .withLanguage("mustache") --------3 .withSource(""" --------4 { "query": { "bool": { "must": [ { "match": { "firstName": "{{firstName}}" --------5 } } ] } }, "from": "{{from}}", --------6 "size": "{{size}}" --------7 } """) .build() ); 1. 使用putScript()方法存储搜索模板脚本 2. 脚本的名称/id 3. 搜索模板中使用的脚本必须是mustache语言。 4. 脚本源 5. 脚本中的搜索参数 6. 分页请求偏移 7. 分页请求大小
为了在搜索查询中使用搜索模板,Spring Data Elasticsearch提供了SearchTemplateQuery,这是“org.springframework.data.elasticsearch.core.query.Query”接口的实现。
在下面的代码中,我们将使用搜索模板查询向自定义存储库实现添加一个调用(请参阅自定义存储库实现),作为如何将其集成到存储库调用中的示例。
我们首先定义自定义存储库片段接口:
interface PersonCustomRepository {
SearchPage<Person> findByFirstNameWithSearchTemplate(String firstName, Pageable pageable);
}
这个存储库片段的实现看起来像这样:
public class PersonCustomRepositoryImpl implements PersonCustomRepository { private final ElasticsearchOperations operations; public PersonCustomRepositoryImpl(ElasticsearchOperations operations) { this.operations = operations; } @Override public SearchPage<Person> findByFirstNameWithSearchTemplate(String firstName, Pageable pageable) { var query = SearchTemplateQuery.builder() --------1 .withId("person-firstname") --------2 .withParams( Map.of( --------3 "firstName", firstName, "from", pageable.getOffset(), "size", pageable.getPageSize() ) ) .build(); SearchHits<Person> searchHits = operations.search(query, Person.class); --------4 return SearchHitSupport.searchPageFor(searchHits, pageable); } } 1. 创建SearchTemplateQuery 2. 提供搜索模板的id 3. 参数在Map<String,Object>中传递 4. 以与其他查询类型相同的方式进行搜索。
Spring Data Elasticsearch支持在嵌套对象内排序(见这里)下面的例子,摘自org.springframework.data.elasticsearch.core.query.sort.NestedSortIntegrationTests类,展示了如何定义嵌套排序。
var filter = StringQuery.builder("""
{ "term": {"movies.actors.sex": "m"} }
""").build();
var order = new org.springframework.data.elasticsearch.core.query.Order(Sort.Direction.DESC,
"movies.actors.yearOfBirth")
.withNested(
Nested.builder("movies")
.withNested(
Nested.builder("movies.actors")
.withFilter(filter)
.build())
.build());
var query = Query.findAll().addSort(Sort.by(order));
关于filter查询:这里不可能使用CriteriaQuery,因为此查询将被转换为Elasticsearch嵌套查询,该查询在filter上下文中不起作用。所以这里只能使用StringQuery或NativeQuery。当使用其中一个时,如上面的term查询,必须使用Elasticsearch字段名,所以当使用@Field(name=“…”)定义重新定义这些字段时要小心。
对于排序路径和嵌套路径的定义,应使用Java实体属性名称。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。