SpringDataElasticsearch(以后简称SDE)是Spring Data项目下的一个子模块。
Spring Data的使命是给各种数据访问提供统一的编程接口,比如Mysql、Redis、ES等等,目的是简化开发人员的代码。
SDE提供对象即支持ES的原生API操作,也提供了ElasticsearchTemplate对象来操作ES。
创建索引库和映射
- 创建springboot工程,导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
- 创建application.yaml
# SpringDataElasticsearch底层使用的不是Elasticsearch提供的RestHighLevelClient,
# 而是TransportClient,并不采用Http协议通信,而是访问elasticsearch对外开放的tcp端口,
spring:
data:
elasticsearch:
cluster-name: my-application
cluster-nodes: 127.0.0.1:9300
- 添加主类
@SpringBootApplication
public class SdeApplication {
public static void main(String[] args) {
SpringApplication.run(SdeApplication.class,args);
}
}
- 创建一个实体类(使用注解表明对应的库)
@Data
@AllArgsConstructor
@NoArgsConstructor
/**
* 配置实体类和es数据库的映射关系
* @Document : 指定实体类和索引库的映射关系
* indexName:指定索引库
* type:指定类型
* shards:分片数量
* replicas:分片的备份数量
*/
@Document(indexName = "goods",type = "_doc")
public class Goods {
@Id
private Long id;
/**
* @Id:映射注解
* @FielId: 映射普通属性
* type:字段类型
* analyzer:分词器(只对text有效)
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String title; //标题
@Field(type = FieldType.Keyword)
private String category;// 分类
@Field(type = FieldType.Keyword)
private String brand; // 品牌
@Field(type = FieldType.Double)
private Double price; // 价格
@Field(type = FieldType.Keyword, index = false)
private String images; // 图片地址
}
- 创建一个测试类,然后创建索引库和映射
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class SdeTest {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Autowired
private GoodsRepository goodsRepository;
@Test
public void testCreateIndex() {
elasticsearchTemplate.createIndex(Goods.class);//创建索引
elasticsearchTemplate.putMapping(Goods.class);//创建映射
}
}
测试后可查看索引库
基于接口代理的操作(重点)
SDE提供了一种基于接口代理的操作,我们只需要自定义接口,继承ElasticsearchRepository,就可以使用里面的方法
- 自定义接口继承ElasticsearchRepository
//泛型分别是实体类和实体类主键类型
public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {
}
- 在测试类中创建索引数据
//保存一个
@Test
public void testSave() {
Goods goods = new Goods(1L, "华为pro40手机", "手机", "华为", 4999D, "http://images.huawei.com/pro40.jpg");
goodsRepository.save(goods);
}
//保存多个
@Test
public void testSaveMulti(){
ArrayList<Goods> list = new ArrayList<>();
list.add(new Goods(11L, "小米手机", "手机", "小米", 3299.00, "http://image.huawei.com/13123.jpg"));
list.add(new Goods(12L, "锤子手机", "手机", "锤子", 3699.00, "http://image.huawei.com/13123.jpg"));
list.add(new Goods(13L, "联想手机", "手机", "联想", 4499.00, "http://image.huawei.com/13123.jpg"));
list.add(new Goods(14L, "红米手机", "手机", "小米", 4299.00, "http://image.huawei.com/13123.jpg"));
goodsRepository.saveAll(list);
}
- 在测试类中查询索引数据
//主键查询
@Test
public void testFindById() {
Optional<Goods> goodsOptional = goodsRepository.findById(1L);
System.out.println(goodsOptional.orElse(null));
}
//查询所有
@Test
public void testFindAll() {
Iterable<Goods> goodsList = goodsRepository.findAll();
for (Goods goods : goodsList) {
System.out.println(goods);
}
}
//条件查询
@Test
public void testSearch() {
//Iterable<Goods> goodsList = goodsRepository.search(QueryBuilders.matchAllQuery());
//Iterable<Goods> goodsList = goodsRepository.search(QueryBuilders.matchQuery("title", "小米"));
Iterable<Goods> goodsList = goodsRepository.search(QueryBuilders.rangeQuery("price").lt(4000).gt(3000));
for (Goods goods : goodsList) {
System.out.println(goods);
}
}
- 在测试类中实现分页和排序
//分页和排序查询
@Test
public void testFindByPage() {
//排序
//Iterable<Goods> goodsList = goodsRepository.findAll(Sort.by(Sort.Order.desc("id")));
//分页和排序
Sort sort = Sort.by(Sort.Order.desc("id"));
Pageable pageable = PageRequest.of(1, 2, sort);//page 第几页(从0开始), size 每页条数
Page<Goods> page = goodsRepository.findAll(pageable);
for (Goods goods : page.getContent()) {
System.out.println(goods);
}
}
基于Template的查询
应用场景:高亮(******),分组聚合
SDE也支持ElasticsearchTemplate来实现查询,它的使用更加灵活
//基本使用
@Test
public void test1() {
//1.创建NativeSearchQueryBuilder
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//2.设置条件
builder.withQuery(QueryBuilders.matchAllQuery()); //查询全部
//builder.withQuery(QueryBuilders.matchQuery("title","小米手机")); //match查询
//builder.withQuery(QueryBuilders.termQuery("title","小米手机"));//词条查询
//builder.withQuery(QueryBuilders.rangeQuery("price").lte(3000).gte(1000)); //范围查询
//3.调用elasticsearchTemplate的方法完成操作
List<Goods> list = elasticsearchTemplate.queryForList(builder.build(), Goods.class);
for (Goods goods : list) {
System.out.println(goods);
}
}
//排序 分页
@Test
public void test2() {
//1.创建NativeSearchQueryBuilder
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//2.设置条件
builder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));//排序
builder.withPageable(PageRequest.of(1,2)) ;//封装所有的分页数据 (页码从0开始,每页查询条数)
//3.调用elasticsearchTemplate的方法完成操作
AggregatedPage<Goods> page = elasticsearchTemplate.queryForPage(builder.build(), Goods.class);
for (Goods goods : page.getContent()) {
System.out.println(goods);
}
}
// 分组
@Test
public void test3() {
//1.创建NativeSearchQueryBuilder
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//2. 添加分组条件
builder.addAggregation(AggregationBuilders.terms("agg-brand").field("brand"));
//3. 执行
AggregatedPage<Goods> page = elasticsearchTemplate.queryForPage(builder.build(), Goods.class);
//4. 解析结果
Terms terms = page.getAggregations().get("agg-brand");
for (Terms.Bucket bucket : terms.getBuckets()) {
System.out.println(bucket.getKey());
System.out.println(bucket.getDocCount());
}
}