沈阳建设局网站/企业软文
01.Spring Data 简介
what:是什么
- Spring Data是一个用于简化持久层数据访问的开源框架。
- 其主要目标是使得对数据的访问变得方便快捷。
- Spring Data可以极大的简化数据操作的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。
- 包括CRUD外,还包括如分页、排序等一些常用的功能,几乎可以节省持久层代码80%以上的编码工作量。
- Spring Data的官网:http://projects.spring.io/spring-data/
02.Spring Data ElasticSearch简介
what:是什么
- Spring Data ElasticSearch 基于 spring data API 简化 elasticSearch操作,将原始操作elasticSearch的客户端API 进行封装 。
- Spring Data为Elasticsearch项目提供集成搜索引擎。
- Spring Data Elasticsearch POJO的关键功能区域为中心的模型与Elastichsearch交互文档和轻松地编写一个存储库数据访问层。
- 官方网站:http://projects.spring.io/spring-data-elasticsearch/
why:为什么使用
- 用来操作ElasticSearch的框架,使得开发更加便捷
03.环境搭建
实现步骤:
- 创建SpringBoot的项目:版本为
<version>2.1.9.RELEASE</version>
- 勾选starter依赖坐标
- 编写持久层接口GoodDao,编写pojo实体类
- 配置文件,集群配置,ElasticSearch服务地址http://127.0.0.1:9300
实现过程:
- 创建SpringBoot的项目!
- 勾选starter依赖坐标,依赖如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.9.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.lxgzhw</groupId><artifactId>springdata_es_demo</artifactId><version>0.0.1-SNAPSHOT</version><name>springdata_es_demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
编写持久层接口GoodDao,编写pojo实体类
package com.lxgzhw.dao;public interface GoodDao {
}
pojo实体类,商品good:这里的索引名称不能是已存在的
package com.lxgzhw.pojo;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;/*** 商品实体类** @Document() 注解作用:定义一个索引库,一个类型* indexName属性:指定索引库的名称* type属性:指定类型名称* shards属性:指定分片数* replicas属性:指定复制副本数*/
@Data
@Document(indexName = "lxgzhw1", type = "goods", shards = 5, replicas = 1)
public class Good {private Long id;//商品的唯一标识private String title;//标题private String category;//分类private String brand;//品牌private Double price;//价格private String images;//图片地址//getter,setter,toString
}
配置文件:applacation.properties
- 集群配置,ElasticSearch服务地址http://127.0.0.1:9301
- 这里的集群名称和服务地址要与之前教程中配置的保持一致
# 配置集群名称
spring.data.elasticsearch.cluster-name=my-Elasticsearch
# 配置es的服务地址
spring.data.elasticsearch.cluster-nodes=127.0.0.1:9301
04.创建和删除索引
几个用到的注解:
- @Document:声明索引库配置
- indexName:索引库名称
- type:类型名称,默认是“docs”
- shards:分片数量,默认5
- replicas:副本数量,默认1
- @Id:声明实体类的id
- @Field:声明字段属性
- type:字段的数据类型
- analyzer:指定分词器类型
- index:是否创建索引 默认为true
- store:是否存储 默认为false
实体类配置:
package com.lxgzhw.pojo;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;/*** 商品实体类** @Document() 注解作用:定义一个索引库,一个类型* indexName属性:指定索引库的名称* type属性:指定类型名称* shards属性:指定分片数* replicas属性:指定复制副本数*/
@Data
@Document(indexName = "lxgzhw2", type = "goods", shards = 5, replicas = 1)
public class Good {//必须有id,这里的id是全局唯一的标识,等同于es中的“_id”@Idprivate Long id;/*** type: 字段数据类型* analyzer: 分词器类型* index: 是否索引(默认值:true)* store: 是否存储(默认值:false)*/@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;//图片地址//getter ,setter ,toString
}
测试类:Demo01IndexOperationTests.java
package com.lxgzhw;import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.junit4.SpringRunner;/*** 创建索引* 配置映射* 删除索引*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class Demo01IndexOperationTests {//模板设计模式@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;@Testpublic void createIndexAndPutMapping() {elasticsearchTemplate.createIndex(Good.class);//创建索引elasticsearchTemplate.putMapping(Good.class);//配置映射}//删除索引@Testpublic void deleteIndex() {elasticsearchTemplate.deleteIndex(Good.class);}}
05.文档的常见增删改查
修改GoodDao接口:继承ElasticsearchRespository模板接口
package com.lxgzhw.dao;import com.lxgzhw.pojo.Good;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;public interface GoodDao extends ElasticsearchRepository<Good, Long> {
}
添加测试类:SpringdataEsGoodCRUDTests.java
package com.lxgzhw;import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;import java.util.ArrayList;
import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsGoodCRUDTests {//注入Good业务层实现类@Autowiredprivate GoodDao goodDao;/*** 新增*/@Testpublic void save() {Good good = new Good();good.setId(1l);good.setTitle("小米手机");good.setCategory("手机");good.setBrand("小米");good.setPrice(19999.0);good.setImages("http://image.leyou.com/12479122.jpg");goodDao.save(good);}//修改@Testpublic void update() {Good good = new Good();good.setId(1l);good.setTitle("小米手机");good.setCategory("手机");good.setBrand("小米");good.setPrice(9999.0);good.setImages("http://image.leyou.com/12479122.jpg");goodDao.save(good);}//删除@Testpublic void delete() {Good good = new Good();good.setId(1l);goodDao.delete(good);}//根据id查询@Testpublic void findById() {Good good = goodDao.findById(1l).get();System.out.println(good);}//查询所有@Testpublic void findAll() {Iterable<Good> goods = goodDao.findAll();for (Good good : goods) {System.out.println(good);}}//批量新增@Testpublic void saveAll() {List<Good> goodList = new ArrayList<>();for (int i = 0; i < 500; i++) {Good good = new Good();good.setId((long) i);good.setTitle("[" + i + "]小米手机");good.setCategory("手机");good.setBrand("小米");good.setPrice(19999.0 + i);good.setImages("http://image.leyou.com/12479122.jpg");goodList.add(good);}goodDao.saveAll(goodList);}//分页查询@Testpublic void findByPageable() {//设置排序(排序方式,正序还是倒序,排序的id)Sort sort = new Sort(Sort.Direction.DESC, "id");int currentPage = 2;//当前页int pageSize = 100;//每页显示多少条//设置查询分页PageRequest pageRequest = PageRequest.of(currentPage, pageSize, sort);//分页查询System.out.println("分页数据:");Page<Good> goodPage = goodDao.findAll(pageRequest);for (Good good : goodPage.getContent()) {System.out.println(good);}}
}
07.Search查询
what:是什么
- ElasticSearch的search方法中QueryBuilders,就是第一章中的查询对象构建对象QueryBuilders。
- QueryBuilders具备的能力,search方法都具备。
- 所以,在这里重复内容不赘述,仅举例term查询。
创建测试类:SpringdataEsSearchTests.java
package com.lxgzhw;import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsSearchTests {//注入Good业务层实现类@Autowiredprivate GoodDao goodDao;/*** term查询* search(termQueryBuilder) 调用搜索方法,参数查询构建器对象*/@Testpublic void termQuery() {TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");Iterable<Good> goods = goodDao.search(termQueryBuilder);for (Good g : goods) {System.out.println(g);}}/*** term查询加分页*/@Testpublic void termQueryByPage() {int currentPage = 0;int pageSize = 5;//设置查询分页PageRequest pageRequest = PageRequest.of(currentPage, pageSize);TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", "小米");Iterable<Good> goods = goodDao.search(termQueryBuilder, pageRequest);for (Good g : goods) {System.out.println(g);}}
}
08.自定义方法名称查询
what:是什么
- GoodsRepository提供了非常强大的自定义查询功能;只要遵循SpringData提供的语法,我们可以任意定义方法声明
- 查询语法:findBy+字段名+Keyword+字段名+…
Keyword | Sample | Elasticsearch Query String |
---|---|---|
And | findByNameAndPrice | {"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or | findByNameOrPrice | {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is | findByName | {"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not | findByNameNot | {"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between | findByPriceBetween | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
Before | findByPriceBefore | {"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After | findByPriceAfter | {"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like | findByNameLike | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith | findByNameStartingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith | findByNameEndingWith | {"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
In | findByNameIn(Collection<String>names) | {"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn | findByNameNotIn(Collection<String>names) | {"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
OrderBy | findByNameOrderByNameDesc | {"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"name" : "?"}}} |
持久层接口:
package com.lxgzhw.dao;import com.lxgzhw.pojo.Good;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;import java.util.List;/*** ElasticsearchRepository 持久层操作ElasticSearch的模板接口*/
public interface GoodDao extends ElasticsearchRepository<Good, Long> {/*** 根据title和价格查询,and的关系*/List<Good> findAllByTitleAndPrice(String title, Double price);/*** 根据商品价格范围查询* 最低价格lowPrice* 最高价格highPrice*/List<Good> findByPriceBetween(Double lowPrice, Double highPrice);
}
添加测试类:SpringdataEsCustomMethodQueryTests.java
package com.lxgzhw;import com.lxgzhw.dao.GoodDao;
import com.lxgzhw.pojo.Good;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringdataEsCustomMethodQueryTests {//注入Good业务层实现类@Autowiredprivate GoodDao goodDao;/*** 根据标题及价格查询* 要求价格等于20023且标题的内容包含小米关键词*/@Testpublic void findAllByTitleAndPrice() {String title = "小米";Double price = 20023.0;List<Good> goods = goodDao.findAllByTitleAndPrice(title, price);for (Good g : goods) {System.out.println(g);}}/*** 根据价格范围查询* 要求商品价格再3000,到20000之间*/@Testpublic void findPriceBetween() {double lowPrice = 3000.0;//最低价double highPrice = 20000.0;//最高价List<Good> goods = goodDao.findByPriceBetween(lowPrice, highPrice);for (Good g : goods) {System.out.println(g);}}
}