平凡也就两个字: 懒和惰;
成功也就两个字: 苦和勤;
优秀也就两个字: 你和我。
跟着我从0学习JAVA、spring全家桶和linux运维等知识,带你从懵懂少年走向人生巅峰,迎娶白富美!
关注微信公众号【 IT特靠谱 】,每天都会分享技术心得~
创建的项目名称为:elasticsearch-demo
选择需要依赖的基础jar包。
创建成功后,项目结构如下图所示:
org.springframework.boot
spring-boot-starter-data-elasticsearch
由于之前的文章中,我们安装的是7.6.2版本的elasticsearch。而创建的springboot项目是2.4.0版本的,其默认依赖的是7.9.3版本的elasticsearch相关包。
如果项目用到的es相关包版本与安装的es服务版本不一致,在实际使用es进行CRUD的时候就会出现一些版本导致的未知问题。因此,我们需要调整项目依赖的es版本或者调整springboot版本!
恰好!springboot的2.3.0.RELEASE版本,默认依赖的就是7.6.2版本的es相关依赖包。那么我们调整springboot版本为2.3.0.RELEASE就达到目的了!
将springboot版本调整为:2.3.0.RELEASE
自动下载完依赖后,查看依赖的es相关包版本:
到此,项目组依赖的es相关包版本与es服务版本相同了!都为:7.6.2版本
#指定es服务访问url
spring:
elasticsearch:
rest:
uris: http://localhost:9200
创建实体类:User.java
package com.test.elasticsearchdemo.entity;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* 用户实体类
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "pms", type = "_doc") //es注解1。指定es索引名和类型。es8版本中会废弃掉type类型(实际上默认的type为"_doc")。
public class User implements Serializable {
/**
* 数据id Id注解:指明pms索引_doc类型中的文档的id为数据的id。如果insert到es中的数据的id值为空,那么es会自动生成一个唯一的uuid作为文档id
*/
@Id
private Long id;
/**
* 用户名 Text:其取代了string,当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用text类型。 设置text类型以后,字段内容会被分词,在生成倒排索引以前,字符串会被分词器分成一个个词项。text类型的字段不用于排序,很少用于聚合(termsAggregation除外)。
* ik_max_word:指示了该字段使用到的分词算法,为:最细粒度分词
*/
@Field(analyzer = "ik_max_word", type = FieldType.Text)
private String name;
/**
* 用户密码 注意:password字段添加@Transient注解,也就意味着该字段不会被写入es中!
*/
@Transient
private String password;
/**
* 用户手机号 Keyword:关键词。该类型字段只能通过"精确查找"方式索引到,不会对该字段分词后与查询条件匹配
*/
@Field(type = FieldType.Keyword)
private String mobile;
/**
* 用户年龄 Integer:整数类型
*/
@Field(type = FieldType.Integer)
private Integer age;
/**
* 用户生日 Date:日期类型
*/
@Field(type = FieldType.Date)
private Date birthday;
/**
* 删除标识 Boolean:bool类型
*/
@Field(type = FieldType.Boolean)
private Boolean deleteStatus;
/**
* 用户标签 Nested:嵌套类型
*/
@Field(type = FieldType.Nested)
private List
创建自定义es仓库接口:EsUserRepository.java,继承ElasticsearchRepository.java接口。
ElasticsearchRepository及其父接口封装了一些常用的CRUD方法。因此我们只需要继承该接口,就可以进行简单的增删改查操作了。当然如果希望实现更复杂的查询操作,就需要搭配RestHighLevelClient客户端来使用!
package com.test.elasticsearchdemo.repository;
import com.test.elasticsearchdemo.entity.User;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* ES用户repository
*/
public interface EsUserRepository extends ElasticsearchRepository {
/**
* 根据名称查询
*/
List findByName(String name);
/**
* 分页搜索查询:分页查询名称或手机号相同的信息
*/
Page findByNameOrMobile(String name, String mobile, Pageable page);
}
创建service接口类:UserService.java
package com.test.elasticsearchdemo.service;
import com.test.elasticsearchdemo.dto.request.PageByNameOrMobileRequest;
import com.test.elasticsearchdemo.entity.User;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
/**
* 用户service接口类
*/
public interface UserService {
/**
* 保存一条数据
*/
void insert(User user);
/**
* 批量保存数据
*/
void insertBatch(List users);
/**
* 更新一条数据
*/
void update(User user);
/**
* 删除一条数据
* @param id 删除数据文档id(文档id与数据id相同)
*/
void deleteById(Long id);
/**
* 根据名称查询
*/
List listByName(String name);
/**
* 根据id查询唯一数据
*/
User findById(Long id);
/**
* 分页搜索查询:分页查询名称或手机号相同的信息
*/
Page findByNameOrMobile(PageByNameOrMobileRequest request);
/**
* 分页搜索查询:分页查询名称或手机号相同的信息,并按age升序排序
*/
Page pageByConditions(PageByNameOrMobileRequest request);
}
创建service接口实现类:UserServiceImpl.java
package com.test.elasticsearchdemo.service.impl;
import com.test.elasticsearchdemo.dto.request.PageByNameOrMobileRequest;
import com.test.elasticsearchdemo.entity.User;
import com.test.elasticsearchdemo.repository.EsUserRepository;
import com.test.elasticsearchdemo.service.UserService;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/**
* 用户接口实现类
*/
@Service
public class UserServiceImpl implements UserService {
/**
* 一般CRUD查询用这个!spring-data风格
*/
@Autowired
private EsUserRepository esUserRepository;
/**
* es复杂操作用这个!底层用的是RestHighLevelClient客户端
*/
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
/***********************EsUserRepository新增、更新和删除***********************/
/**
* 新增一条数据
*/
@Override
public void insert(User user) {
esUserRepository.save(user);
}
/**
* 批量保存数据
*/
@Override
public void insertBatch(List users) {
esUserRepository.saveAll(users);
}
/**
* 更新一条数据 说明:如果es数据库中存在相同id的数据,那么就是更新数据!否则就是新增数据。
*/
@Override
public void update(User user) {
esUserRepository.save(user);
}
/**
* 删除一条数据
*
* @param id 删除数据文档id(文档id与数据id相同)
*/
@Override
public void deleteById(Long id) {
esUserRepository.deleteById(id);
}
/***********************EsUserRepository普通查询***********************/
/**
* 根据名称查询
*/
@Override
public List listByName(String name) {
return esUserRepository.findByName(name);
}
/**
* 根据id查询唯一数据
*/
@Override
public User findById(Long id) {
Optional optional = esUserRepository.findById(id);
return optional.orElse(null);
}
/**
* 分页搜索查询:分页查询名称或手机号相同的信息
*/
@Override
public Page findByNameOrMobile(PageByNameOrMobileRequest request) {
Pageable pageable = PageRequest.of(request.getPage()-1, request.getSize());
return esUserRepository.findByNameOrMobile(request.getName(), request.getMobile(), pageable);
}
/***********************RestHighLevelClient高级查询***********************/
@Override
public Page pageByConditions(PageByNameOrMobileRequest request) {
//构建查询条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//1.排序
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("age").order(SortOrder.ASC));
//2.分页
Pageable pageable = PageRequest.of(request.getPage() - 1, request.getSize());
nativeSearchQueryBuilder.withPageable(pageable);
//3.过滤
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termQuery("deleteStatus", false));
nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
//4.搜索条件
if (StringUtils.isEmpty(request.getMobile()) && StringUtils.isEmpty(request.getName())) {
nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
} else {
List filterFunctionBuilders = new ArrayList<>();
if (!StringUtils.isEmpty(request.getMobile())) {
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("mobile", request.getMobile()),
ScoreFunctionBuilders.weightFactorFunction(10)));
}
if (!StringUtils.isEmpty(request.getName())) {
filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("name", request.getName()),
ScoreFunctionBuilders.weightFactorFunction(7)));
}
FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
filterFunctionBuilders.toArray(builders);
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
.scoreMode(FunctionScoreQuery.ScoreMode.SUM)
.setMinScore(3);
nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
}
NativeSearchQuery query = nativeSearchQueryBuilder.build();
SearchHits searchHits = elasticsearchRestTemplate.search(query, User.class);
if (searchHits.getTotalHits() <= 0) {
return new PageImpl<>(null, pageable, 0);
}
List userList = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
return new PageImpl<>(userList, pageable, searchHits.getTotalHits());
}
}
创建控制器类:UserController.java
package com.test.elasticsearchdemo.controller;
import com.test.elasticsearchdemo.dto.request.PageByNameOrMobileRequest;
import com.test.elasticsearchdemo.entity.User;
import com.test.elasticsearchdemo.service.UserService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 用户api接口控制器
*/
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserService userService;
/***********************EsUserRepository新增、更新和删除***********************/
/**
* 保存一条数据
*/
@PostMapping("insert")
public void insert(@RequestBody User user) {
userService.insert(user);
}
/**
* 批量保存数据
*/
@PostMapping("insertBatch")
public void insertBatch(@RequestBody List users) {
userService.insertBatch(users);
}
/**
* 更新一条数据
*/
@PostMapping("update")
public void update(@RequestBody User user) {
userService.update(user);
}
/**
* 删除一条数据
*/
@GetMapping("deleteById")
public void deleteById(Long id) {
userService.deleteById(id);
}
/***********************EsUserRepository普通查询***********************/
/**
* 根据名称查询
*/
@GetMapping("listByName")
public List listByName(String name) {
return userService.listByName(name);
}
/**
* 根据id查询唯一数据
*/
@GetMapping("findById")
public User findById(Long id) {
return userService.findById(id);
}
/**
* 分页搜索查询:分页查询名称或手机号相同的信息
*/
@PostMapping("findPageByNameOrMobile")
public Page findPageByNameOrMobile(@RequestBody PageByNameOrMobileRequest request) {
return userService.findByNameOrMobile(request);
}
/***********************highLevelClient高级查询***********************/
/**
* 分页搜索查询:分页查询名称或手机号相同的信息,并按age升序排序
*/
@PostMapping("pageByConditions")
public Page pageByConditions(@RequestBody PageByNameOrMobileRequest request) {
return userService.pageByConditions(request);
}
}
到此,springboot整合Elasticsearch,并实现了基于repository和restHighLevel两种方式实现了数据的CRUD。
(1) 商务合作微信号:M9392W
(2) 购物商城: 扫码即可进入博主开发的小程序购物商城,享超大优惠购物,支持一下博主吧~
(3) 博主微信公众号:IT特靠谱,学习更多开发实战技巧!