新建业务包
├─config # 配置文件
├─controller # 控制器
├─entity # 实体映射
│ └─response # 响应实体
└─service # 相关业务
在 response 包下,新建两个类,分别是 ResultCode(interface), ResponseResult.java:
ResultCode.java:
/**
* @author BNTang
*/
public interface ResultCode {
/**
* 成功状态码
*/
Integer SUCCESS = 20000;
/**
* 失败的状态码
*/
Integer ERROR = 20001;
}
ResponseResult.java:
public class ResponseResult {
private ResponseResult() {
}
(value = "是否成功")
private Boolean success;
(value = "状态码")
private Integer code;
(value = "返回消息")
private String message;
(value = "返回的数据")
private Map<String, Object> RESPONSE_DATA_MAP = new HashMap<>();
/**
* 提供工具方法
*/
public static ResponseResult ok() {
ResponseResult responseResult = new ResponseResult();
responseResult.setSuccess(true);
responseResult.setCode(ResultCode.SUCCESS);
responseResult.setMessage("成功");
return responseResult;
}
public static ResponseResult error() {
ResponseResult responseResult = new ResponseResult();
responseResult.setSuccess(false);
responseResult.setCode(ResultCode.ERROR);
responseResult.setMessage("失败");
return responseResult;
}
public ResponseResult success(Boolean success) {
this.setSuccess(success);
return this;
}
public ResponseResult message(String message) {
this.setMessage(message);
return this;
}
public ResponseResult code(Integer code) {
this.setCode(code);
return this;
}
public ResponseResult data(String key, Object value) {
this.RESPONSE_DATA_MAP.put(key, value);
return this;
}
public ResponseResult data(Map<String, Object> map) {
this.setRESPONSE_DATA_MAP(map);
return this;
}
}
然后接下来就可以来看本文需要介绍的索引相关的操作内容了:
索引操作
查看索引是否存在
首先在 service 包当中新建一个 IElasticSearchService.java 接口,在当中添加一个判断索引是否存在的约束方法如下:
/**
* @author BNTang
* @version V1.0
* @project SpringBoot-ElasticSearch-Pro
* @date Created in 2022/3/5 /005 18:41
* @description elasticsearch 接口
**/
public interface IElasticSearchService {
/**
* 查看索引是否存在
*
* @param indexName 索引名称
* @return boolean true,代表存在,false,代表不存在
*/
boolean seeIndexIsNoExists(String indexName);
}
还是在 service 包当中创建所对应的实现类来实现这个判断索引是否存在的方法, 新建一个 ElasticSearchServiceImpl.java:
/**
* @author BNTang
* @version V1.0
* @project SpringBoot-ElasticSearch-Pro
* @date Created in 2022/3/5 /005 18:45
* @description
**/
public class ElasticSearchServiceImpl implements IElasticSearchService {
private final Log logger = LogFactory.getLog(ElasticSearchServiceImpl.class);
private ElasticsearchClient elasticsearchClient;
public void setElasticsearchClient(ElasticsearchClient elasticsearchClient) {
this.elasticsearchClient = elasticsearchClient;
}
public boolean seeIndexIsNoExists(String indexName) {
ExistsRequest existsRequest = new ExistsRequest.Builder().index(indexName)
.build();
try {
BooleanResponse booleanResponse = this.elasticsearchClient.indices()
.exists(existsRequest);
return booleanResponse.value();
} catch (IOException e) {
logger.error("see Index Is No Exists error", e);
}
return false;
}
}
然后,在 controller 包当中创建一个控制器用来测试用,ElasticSearchController.java:
/**
* @author BNTang
* @version V1.0
* @project SpringBoot-ElasticSearch-Pro
* @date Created in 2022/3/5 /005 18:48
* @description
**/
("ElasticSearch Api Controller")
("elasticSearch-controller")
public class ElasticSearchController {
private ElasticSearchServiceImpl elasticSearchService;
public void setElasticSearchService(ElasticSearchServiceImpl elasticSearchService) {
this.elasticSearchService = elasticSearchService;
}
("查看索引是否存在")
("seeIndexIsNoExists")
public boolean seeIndexIsNoExists(String indexName) {
return this.elasticSearchService.seeIndexIsNoExists(indexName);
}
}
然后就是启动工程,访问 swagger,进行接口调试即可,这一步博主不贴出来了自行测试。
创建索引
在 IElasticSearchService.java 当中添加如下约束方法:
/**
* 创建索引
*
* @param indexName 索引名称
* @param numOfShards 分片数
* @param properties 属性
* @return boolean true,代表创建成功,false,代表创建失败
*/
boolean createIndex(String indexName, int numOfShards, Map<String, Property> properties);
在 ElasticSearchServiceImpl.java 实现类当中进行实现:
public boolean createIndex(String indexName, int numOfShards, Map<String, Property> properties) {
// 创建的映射处理
TypeMapping typeMapping = new TypeMapping.Builder()
.properties(properties)
.build();
IndexSettings indexSettings = new IndexSettings.Builder()
.numberOfShards(String.valueOf(numOfShards))
.build();
CreateIndexRequest createIndexRequest = new CreateIndexRequest.Builder()
.index(indexName)
.mappings(typeMapping)
.settings(indexSettings)
.build();
try {
return Optional
.ofNullable(this.elasticsearchClient.indices().create(createIndexRequest).acknowledged())
.orElse(Boolean.FALSE);
} catch (IOException e) {
logger.error("create Index error", e);
}
return false;
}
控制器:
"创建索引")(
("createIndex")
public ResponseResult createIndex(String indexName) {
Map<String, Property> propertyMap = new HashMap<>();
propertyMap.put("id", new Property(new LongNumberProperty.Builder().index(true).store(true).build()));
propertyMap.put("name", new Property(new TextProperty.Builder().index(true).analyzer("ik_max_word").store(true).build()));
if (this.elasticSearchService.createIndex(indexName, 1, propertyMap)) {
return ResponseResult.ok();
}
return ResponseResult.error();
}
然后就是启动工程,访问 swagger,进行接口调试即可,这一步博主不贴出来了自行测试。
删除索引
接口:
/**
* 删除索引
*
* @param indexNameList 索引名称列表
* @return boolean
*/
boolean deleteIndex(List<String> indexNameList);
实现类:
public boolean deleteIndex(List<String> indexNameList) {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest.Builder()
.index(indexNameList)
.build();
try {
return this.elasticsearchClient.indices()
.delete(deleteIndexRequest).acknowledged();
} catch (IOException e) {
logger.error("delete Index error", e);
}
return false;
}
控制器:
"删除索引")(
("deleteIndex")
public ResponseResult deleteIndex( List<String> indexNameList) {
if (this.elasticSearchService.deleteIndex(indexNameList)) {
return ResponseResult.ok();
}
return ResponseResult.error();
}
根据 ID 查询(批量OR单个)
更改 IElasticSearchService.java 接口新增泛型:
public interface IElasticSearchService<T>
然后在新增两个查询数据的方法约束:
/**
* 根据id获取文档
*
* @param index index
* @param id id
* @param clazz clazz 把查询的结果封装成对象的实体
* @return T
*/
T getById(String index, String id, Class<T> clazz);
/**
* 根据id列表获取文档
*
* @param index index
* @param idList id
* @param clazz clazz
* @return List<T>
*/
List<T> getByIdList(String index, List<String> idList, Class<T> clazz);
修改 ElasticSearchServiceImpl.java 实现类,也需要添加所对应的泛型:
public class ElasticSearchServiceImpl<T> implements IElasticSearchService<T>
实现根据ID查询的业务方法,可以批量也可以单个:
public T getById(String index, String id, Class<T> clazz) {
GetRequest getRequest = new GetRequest.Builder()
.index(index)
.id(id)
.build();
try {
return this.elasticsearchClient.get(getRequest, clazz)
.source();
} catch (IOException e) {
logger.error("get By Id error", e);
}
return null;
}
public List<T> getByIdList(String index, List<String> idList, Class<T> clazz) {
try {
List<T> tList = new ArrayList<>(idList.size());
for (String id : idList) {
GetRequest getRequest = new GetRequest.Builder()
.index(index)
.id(id)
.build();
T source = this.elasticsearchClient.get(getRequest, clazz)
.source();
tList.add(source);
}
return tList;
} catch (IOException e) {
logger.error("get By Id List error", e);
}
return null;
}
然后在控制器调用之前首先在新建一个实体类用来封装从ES当中查询出来的数据新建 Goods.java:
/**
* @author BNTang
* @version V1.0
* @project SpringBoot-ElasticSearch-Pro
* @date Created in 2022/4/3 /003 23:20
* @description
**/
public class Goods implements Serializable {
/**
* id
*/
private String id;
/**
* 名字
*/
private String name;
/**
* 价格
*/
private BigDecimal price;
/**
* 描述
*/
private String description;
/**
* 创建日期
*/
private String create_date;
}
修改控制器进行使用,测试一下根据 ID 查询出来的结果和批量的接口即可,这里博主不再赘述,只是贴出所对应的控制器代码,修改 ElasticSearchController.java:
private ElasticSearchServiceImpl<Goods> elasticSearchService;
public void setElasticSearchService(ElasticSearchServiceImpl<Goods> elasticSearchService) {
this.elasticSearchService = elasticSearchService;
}
value = "根据id获取文档数据")(
("/api/v1/getById/{index}/{id}")
public ResponseResult getById( String index, String id) {
return ResponseResult.ok().data("goods", this.elasticSearchService.getById(index, id, Goods.class));
}
(value = "根据id数组获取文档数据")
("/api/v1/getByIdList")
public ResponseResult getByIdList( (value = "ids") List<String> ids,
(value = "index") String index) {
return ResponseResult.ok().data("goods", this.elasticSearchService.getByIdList(index, ids, Goods.class));
}
分页查询
修改接口添加分页查询约束方法:
/**
* 分页查询
*
* @param index index
* @param pageNo pageNo
* @param pageSize pageSize
* @param clazz clazz
* @return 查询结果
*/
List<T> searchByPages(String index, Integer pageNo, Integer pageSize, Class<T> clazz);
实现类:
public List<T> searchByPages(String index, Integer pageNo, Integer pageSize, Class<T> clazz) {
SearchRequest searchRequest = new SearchRequest.Builder()
.index(Collections.singletonList(index))
.from(pageNo)
.size(pageSize)
.build();
List<T> res = new ArrayList<>();
try {
SearchResponse<T> searchResponse = this.elasticsearchClient.search(searchRequest, clazz);
HitsMetadata<T> hitsMetadata = searchResponse.hits();
hitsMetadata.hits().forEach(action -> res.add(action.source()));
return res;
} catch (IOException e) {
logger.error("search By Pages error", e);
}
return null;
}
控制器:
value = "分页查询文档")(
("/getAll")
public ResponseResult getAll(String index, int pageNo, int pageSize) {
return ResponseResult.ok().data("goods", this.elasticSearchService.searchByPages(index, pageNo, pageSize, Goods.class));
}
分页条件查询
接口:
/**
* 分页条件查询
*
* @param index index
* @param pageNo 当前页
* @param pageSize 每页多少条数据
* @param clazz clazz 封装的实现
* @return 查询结果
*/
List<T> searchByQuery(String index, String queryString, Integer pageNo, Integer pageSize, Class<T> clazz);
实现类:
public List<T> searchByQuery(String index, String queryString, Integer pageNo, Integer pageSize, Class<T> clazz) {
// 1.构建查询的对象
QueryStringQuery stringQuery = new QueryStringQuery.Builder()
.fields("name", "description")
.query(queryString)
.build();
Query query = new Query.Builder()
.queryString(stringQuery)
.build();
// 2.搜索
SearchRequest searchRequest = new SearchRequest.Builder()
.index(index)
.from(pageNo)
.size(pageSize)
.query(query)
.build();
try {
return this.elasticsearchClient.search(searchRequest, clazz)
.hits().hits().stream()
.map(Hit::source)
.collect(Collectors.toList());
} catch (IOException e) {
logger.error("search By Query error", e);
}
return null;
}
控制器:
value = "分页条件查询")(
("/querySearch")
public ResponseResult getAll(String index, String queryString, Integer pageNo, Integer pageSize) {
return ResponseResult.ok().data("goods", this.elasticSearchService.searchByQuery(index, queryString, pageNo, pageSize, Goods.class));
}
分页条件查询高亮
接口:
/**
* 分页条件高亮查询
*
* @param index index
* @param pageNo 当前页
* @param pageSize 每页多少条数据
* @param clazz clazz 封装的实现
* @return 查询结果
*/
List<T> searchByQueryHighlight(String index, String queryString, Integer pageNo, Integer pageSize, Class<T> clazz);
实现类:
public List<T> searchByQueryHighlight(String index, String queryString, Integer pageNo, Integer pageSize, Class<T> clazz) {
// 1.构建查询的对象
QueryStringQuery stringQuery = new QueryStringQuery.Builder()
.fields("name", "description")
.query(queryString)
.build();
Query query = new Query.Builder()
.queryString(stringQuery)
.build();
// 高亮显示
HighlightField highlightField = new HighlightField.Builder()
.matchedFields("name")
.preTags("<span style=\"color:red\">")
.postTags("</span>")
.build();
Highlight highlight = new Highlight.Builder()
.fields("name", highlightField)
.requireFieldMatch(false)
.build();
// 2.搜索请求
SearchRequest searchRequest = new SearchRequest.Builder()
.index(index)
.from(pageNo)
.size(pageSize)
.query(query)
.highlight(highlight)
.build();
try {
return this.elasticsearchClient.search(searchRequest, clazz)
.hits()
.hits()
.stream()
.map(mapper -> {
String name = mapper.highlight()
.get("name")
.get(0);
Goods goods = (Goods) mapper.source();
Goods anElse = Optional.ofNullable(goods)
.orElse(new Goods());
anElse.setName(name);
return mapper.source();
}).collect(Collectors.toList());
} catch (IOException e) {
logger.error("search By Query Highlight error", e);
}
return null;
}
控制器:
value = "分页条件查询高亮")(
("/api/v1/searchByQueryHighlight")
public ResponseResult searchByQueryHighlight(String index, String queryString, Integer pageNo, Integer pageSize) {
return ResponseResult.ok().data("goods", this.elasticSearchService.searchByQueryHighlight(index, queryString, pageNo, pageSize, Goods.class));
}