spring data的中心接口是 Repository ,需要实体类和ID作为类型参数,这个CrudRepository
接口为我们正在管理的实体类提供复杂的CRUD功能
PagingAndSortingRepository
则是继承了 CrudRepository
接口,还增加了额外的方法来简化对实体的分页访问
分页接口的使用:
PagingAndSortingRepository<User, Long> repository = // … get access to a bean
Page<User> users = repository.findAll(PageRequest.of(1, 20));
声明一个接口,继承Repositoriy接口:
interface PersonRepository extends Repository<Person, Long> { … }
在接口上声明查询方法,也可以不声明
interface PersonRepository extends Repository<Person, Long> {
List<Person> findByLastname(String lastname);
}
对接口使用 @Repositories
,为接口创建代理实例
自动注入@AutoWired
接口并使用
实体类作为ES的映射对象,需要对该类添加注解:
@Document
: 应用于类级别,表示该类是映射到数据库的候选。最重要的属性是:
indexName
:存储该实体的索引名称shards
:索引的分片数。replicas
:索引的副本数。createIndex
: 配置是否在使用 Repositories时创建索引。默认值为*true
*。versionType
: 版本管理的配置。默认值为EXTERNAL。@Id
:在字段级别应用以标记用于标识目的的字段。@Field
:应用于字段级别,定义字段的属性
name
: 字段名称,因为它将在 Elasticsearch 文档中表示,如果未设置,则使用 Java 字段名称。type
:字段类型,可以是Text、Keyword、Long、Integer、Short、Byte、Double、Float等等,format
和Date类型的pattern
定义。必须在日期类型上定义。format
store
: 标记原始字段值是否应存储在 Elasticsearch 中,默认值为false。analyzer
, searchAnalyzer
,normalizer
用于指定自定义自定义分析器和规范器。当我们在插入 document的时候,会发现有一个 _class
字段会显示我们的类路径:
我们可以通过添加 @TypeAlias("xxxx")
来修改这个值。
spring data elasticsearch 使用多个接口来定义可以针对 elastic search索引调用的操作
IndexOperations
定义索引级别的操作,例如创建或删除索引。DocumentOperations
定义基于 id 存储、更新和检索实体的操作。SearchOperations
定义使用查询搜索多个实体的操作ElasticsearchOperations
结合了DocumentOperations
和SearchOperations
接口。ElasticsearchRestTemplate
是ElasticsearchOperations
使用高级客户端的接口的实现。
我们无需对 这个模板接口进行特殊定义,因为在我们的继承配置类AbstractElasticsearchConfiguration
就已经提供了 这个模板接口的 bean:
所以我们直接自动注入使用即可。
spring-data-elasticsearch 支持使用模板类进行CRUD的操作
@Test
void insert_By_Template(){
Product product=new Product(333L,"title","cate",100.0,"/a.jsp",null);
IndexQuery indexQuery=new IndexQueryBuilder()
.withObject(product)
.build();
template.index(indexQuery, IndexCoordinates.of("shopping"));
}
Product product = template.queryForObject(GetQuery.getById("333"), Product.class);
这是通过ID 查询检索实体
ES的查询创建机制按照ES的请求方式创建
interface BookRepository extends Repository<Book, String> {
List<Book> findByNameAndPrice(String name, Integer price);
}
这样的方法名会被翻译成下面的json格式:
{
"query": {
"bool" : {
"must" : [
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
]
}
}
}
我们并不需要自己定义方法的具体实现,只需要定义方法名,然后使用方法即可。
定义之后,直接使用:
即可查出具体内容:
注意我们在定义方法的时候就会有提示了:
关键词 | 参考名字 | 备注 |
---|---|---|
And |
findByNameAndPrice |
|
Or |
findByNameOrPrice |
|
Is |
findByName |
仅仅一个 match |
Not |
findByNameNot |
{ "query" : { "bool" : { "must_not" : [ { "query_string" : { "query" : "?", "fields" : [ "name" ] } } ] } }} |
Between |
findByPriceBetween |
包含上下界 |
LessThan |
findByPriceLessThan |
少于,不包含上界 |
LessThanEqual |
findByPriceLessThanEqual |
小于等于 |
Before |
findByPriceBefore |
比当前值小,包含上下界(下界为null) |
Like |
findByNameLike |
|
OrderBy |
findByAvailableTrueOrderByNameDesc |
降序排序所有的值 |
使用如下:
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
List<Product> findMySelf();
这样,我们在使用 findMySelf()
查询的时候,就会使用如下json查询:
{
"query": {
"match": {
"name": {
"query": "John"
}
}
}
}
我们要在console中能显示出高亮,那么必须要返回值设置为 SearchHit,如果返回的是实体类那么就不能查看出高亮
自定义方法:
@Highlight(fields ={ @HighlightField(name = "title")
})
List<SearchHit<Product>> findByTitleAndPrice(String title, Double price);
我们直接使用该方法:
List<SearchHit<Product>> hits = productDao.findByTitleAndPrice("hello", 267.0);
System.out.println(hits);
for (SearchHit<Product> hit : hits) {
System.out.println(hit);
}
可以发现,title
字段确实被高亮显示了
对于聚合操作,spring data search 的 Repository
并不支持,可能还是需要使用高级客户端去进行聚合的查询
@Test
void use_aggregation() throws Exception{
RestHighLevelClient client= new RestHighLevelClient(RestClient.builder(new HttpHost("localhost",9200,"http")));
SearchRequest request=new SearchRequest();
request.indices("shopping");
AggregationBuilder aggregationBuilder= AggregationBuilders.max("maxprice").field("price");
SearchSourceBuilder sourceBuilder=new SearchSourceBuilder().aggregation(aggregationBuilder);
request.source(sourceBuilder);
SearchResponse search = client.search(request, RequestOptions.DEFAULT);
Max maxprice = search.getAggregations().get("maxprice");
System.out.println(maxprice.getValue());
}
需要使用分页的 Repository
来操作:
@Repository
public interface ProductDaoPaging extends PagingAndSortingRepository<Product,Long> {
}
@Autowired
ProductDaoPaging dao;
@Test
void test(){
PageRequest request=PageRequest.of(0,2);
Page<Product> all = dao.findAll(request);
Iterator<Product> iterator = all.iterator();
while (iterator.hasNext()){
Product next = iterator.next();
System.out.println(next);
}
}
依赖:
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.6.RELEASEversion>
<relativePath/>
parent>
<dependencies>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-testartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
dependency>
dependencies>
实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Document(indexName = "shopping",shards = 3,replicas = 1)
@TypeAlias("shopping")
public class Product {
@Id
private Long id;
private String title;
@Field(type = FieldType.Keyword)//keyword表示不能被分词
private String category;
@Field(type = FieldType.Double)//表示为浮点类型,非字符串类型都必须要使用这个
private Double price;
@Field(type = FieldType.Keyword,index = false) //不能被索引
private String images;
private List<Product> products;
}
Repository接口:
@Repository
public interface ProductDao extends ElasticsearchRepository<Product,Long>{
List<Product> findByTitleAndCategory(String title, String category);
@Highlight(fields ={
@HighlightField(name = "title")
})
List<SearchHit<Product>> findByTitleAndPrice(String title, Double price);
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
List<Product> findMySelf();
}
配置类:
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
RestHighLevelClient client=new RestHighLevelClient(RestClient.builder(new HttpHost("localhost",9200)));
return client;
}
}
然后其他的就是一些测试代码,这里就不上了