Spring Boot整合ElasticSearch和Mysql 附案例源码
导读
前二天,写了一篇ElasticSearch7.8.1从入门到精通的(点我直达),但是还没有整合到SpringBoot中,下面演示将ElasticSearch和mysql整合到Spring Boot中,附演示源码。
项目介绍
模仿NBA网站
网址地址:点我直达
接口开发
- 将数据库数据导入到ElasticSearch
- 通过姓名查找球员
- 通过国家或者球队查询球员
- 通过姓名字母查找球员
项目搭建
SpringBoot整合ElasticSearch和Mysql
数据库数据
将百度云盘里的sql,在mysql上运行即可
链接: https://pan.baidu.com/s/1MJaJy8isfVnPha00tlS8_w 密码: u3dg
项目结构
pom.xml
<?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.3.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.cyb</groupId> <artifactId>yb_search</artifactId> <version>0.0.1-SNAPSHOT</version> <name>yb_search</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--ElasticSearch相关开始--> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.8.1</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.8.1</version> </dependency> <!--ElasticSearch相关结束--> <!--fastjson相关开始--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency> <!--fastjson相关结束--> <!--druid相关开始--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <!--druid相关结束--> <!--mybatis与springboot兼容包相关开始--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency> <!--mybatis与springboot兼容包相关结束--> <!--mysql相关开始--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version> </dependency> <!--mysql相关结束--> <!--commons-lang3相关开始--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.11</version> </dependency> <!--commons-lang3相关结束--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <!-- <exclusions>--> <!-- <exclusion>--> <!-- <groupId>org.junit.vintage</groupId>--> <!-- <artifactId>junit-vintage-engine</artifactId>--> <!-- </exclusion>--> <!-- </exclusions>--> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
注意
我本地安装的ElasticSearch版本是7.8.1,引入pom的ES依赖的话,最好版本一致,否则可能出现版本兼容问题!!!!!!!!!!!
application.properties
# 端口号 server.port=8083 # 数据库配置 spring.datasource.url=jdbc:mysql://localhost:3306/nba?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root # 连接池 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 表明使用Druid连接池 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #初始化时建立物理连接的个数。 spring.datasource.druid.initial-size=5 #最大连接池数量 spring.datasource.druid.max-active=20 #最小连接池数量 spring.datasource.druid.min-idle=5 #获取连接时最大等待时间,单位毫秒 spring.datasource.druid.max-wait=3000 #是否缓存preparedStatement,也就是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle,在mysql下建议关闭。 spring.datasource.druid.pool-prepared-statements=false #要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 spring.datasource.druid.max-open-prepared-statements= -1 #配置检测可以关闭的空闲连接间隔时间 spring.datasource.druid.time-between-eviction-runs-millis=60000 # 配置连接在池中的最小生存时间 spring.datasource.druid.min-evictable-idle-time-millis= 300000 spring.datasource.druid.max-evictable-idle-time-millis= 400000 # 日志相关 logging.level.root: info logging.level.com.cyb.search: debug # ElasticSearch配置 elasticsearch.host:192.168.199.170 elasticsearch.port=9200
EsConfig.java(ES配置类)
package com.cyb.search.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @ClassName:EsConfig * @Description:ES配置文件 * @Author:chenyb * @Date:2020/8/10 11:25 下午 * @Versiion:1.0 */ @Configuration //获取application.properties或application.yml获取里面的参数值 @ConfigurationProperties(prefix = "elasticsearch") public class EsConfig { private String host; private Integer port; //初始化RestHighLevelClient @Bean(destroyMethod = "close") public RestHighLevelClient client(){ return new RestHighLevelClient(RestClient.builder( new HttpHost(host,port,"http") )); } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public Integer getPort() { return port; } public void setPort(Integer port) { this.port = port; } }
NBAPlayerDao.java
package com.cyb.search.dao; import com.cyb.search.model.NBAPlayer; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; @Mapper public interface NBAPlayerDao { @Select("select * from nba_player") List<NBAPlayer> selectAll(); }
NBAPlayer.java(实体类)
package com.cyb.search.model; /** * @ClassName:NBAPlayer * @Description:TODO * @Author:chenyb * @Date:2020/8/10 11:39 下午 * @Versiion:1.0 */ public class NBAPlayer { private Integer id; private String countryEn; private String country; private String code; private String displayAffiliation; private String displayName; private Integer draft; private String schoolType; private String weight; private Integer playYear; private String jerseyNo; private Long birthDay; private String birthDayStr; private String displayNameEn; private String position; private Double heightValue; private String playerId; private String teamCity; private String teamCityEn; private String teamName; private String teamNameEn; private String teamConference; private String teamConferenceEn; private Integer age; public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public String getBirthDayStr() { return birthDayStr; } public void setBirthDayStr(String birthDayStr) { this.birthDayStr = birthDayStr; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getDisplayAffiliation() { return displayAffiliation; } public void setDisplayAffiliation(String displayAffiliation) { this.displayAffiliation = displayAffiliation; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public Integer getDraft() { return draft; } public void setDraft(Integer draft) { this.draft = draft; } public String getSchoolType() { return schoolType; } public void setSchoolType(String schoolType) { this.schoolType = schoolType; } public String getWeight() { return weight; } public void setWeight(String weight) { this.weight = weight; } public Integer getPlayYear() { return playYear; } public void setPlayYear(Integer playYear) { this.playYear = playYear; } public String getCountryEn() { return countryEn; } public void setCountryEn(String countryEn) { this.countryEn = countryEn; } public String getTeamCityEn() { return teamCityEn; } public void setTeamCityEn(String teamCityEn) { this.teamCityEn = teamCityEn; } public String getTeamNameEn() { return teamNameEn; } public void setTeamNameEn(String teamNameEn) { this.teamNameEn = teamNameEn; } public String getTeamConference() { return teamConference; } public void setTeamConference(String teamConference) { this.teamConference = teamConference; } public String getTeamConferenceEn() { return teamConferenceEn; } public void setTeamConferenceEn(String teamConferenceEn) { this.teamConferenceEn = teamConferenceEn; } public String getJerseyNo() { return jerseyNo; } public void setJerseyNo(String jerseyNo) { this.jerseyNo = jerseyNo; } public Long getBirthDay() { return birthDay; } public void setBirthDay(Long birthDay) { this.birthDay = birthDay; } public String getDisplayNameEn() { return displayNameEn; } public void setDisplayNameEn(String displayNameEn) { this.displayNameEn = displayNameEn; } public String getPosition() { return position; } public void setPosition(String position) { this.position = position; } public Double getHeightValue() { return heightValue; } public void setHeightValue(Double heightValue) { this.heightValue = heightValue; } public String getPlayerId() { return playerId; } public void setPlayerId(String playerId) { this.playerId = playerId; } public String getTeamCity() { return teamCity; } public void setTeamCity(String teamCity) { this.teamCity = teamCity; } public String getTeamName() { return teamName; } public void setTeamName(String teamName) { this.teamName = teamName; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } }
NBAPlayerService.java(接口)
package com.cyb.search.service; import com.cyb.search.model.NBAPlayer; import java.io.IOException; public interface NBAPlayerService { boolean addPlayer(NBAPlayer player,String id) throws IOException; }
NBAPlayerServiceImpl.java
package com.cyb.search.service.impl; import com.alibaba.fastjson.JSONObject; import com.cyb.search.model.NBAPlayer; import com.cyb.search.service.NBAPlayerService; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.cglib.beans.BeanMap; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * @ClassName:NBAPlayerServiceImpl * @Description:TODO * @Author:chenyb * @Date:2020/8/11 10:09 下午 * @Versiion:1.0 */ @Service public class NBAPlayerServiceImpl implements NBAPlayerService { @Resource private RestHighLevelClient client; /** * 添加 * @param player 实体类 * @param id 编号 * @return * @throws IOException */ @Override public boolean addPlayer(NBAPlayer player, String id) throws IOException { IndexRequest request=new IndexRequest("nba_latest").id(id).source(beanToMap(player)); IndexResponse response = client.index(request, RequestOptions.DEFAULT); System.out.println(JSONObject.toJSON(response)); return false; } /** * 对象转map * @param bean * @param <T> * @return */ public static <T> Map<String,Object> beanToMap(T bean){ Map<String,Object> map=new HashMap<>(); if (bean!=null){ BeanMap beanMap=BeanMap.create(bean); for(Object key:beanMap.keySet()){ if (beanMap.get(key)!=null){ map.put(key+"",beanMap.get(key)); } } } return map; } }
基础功能实现
往ES中插入一条数据
查看数据库数据
根据ID查ES
单元测试
修改
单元测试
删除
单元测试
将数据库中的数据导入ES
通过名字查找球员
测试
通过国家或球队查找球员
测试
通过字母查球员
测试
项目源码下载
链接: https://pan.baidu.com/s/1QJ8wvjg7TPqGSP-68qpSIQ 密码: d26m
SpringBoot整合ES优化通用工具类 二
依赖项
<?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.5.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>ybchen-es</artifactId> <version>0.0.1-SNAPSHOT</version> <name>ybchen-es</name> <description>SpringBoot 整合ES</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <!-- 代码自动生成依赖 begin --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> <!-- velocity --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.0</version> </dependency> <!-- 代码自动生成依赖 end--> <!--springBoot整合swagger3.0--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> <!--ElasticSearch相关开始--> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.6.2</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.6.2</version> </dependency> <!--ElasticSearch相关结束--> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.18</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
配置文件
spring.application.name=es-service # ===== 自定义swagger配置 ===== # swagger.enable=true swagger.application-name= ${spring.application.name} swagger.application-version=1.0 swagger.application-description=es api #mysql spring.datasource.url=jdbc:mysql://localhost:3306/nba?useUnicode=true&characterEncoding=utf8 spring.datasource.username=root spring.datasource.password=rootroot spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver #mybatis-plus配置控制台打印完整带参数SQL语句 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl # ElasticSearch配置 elasticsearch.host=47.116.143.16 elasticsearch.port=9200 elasticsearch.userName=es elasticsearch.password=es
ES客户端
package com.ybchen.service; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.reactor.IOReactorConfig; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; /** * es 客户端 * @author: chenyanbin 2022-11-06 14:08 */ @Service @Slf4j public class EsService { @Value("${elasticsearch.host}") String esHosts; @Value("${elasticsearch.port}") int esPort; @Value("${elasticsearch.userName}") String esUserName; @Value("${elasticsearch.password}") String esPassword; private static volatile RestHighLevelClient instance; /** * 获取es客户端 * * @return */ public RestHighLevelClient getInstance() { if (instance == null) { synchronized (EsService.class) { if (instance == null) { instance = createInstance(); } } } return instance; } /** * 创建es客户端 * * @return */ private RestHighLevelClient createInstance() { List<HttpHost> httpHostsList = new ArrayList<>(); //填充es数据 httpHostsList.add(new HttpHost(esHosts, esPort)); //es客户端构建者 RestClientBuilder clientBuilder = RestClient.builder(httpHostsList.get(0)); //异步链接延时配置 clientBuilder.setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder .setConnectTimeout(5000) //5秒 .setSocketTimeout(5000) .setConnectionRequestTimeout(5000) ); //异步链接数配置 clientBuilder.setHttpClientConfigCallback(httpClientBuilder -> { //最大连接数100个 httpClientBuilder.setMaxConnTotal(100); //最大路由连接数 httpClientBuilder.setMaxConnPerRoute(100); //==================ES有账号密码-开始====================== final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(esUserName, esPassword)); httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); //==================ES有账号密码-结束====================== // 设置KeepAlive为5分钟的时间,不设置默认为-1,也就是持续连接,然而这会受到外界的影响比如Firewall,会将TCP连接单方面断开,从而会导致Connection reset by peer的报错 // 参考github解决方案:https://github.com/TFdream/Elasticsearch-learning/issues/30 httpClientBuilder.setKeepAliveStrategy((response, context) -> TimeUnit.MINUTES.toMillis(3)) .setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).setSoKeepAlive(true).build()); return httpClientBuilder; }); return new RestHighLevelClient(clientBuilder); } /** * 30秒一次检查es状态 */ @Scheduled(fixedRate = 30 * 1000) public void heartbeatToES() { try { RequestOptions requestOptions = RequestOptions.DEFAULT.toBuilder().build(); boolean result = getInstance().ping(requestOptions); log.info("检查ES状态:{}", result); } catch (Exception e) { log.error("检查ES状态发生异常:{}", e); } } }
工具类
package com.ybchen.service; import com.ybchen.model.NbaPlayerDO; import com.ybchen.vo.EsDocumentVo; import java.util.List; import java.util.Map; public interface NbaService { /** * 添加文档 * * @param indexName 索引名称 * @param docId 文档id * @param jsonBody json数据 * @return */ boolean addDoc( String indexName, String docId, String jsonBody ); /** * 异步添加文档 * * @param indexName 索引名称 * @param docId 文档id * @param jsonBody json数据 * @return */ boolean asyncAddDoc( String indexName, String docId, String jsonBody ); /** * 批量添加文档 * * @param indexName 索引名称 * @param documentVoList 文档对象集合 * @return */ boolean batchAddDoc( String indexName, List<EsDocumentVo> documentVoList ); /** * 批量异步添加文档 * * @param indexName 索引名称 * @param documentVoList 文档对象集合 * @return */ boolean batchAsyncAddDoc( String indexName, List<EsDocumentVo> documentVoList ); /** * 根据文档id搜索文档 * * @param indexName 索引名称 * @param docId 文档id * @return */ Map<String, Object> getDocumentByDocId( String indexName, String docId ); /** * 根据文档id更新文档 * * @param indexName 索引名称 * @param docId 文档id * @param jsonBody json数据 * @return */ boolean updateDocumentByDocId( String indexName, String docId, String jsonBody ); /** * 批量异步根据文档id更新文档 * * @param indexName 索引名称 * @param documentVoList 文档对象集合 * @return */ boolean batchAsyncUpdateDocumentByDocId( String indexName, List<EsDocumentVo> documentVoList ); /** * 根据文档id删除文档 * * @param indexName 索引名称 * @param docId 文档id * @return */ boolean deleteDocumentByDocId( String indexName, String docId ); /** * 根据索引名称全部删除文档 * * @param indexName 索引名称 * @return */ boolean deleteAllDocumentByIndexName( String indexName ); /** * 通过名字查找球员 * * @param indexName 索引名称 * @param key 文档字段 * @param value 文档值 * @param pageNum 第几页 * @param pageSize 一页多少条 * @param highlightField 高亮字段 * @return */ List<NbaPlayerDO> searchMatch( String indexName, String key, String value, int pageNum, int pageSize, String highlightField ); }
package com.ybchen.service.impl; import com.alibaba.fastjson2.JSON; import com.ybchen.model.NbaPlayerDO; import com.ybchen.service.EsService; import com.ybchen.service.NbaService; import com.ybchen.vo.EsDocumentVo; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @author: chenyanbin 2022-11-06 14:36 */ @Service @Slf4j public class NbaServiceImpl implements NbaService { @Autowired EsService esService; /** * 添加文档 * * @param indexName 索引名称 * @param docId 文档id * @param jsonBody json数据 * @return */ @Override public boolean addDoc( String indexName, String docId, String jsonBody ) { IndexRequest indexRequest = new IndexRequest(); //添加索引名称 indexRequest.index(indexName); //文档id indexRequest.id(docId); //json数据 indexRequest.source(jsonBody, XContentType.JSON); try { //添加文档 esService.getInstance().index( indexRequest, RequestOptions.DEFAULT ); log.info("添加文档成功,indexName:{},docId:{},jsonBody:{}", indexName, docId, jsonBody ); return true; } catch (Exception e) { log.error("添加文档失败,indexName:{},docId:{},jsonBody:{},异常信息:{}", indexName, docId, jsonBody, e ); } return false; } /** * 异步添加文档 * * @param indexName 索引名称 * @param docId 文档id * @param jsonBody json数据 * @return */ @Override public boolean asyncAddDoc( String indexName, String docId, String jsonBody ) { IndexRequest indexRequest = new IndexRequest(); //添加索引名称 indexRequest.index(indexName); //文档id indexRequest.id(docId); //json数据 indexRequest.source(jsonBody, XContentType.JSON); //异步批量插入 esService.getInstance().indexAsync( indexRequest, RequestOptions.DEFAULT, new ActionListener<IndexResponse>() { @Override public void onResponse(IndexResponse indexResponse) { log.info("异步添加文档成功,indexName:{},docId:{},jsonBody:{}", indexName, docId, jsonBody ); } @Override public void onFailure(Exception e) { log.error("异步添加文档失败,indexName:{},docId:{},jsonBody:{},异常信息:{}", indexName, docId, jsonBody, e ); } }); return true; } /** * 批量添加文档 * * @param indexName 索引名称 * @param documentVoList 文档对象集合 * @return */ @Override public boolean batchAddDoc( String indexName, List<EsDocumentVo> documentVoList ) { if (documentVoList == null || documentVoList.size() == 0) { return false; } //批量文档请求对象 BulkRequest bulkRequest = new BulkRequest(); for (EsDocumentVo esDocumentVo : documentVoList) { IndexRequest indexRequest = new IndexRequest(); //添加索引名称 indexRequest.index(indexName); //文档id indexRequest.id(esDocumentVo.getDocId()); //json数据 indexRequest.source(esDocumentVo.getJsonBody(), XContentType.JSON); bulkRequest.add(indexRequest); } try { //批量添加 esService.getInstance().bulk(bulkRequest, RequestOptions.DEFAULT); log.info("批量添加文档成功,indexName:{},documentVoList:{}", indexName, documentVoList ); return true; } catch (Exception e) { log.error("批量添加文档失败,indexName:{},documentVoList:{},异常信息:{}", indexName, documentVoList, e ); } return false; } /** * 批量异步添加文档 * * @param indexName 索引名称 * @param documentVoList 文档对象集合 * @return */ @Override public boolean batchAsyncAddDoc( String indexName, List<EsDocumentVo> documentVoList ) { if (documentVoList == null || documentVoList.size() == 0) { return false; } //批量文档请求对象 BulkRequest bulkRequest = new BulkRequest(); for (EsDocumentVo esDocumentVo : documentVoList) { IndexRequest indexRequest = new IndexRequest(); //添加索引名称 indexRequest.index(indexName); //文档id indexRequest.id(esDocumentVo.getDocId()); //json数据 indexRequest.source(esDocumentVo.getJsonBody(), XContentType.JSON); bulkRequest.add(indexRequest); } //批量添加 esService.getInstance().bulkAsync(bulkRequest, RequestOptions.DEFAULT, new ActionListener<BulkResponse>() { @Override public void onResponse(BulkResponse bulkItemResponses) { log.info("批量异步添加文档成功,indexName:{},documentVoList:{}", indexName, documentVoList ); } @Override public void onFailure(Exception e) { log.info("批量异步添加文档失败,indexName:{},documentVoList:{},异常信息:{}", indexName, documentVoList, e ); } }); return true; } /** * 根据文档id搜索文档 * * @param indexName 索引名称 * @param docId 文档id * @return */ @Override public Map<String, Object> getDocumentByDocId( String indexName, String docId ) { GetRequest getRequest = new GetRequest(); getRequest.index(indexName); getRequest.id(docId); try { //查询 GetResponse response = esService.getInstance().get(getRequest, RequestOptions.DEFAULT); return response.getSource(); } catch (Exception e) { log.error("根据文档id搜索文档失败,indexName:{},docId:{},异常信息:{}", indexName, docId, e ); } return null; } /** * 根据文档id更新文档 * * @param indexName 索引名称 * @param docId 文档id * @param jsonBody json数据 * @return */ @Override public boolean updateDocumentByDocId( String indexName, String docId, String jsonBody ) { UpdateRequest updateRequest = new UpdateRequest(); //添加索引名称 updateRequest.index(indexName); //文档id updateRequest.id(docId); //json数据 updateRequest.doc(jsonBody, XContentType.JSON); try { //更新文档 esService.getInstance().update(updateRequest, RequestOptions.DEFAULT); log.error("根据文档id更新文档成功,indexName:{},docId:{},jsonBody:{}", indexName, docId, jsonBody ); return true; } catch (Exception e) { log.error("根据文档id更新文档失败,indexName:{},docId:{},jsonBody:{},异常信息:{}", indexName, docId, jsonBody, e ); } return false; } /** * 批量异步根据文档id更新文档 * * @param indexName 索引名称 * @param documentVoList 文档对象集合 * @return */ @Override public boolean batchAsyncUpdateDocumentByDocId( String indexName, List<EsDocumentVo> documentVoList ) { if (documentVoList == null || documentVoList.size() == 0) { return false; } BulkRequest bulkRequest = new BulkRequest(); for (EsDocumentVo esDocumentVo : documentVoList) { UpdateRequest updateRequest = new UpdateRequest(); //添加索引名称 updateRequest.index(indexName); //文档id updateRequest.id(esDocumentVo.getDocId()); //json数据 updateRequest.doc(esDocumentVo.getJsonBody(), XContentType.JSON); bulkRequest.add(updateRequest); } esService.getInstance().bulkAsync(bulkRequest, RequestOptions.DEFAULT, new ActionListener<BulkResponse>() { @Override public void onResponse(BulkResponse bulkItemResponses) { log.info("批量异步根据文档id更新文档成功,indexName:{},documentVoList:{}", indexName, documentVoList ); } @Override public void onFailure(Exception e) { log.info("批量异步根据文档id更新文档失败,indexName:{},documentVoList:{},异常信息:{}", indexName, documentVoList, e ); } }); return true; } /** * 根据文档id删除文档 * * @param indexName 索引名称 * @param docId 文档id * @return */ @Override public boolean deleteDocumentByDocId(String indexName, String docId) { DeleteRequest deleteRequest = new DeleteRequest(); //添加索引名称 deleteRequest.index(indexName); //文档id deleteRequest.id(docId); try { esService.getInstance().delete(deleteRequest, RequestOptions.DEFAULT); log.error("根据文档id删除文档成功,indexName:{},docId:{}", indexName, docId ); return true; } catch (Exception e) { log.error("根据文档id删除文档失败,indexName:{},docId:{},异常信息:{}", indexName, docId, e ); } return false; } /** * 根据索引名称全部删除文档 * * @param indexName 索引名称 * @return */ @Override public boolean deleteAllDocumentByIndexName(String indexName) { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(); deleteIndexRequest.indices(indexName); try { esService.getInstance().indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); log.error("根据索引名称全部删除文档成功,indexName:{}", indexName ); return true; } catch (Exception e) { log.error("根据索引名称全部删除文档失败,indexName:{},异常信息:{}", indexName, e ); } return false; } /** * 通过名字查找球员 * * @param indexName 索引名称 * @param key 文档字段 * @param value 文档值 * @param pageNum 第几页 * @param pageSize 一页多少条 * @param highlightField 高亮字段 * @return */ @Override public List<NbaPlayerDO> searchMatch( String indexName, String key, String value, int pageNum, int pageSize, String highlightField ) { //>>>>>>构建查找对象 SearchRequest searchRequest = new SearchRequest(); //添加索引名称 searchRequest.indices(indexName); //>>>>>>>类似于查询语句,相当于:where后面的条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //构建查询条件 displayname:查询字段名称 searchSourceBuilder.query(QueryBuilders.matchQuery(key, value)); //从第0条开始 searchSourceBuilder.from((pageNum - 1) * pageSize); //查1000条记录 searchSourceBuilder.size(pageSize); //>>>>>>>>>设置高亮样式 HighlightBuilder highlightBuilder = new HighlightBuilder(); //设置高亮字段 highlightBuilder.field(new HighlightBuilder.Field(highlightField)); //高亮样式,前缀样式;后缀样式 highlightBuilder.preTags("<span style=color:red>").postTags("</span>"); searchSourceBuilder.highlighter(highlightBuilder); //>>>>>>将筛选条件添加到查找对象中 searchRequest.source(searchSourceBuilder); try { SearchResponse response = esService.getInstance().search(searchRequest, RequestOptions.DEFAULT); //总共查询出来的数据总条数 long total = response.getHits().getTotalHits().value; //本次数据查询条数 int length = response.getHits().getHits().length; //拿到数据 SearchHit[] hits = response.getHits().getHits(); List<NbaPlayerDO> nbaPlayerDOList = new ArrayList<>(); for (SearchHit hit : hits) { //单条记录 Map<String, Object> sourceAsMap = hit.getSourceAsMap(); //高亮字段 Map<String, HighlightField> highlightFields = hit.getHighlightFields(); HighlightField hField = highlightFields.get(highlightField); //>>>>>>>重新组装高亮字段和值 if (hField != null) { StringBuilder sbValue = new StringBuilder(); for (Text text : hField.fragments()) { sbValue.append(text); } sourceAsMap.put(highlightField, sbValue.toString()); } nbaPlayerDOList.add(JSON.parseObject(JSON.toJSONString(sourceAsMap), NbaPlayerDO.class)); } return nbaPlayerDOList; } catch (Exception e) { log.error("搜索发生了异常:{}", e); } return new ArrayList<>(); } }
package com.ybchen.vo; import lombok.Data; import java.io.Serializable; /** * ES文档vo * @author: chenyanbin 2022-11-07 22:10 */ @Data public class EsDocumentVo implements Serializable { /** * 文档id */ private String docId; /** * 文档数据 */ private String jsonBody; }
实体类
package com.ybchen.model; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import lombok.Data; import lombok.EqualsAndHashCode; import java.io.Serializable; import java.math.BigDecimal; /** * <p> * * </p> * * @author chenyanbin * @since 2022-11-06 */ @Data @EqualsAndHashCode(callSuper = false) @TableName("nba_player") @ApiModel(value = "NbaPlayerDO对象", description = "") public class NbaPlayerDO implements Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id", type = IdType.AUTO) private Integer id; @TableField("countryEn") private String countryen; @TableField("teamName") private String teamname; @TableField("birthDay") private Long birthday; private String country; @TableField("teamCityEn") private String teamcityen; private String code; @TableField("displayAffiliation") private String displayaffiliation; @TableField("displayName") private String displayname; @TableField("schoolType") private String schooltype; @TableField("teamConference") private String teamconference; @TableField("teamConferenceEn") private String teamconferenceen; private String weight; @TableField("teamCity") private String teamcity; @TableField("playYear") private Integer playyear; @TableField("jerseyNo") private String jerseyno; @TableField("teamNameEn") private String teamnameen; private Integer draft; @TableField("displayNameEn") private String displaynameen; @TableField("birthDayStr") private String birthdaystr; @TableField("heightValue") private BigDecimal heightvalue; private String position; private Integer age; @TableField("playerId") private String playerid; }
Mapper
package com.ybchen.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.ybchen.model.NbaPlayerDO; /** * <p> * Mapper 接口 * </p> * * @author chenyanbin * @since 2022-11-06 */ public interface NbaPlayerMapper extends BaseMapper<NbaPlayerDO> { }
单元测试
package com.ybchen.service.impl; import com.alibaba.fastjson2.JSON; import com.ybchen.EsApplication; import com.ybchen.mapper.NbaPlayerMapper; import com.ybchen.model.NbaPlayerDO; import com.ybchen.service.NbaService; import com.ybchen.vo.EsDocumentVo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.ArrayList; import java.util.List; import java.util.Map; @SpringBootTest(classes = EsApplication.class) class NbaServiceImplTest { @Autowired NbaService nbaService; @Autowired NbaPlayerMapper nbaPlayerMapper; private final String NBA_INDEX_NAME = "nba_player"; /** * 添加文档 */ @Test public void addDoc() { NbaPlayerDO nbaPlayerDO = new NbaPlayerDO(); nbaPlayerDO.setCountryen("中国"); boolean flag = nbaService.addDoc(NBA_INDEX_NAME, "188", JSON.toJSONString(nbaPlayerDO)); System.err.println(flag); } /** * 异步添加文档 */ @Test public void asyncAddDoc() { NbaPlayerDO nbaPlayerDO = new NbaPlayerDO(); nbaPlayerDO.setCountryen("美国"); boolean flag = nbaService.asyncAddDoc(NBA_INDEX_NAME, "191", JSON.toJSONString(nbaPlayerDO)); System.err.println(flag); while (true) { } } /** * 批量添加文档 */ @Test public void batchAddDoc() { List<EsDocumentVo> list = new ArrayList<EsDocumentVo>() { { EsDocumentVo vo1 = new EsDocumentVo(); vo1.setDocId("192"); NbaPlayerDO nbaPlayerDO1 = new NbaPlayerDO(); nbaPlayerDO1.setCountryen("中国"); vo1.setJsonBody(JSON.toJSONString(nbaPlayerDO1)); this.add(vo1); EsDocumentVo vo2 = new EsDocumentVo(); vo1.setDocId("193"); NbaPlayerDO nbaPlayerDO2 = new NbaPlayerDO(); nbaPlayerDO2.setCountryen("俄罗斯"); vo2.setJsonBody(JSON.toJSONString(nbaPlayerDO2)); this.add(vo2); } }; boolean flag = nbaService.batchAddDoc(NBA_INDEX_NAME, list); System.err.println(flag); } /** * 异步批量添加文档 */ @Test public void batchAsyncAddDoc() { List<EsDocumentVo> list = new ArrayList<EsDocumentVo>() { { EsDocumentVo vo1 = new EsDocumentVo(); vo1.setDocId("194"); NbaPlayerDO nbaPlayerDO1 = new NbaPlayerDO(); nbaPlayerDO1.setCountryen("中国"); vo1.setJsonBody(JSON.toJSONString(nbaPlayerDO1)); this.add(vo1); EsDocumentVo vo2 = new EsDocumentVo(); vo1.setDocId("195"); NbaPlayerDO nbaPlayerDO2 = new NbaPlayerDO(); nbaPlayerDO2.setCountryen("俄罗斯"); vo2.setJsonBody(JSON.toJSONString(nbaPlayerDO2)); this.add(vo2); } }; boolean flag = nbaService.batchAsyncAddDoc(NBA_INDEX_NAME, list); System.err.println(flag); while (true) { } } /** * 根据文档id获取文档数据 */ @Test public void getDocumentByDocId() { Map<String, Object> documentByDocId = nbaService.getDocumentByDocId(NBA_INDEX_NAME, "188"); System.out.println(JSON.toJSON(documentByDocId)); } @Test public void updateDocumentByDocId() { } @Test public void batchAsyncUpdateDocumentByDocId() { } /** * 根据文档id删除文档 */ @Test void deleteDocumentByDocId() { boolean flag = nbaService.deleteDocumentByDocId(NBA_INDEX_NAME, "188"); System.out.println(flag); } /** * 根据索引名称删除所有文档 */ @Test void deleteAllDocumentByIndexName() { boolean flag = nbaService.deleteAllDocumentByIndexName(NBA_INDEX_NAME); System.out.println(flag); } /** * 导入所有球员数据到es */ @Test public void importAll() { List<NbaPlayerDO> nbaPlayerDOList = nbaPlayerMapper.selectList(null); List<EsDocumentVo> documentVoList = new ArrayList<>(nbaPlayerDOList.size()); for (NbaPlayerDO playerDO : nbaPlayerDOList) { EsDocumentVo vo = new EsDocumentVo(); vo.setDocId(playerDO.getId().toString()); vo.setJsonBody(JSON.toJSONString(playerDO)); documentVoList.add(vo); } boolean flag = nbaService.batchAsyncAddDoc(NBA_INDEX_NAME, documentVoList); System.err.println(flag); while (true) { } } /** * 根据名称查找球员 */ @Test public void searchMatch() { List<NbaPlayerDO> nbaPlayerDOList = nbaService.searchMatch( NBA_INDEX_NAME, "displaynameen", "james", 1, 1000, "displaynameen" ); System.err.println(JSON.toJSON(nbaPlayerDOList)); } }
源码下载
链接: https://pan.baidu.com/s/1NpwqP3YCjLm5nLFKDZFzUQ?pwd=ubiv 提取码: ubiv