目录

  • 1.版本选择
  • 2.ElasticSearch 安装
    • 2.1 新增配置
    • 2.2 设置登录密码
    • 2.3 ElasticSearch作为windows服务启动
  • 3 ElasticSearch-head 插件安装
  • 4 安装IK中文分词插件
  • 5. 基本语法
    • 5.1 索引
      • 5.1.1 创建索引
      • 5.1.2 删除索引
      • 5.1.3 查询索引
      • 5.1.4 查询所有索引
    • 5.2 文档
      • 5.2.1 创建文档
      • 5.2.2 删除文档
      • 5.2.3 查询文档
  • 6. Spring Boot 集成

1.版本选择

版本选择参照
Spring官方
ElasticSearch官方

本文采用版本
Spring Boot-2.3.1.RELEASE
ElasticSearch 7.6.2
ElasticSearch-head

2.ElasticSearch 安装

运行平台:win10
安装解压后,进入解压目录下的config 文件夹下修改 elasticsearch.yml配置文件

2.1 新增配置

# 支持跨域
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,Content-Type
# 开启xpack
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

2.2 设置登录密码

进入bin文件夹下在cmd中以管理员身份执行 elasticsearch-setup-passwords interactive
分别为elastic, kibana, logstash_system,beats_system四个用户设置密码即可(用户名是固定的)。
设置完毕后,进入bin文件夹下执行运行elasticsearch.bat启动ElasticSearch
启动没问题,在浏览器输入:http://127.0.0.1:9200/


输入密码,用户名:elastic,密码:123456

出现此界面说明,安装成功。

2.3 ElasticSearch作为windows服务启动

cmd 进入 bin 文件夹下执行 elasticsearch-service.bat install即可。

3 ElasticSearch-head 插件安装

ElasticSearch-head 是一款ES前端展示页面,具体资料参考github详细介绍。
首先安装 node.js
git clone该项目后,进入目录cmd 执行 npm install 安装依赖,完毕后继续执行 npm run start即可启动项目。因为开启了登录验证,所以登录地址为
http://localhost:9100/?auth_user=elastic&auth_password=123456
首页展示:

4 安装IK中文分词插件

选择7.6.2对应版本(版本不对应会导致安装失败):下载地址
在ES安装目录中的plugins文件夹下新建文件夹并命名为ik(任意命名),copy压缩包在ik文件下解压,重启es服务即安装成功。
测试分词:
url:http://localhost:9200/_analyze
Request Method: post
application/json
请求体:

 {"analyzer": "ik_max_word","text":     "琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!"
}

响应类似即成功

5. 基本语法

5.1 索引

5.1.1 创建索引

整个请求遵循 REST API接口规范,语法参考官方ES官方文档。
因为加入了账号密码认证,所以在postman中需要Authorization授权访问。
如下配置即可

postman:
put http://localhost:9200/employee_index

{"mappings": {"properties": {"id": {"type": "integer"},"name": {"type": "keyword"},"age": {"type": "integer"},"detail": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_max_word"}}},"settings": {"number_of_shards": 3,"number_of_replicas": 0}
}
curl --location --request PUT 'http://localhost:9200/employee_index' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY=' \
--header 'Content-Type: application/json' \
--data-raw '{"mappings": {"properties": {"id": {"type": "integer"},"name": {"type": "keyword"},"age": {"type": "integer"},"detail": {"type": "text","analyzer": "ik_max_word","search_analyzer": "ik_max_word"}}},"settings": {"number_of_shards": 3,"number_of_replicas": 0}
}'
5.1.2 删除索引

postman:
DELETE http://localhost:9200/employee_index

curl --location --request DELETE 'http://localhost:9200/employee_index' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY='
5.1.3 查询索引

postman:
GET http://localhost:9200/employee_index

curl --location --request GET 'http://localhost:9200/employee_index' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY='
5.1.4 查询所有索引

postman:
GET http://localhost:9200/_cat/indices?v

curl --location --request GET 'http://localhost:9200/_cat/indices?v' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY='

5.2 文档

5.2.1 创建文档

postman:
PUT http://localhost:9200/employee_index/_doc/1

{"id": 1,"name": "陈十一","age": 18,"detail": "琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!"
}
curl --location --request PUT 'http://localhost:9200/employee_index/_doc/1' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY=' \
--header 'Content-Type: application/json' \
--data-raw '{"id": 1,"name": "陈十一","age": 18,"detail": "琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!"
}'
5.2.2 删除文档

postman:
DELETE http://localhost:9200/employee_index/_doc/1

curl --location --request DELETE 'http://localhost:9200/employee_index/_doc/1' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY='
5.2.3 查询文档

postman:
GET http://localhost:9200/employee_index/_search

一般查询

{"query": {"match":{"detail":"治愈君"}}
}
curl --location --request GET 'http://localhost:9200/employee_index/_search' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY=' \
--header 'Content-Type: application/json' \
--data-raw '{"query": {"match":{"detail":"治愈君"}}
}'

高亮显示查询
postman:

{"query": {"match": {"detail": "治愈君"}},"highlight": {"fields": {"detail": {"type": "unified"}},"pre_tags": ["<font color='red'>"],"post_tags": ["</font>"]}
}
curl --location --request GET 'http://localhost:9200/employee_index/_search' \
--header 'Authorization: Basic ZWxhc3RpYzoxMjM0NTY=' \
--header 'Content-Type: application/json' \
--data-raw '{"query": {"match": {"detail": "治愈君"}},"highlight": {"fields": {"detail": {"type": "unified"}},"pre_tags": ["<font color='\''red'\''>"],"post_tags": ["</font>"]}
}'

6. Spring Boot 集成

可通过Spring Quickstart 快速创建boot项目或IntelliJ IDEA直接创建。
pom.xml
maven配置
修改boot版本

<version>2.3.1.RELEASE</version>

添加ES依赖,版本一定要对应

<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-elasticsearch</artifactId><version>4.0.9.RELEASE</version></dependency>

yml加入配置(自定义的配置)

es:host: 127.0.0.1port: 9200user-name: elasticpassword: 123456connect-num: 100connect-per-route: 100

加载es配置

package com.zhiyu.common.config.elasticsearch;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/*** @author zhiyu* @since 2021/8/27 17:52*/
@ConfigurationProperties(prefix = "es")
@Data
public class EsConnectionProperties {/*** 主机地址*/private String host;/*** 端口*/private int port;/*** ES用户名*/private String userName;/*** ES密码*/private String password;/*** 最大总连接数*/private int connectNum;/*** 每个路由值的最大连接数*/private int connectPerRoute;
}

配置Factory 类

package com.zhiyu.common.config.elasticsearch;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.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;/*** elasticsearch 工厂类** @author zhiyu* @since 2021/8/27 17:52*/
public class EsClientSpringFactory {private static final Logger log = LoggerFactory.getLogger(EsClientSpringFactory.class);private static final int CONNECT_TIMEOUT_MILLIS = 1000;private static final int SOCKET_TIMEOUT_MILLIS = 30000;private static final int CONNECTION_REQUEST_TIMEOUT_MILLIS = 500;private static int MAX_CONN_PER_ROUTE ;private static int MAX_CONN_TOTAL ;private static HttpHost httpHost;private static String userName;private static String password;private RestClientBuilder builder;private RestClient restClient;private RestHighLevelClient restHighLevelClient;private static final EsClientSpringFactory ES_CLIENT_SPRING_FACTORY = new EsClientSpringFactory();private EsClientSpringFactory() {}public static EsClientSpringFactory build(HttpHost host, String uName, String pwd,Integer maxConnectNum, Integer maxConnectPerRoute) {httpHost = host;userName = uName;password = pwd;MAX_CONN_TOTAL = maxConnectNum;MAX_CONN_PER_ROUTE = maxConnectPerRoute;return ES_CLIENT_SPRING_FACTORY;}public void init() {builder = RestClient.builder(httpHost);setConnectTimeOutConfig();setMuftiConnectConfig();restClient = builder.build();restHighLevelClient = new RestHighLevelClient(builder);log.info("初始化ES工厂类");}/*** 配置连接时间延时*/public void setConnectTimeOutConfig() {builder.setRequestConfigCallback(requestConfigBuilder -> {requestConfigBuilder.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);requestConfigBuilder.setSocketTimeout(SOCKET_TIMEOUT_MILLIS);requestConfigBuilder.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT_MILLIS);return requestConfigBuilder;});}/*** 使用异步httpclient时设置并发连接数*/public void setMuftiConnectConfig() {//连接Elasticsearch集群final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(userName, password));builder.setHttpClientConfigCallback(httpClientBuilder -> {httpClientBuilder.setMaxConnTotal(MAX_CONN_TOTAL);httpClientBuilder.setMaxConnPerRoute(MAX_CONN_PER_ROUTE);httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);return httpClientBuilder;});}public RestClient getClient() {return restClient;}public RestHighLevelClient getRhlClient() {return restHighLevelClient;}public void close() {if (restClient != null) {try {restClient.close();} catch (IOException e) {log.error(e.getMessage());}}log.info("ES客户端实例关闭");}
}

注入bean

package com.zhiyu.common.config.elasticsearch;import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;/*** @author zhiyu* @since 2021/8/27 17:52*/
@Configuration
@ComponentScan(basePackageClasses = EsClientSpringFactory.class)
@EnableConfigurationProperties(value = EsConnectionProperties.class)
public class EsConnectionBean {private final EsConnectionProperties esConnectionProperties;public EsConnectionBean(EsConnectionProperties esConnectionProperties) {this.esConnectionProperties = esConnectionProperties;}@Beanpublic HttpHost httpHost() {return new HttpHost(esConnectionProperties.getHost(), esConnectionProperties.getPort(), "http");}@Bean(initMethod = "init", destroyMethod = "close")public EsClientSpringFactory getFactory() {return EsClientSpringFactory.build(httpHost(),esConnectionProperties.getUserName(),esConnectionProperties.getPassword(),esConnectionProperties.getConnectNum(),esConnectionProperties.getConnectPerRoute());}@Beanpublic RestClient getRestClient() {return getFactory().getClient();}@Beanpublic RestHighLevelClient getRhlClient() {return getFactory().getRhlClient();}
}

构建入参DTO实体

package com.zhiyu.common.entity.dto.elasticsearch;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author zhiyu* @since 2021/8/27 17:52*/
@Data
@ApiModel(value = "文档")
public class IndexDocDto {@ApiModelProperty(value = "索引名称",example = "employee_index")private String index;@ApiModelProperty(value = "索引ID",example = "1")private String id;@ApiModelProperty(value = "数据体 JSON格式")private String source;
}
package com.zhiyu.common.entity.dto.elasticsearch;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author zhiyu* @since 2021/8/27 17:52*/
@Data
@ApiModel(value = "索引")
public class IndexDto {@ApiModelProperty(value = "索引名称",example = "employee_index")private String index;@ApiModelProperty(value = "分片设置信息",example = "json格式")private String settings;@ApiModelProperty(value = "mapping设置信息",example = "json格式")private String mappings;
}
package com.zhiyu.common.entity.dto.elasticsearch;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @author zhiyu* @since 2021/8/27 17:52*/
@Data
@ApiModel(value = "搜索")
public class SearchDocDto {@ApiModelProperty(value = "索引名称", example = "employee_index")private String index;@ApiModelProperty(value = "搜索内容", example = "治愈君")private String keywords;@ApiModelProperty(value = "第几页", example = "1")private Integer pageNo;@ApiModelProperty(value = "每页多少条", example = "10")private Integer pageSize;@ApiModelProperty(value = "关键字是否高亮", example = "false")private Boolean isHighlight = false;
}

crud 接口

package com.zhiyu.common.service;import com.zhiyu.common.entity.dto.elasticsearch.IndexDocDto;
import com.zhiyu.common.entity.dto.elasticsearch.SearchDocDto;
import com.zhiyu.common.utils.response.ResponseData;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.search.SearchHit;import java.util.List;/*** @author zhiyu* @since 2021/8/31 15:34*/
public interface ElasticsearchService {/*** 创建索引** @param index* @param settings* @param mappings* @return*/ResponseData createIndex(String index, String settings, String mappings);/*** 添加setting配置** @param createIndexRequest* @param setting* @return*/void buildIndexSetting(CreateIndexRequest createIndexRequest, String setting);/*** 添加mapping配置** @param createIndexRequest* @param mapping* @return*/void buildIndexMapping(CreateIndexRequest createIndexRequest, String mapping);/*** 删除索引** @param indexName 索引名称* @return*/ResponseData deleteIndex(String indexName);/*** 添加索引文档** @param indexDocDto* @return*/ResponseData createIndexDoc(IndexDocDto indexDocDto);/*** 索引更新文档** @param indexDocDto* @return*/ResponseData updateIndexDoc(IndexDocDto indexDocDto);/*** 删除文档* @param index* @param id* @return*/ResponseData  deleteIndexDoc(String index, String id);/*** 批量添加** @param indexDocDtoList* @return*/ResponseData bulkInsert(List<IndexDocDto> indexDocDtoList);/*** 全文检索** @param searchDocDto* @return*/ResponseData allSearch(SearchDocDto searchDocDto);/*** 获取索引所有设置的字段** @param index* @return*/String[] getAllFieldNames(String index);/*** 获取索引中需要全文检索的字段** @param index* @return*/String[] getQueryFieldNames(String index);/*** 获取搜索结果并是否高亮** @param searchHits* @param isHighlight* @return*/List getSearchList(SearchHit[] searchHits, Boolean isHighlight);
}

实现类

package com.zhiyu.common.service.impl;import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zhiyu.common.entity.dto.elasticsearch.IndexDocDto;
import com.zhiyu.common.entity.dto.elasticsearch.SearchDocDto;
import com.zhiyu.common.exception.BusinessException;
import com.zhiyu.common.service.ElasticsearchService;
import com.zhiyu.common.utils.response.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.TotalHits;
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.delete.DeleteResponse;
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.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
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.stereotype.Service;
import org.springframework.util.CollectionUtils;import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** @author zhiyu* @since 2021/8/31 15:39*/
@Service
@Slf4j
public class ElasticsearchServiceImpl implements ElasticsearchService {private final RestHighLevelClient restHighLevelClient;public ElasticsearchServiceImpl(RestHighLevelClient restHighLevelClient) {this.restHighLevelClient = restHighLevelClient;}@Overridepublic ResponseData createIndex(String index, String settings, String mappings) {try {CreateIndexResponse createIndexResponse = null;if (!existsIndex(index)) {CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);buildIndexSetting(createIndexRequest, settings);buildIndexMapping(createIndexRequest, mappings);createIndexRequest.settings();createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);}return ResponseData.success(createIndexResponse == null ? "索引已存在" : JSON.toJSONString(createIndexResponse));} catch (Exception e) {log.error("索引创建失败", e);return ResponseData.error(e.getMessage());}}@Overridepublic void buildIndexSetting(CreateIndexRequest createIndexRequest, String setting) {createIndexRequest.settings(setting, XContentType.JSON);}@Overridepublic void buildIndexMapping(CreateIndexRequest createIndexRequest, String mapping) {createIndexRequest.mapping(mapping, XContentType.JSON);}@Overridepublic ResponseData deleteIndex(String indexName) {try {DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);return ResponseData.success("索引删除成功");} catch (Exception e) {log.error("索引删除失败", e);return ResponseData.error(e.getMessage());}}@Overridepublic ResponseData createIndexDoc(IndexDocDto indexDocDto) {IndexRequest request = new IndexRequest();request.index(indexDocDto.getIndex());request.id(indexDocDto.getId());request.source(indexDocDto.getSource(), XContentType.JSON);try {IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT);return ResponseData.success(JSON.toJSONString(index));} catch (IOException e) {log.error("创建文档失败", e);return ResponseData.error(e.getMessage());}}@Overridepublic ResponseData updateIndexDoc(IndexDocDto indexDocDto) {try {UpdateRequest updateRequest = new UpdateRequest(indexDocDto.getIndex(), indexDocDto.getId());updateRequest.doc(indexDocDto.getSource(), XContentType.JSON);UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);return ResponseData.success(JSON.toJSONString(updateResponse));} catch (Exception e) {log.error("更新文档失败", e);return ResponseData.error(e.getMessage());}}@Overridepublic ResponseData deleteIndexDoc(String index, String id) {try {DeleteRequest deleteRequest = new DeleteRequest(index, id);DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);return ResponseData.success(JSON.toJSONString(deleteResponse));} catch (IOException e) {log.error("删除文档失败", e);return ResponseData.error(e.getMessage());}}/*** 判断索引是否存在** @param index* @return* @throws IOException*/private boolean existsIndex(String index) throws IOException {GetIndexRequest request = new GetIndexRequest(index);request.indices();return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);}@Overridepublic ResponseData bulkInsert(List<IndexDocDto> indexDocDtoList) {try {if (CollectionUtils.isEmpty(indexDocDtoList)) {return ResponseData.error("插入数据为空");}BulkRequest bulkAddRequest = new BulkRequest();for (IndexDocDto indexDocDto : indexDocDtoList) {IndexRequest indexRequest = new IndexRequest(indexDocDto.getIndex());indexRequest.source(indexDocDto.getSource(), XContentType.JSON);bulkAddRequest.add(indexRequest);}BulkResponse bulkResponse = restHighLevelClient.bulk(bulkAddRequest, RequestOptions.DEFAULT);return ResponseData.success(JSON.toJSONString(bulkResponse));} catch (Exception e) {log.error("批量添加文档失败", e);return ResponseData.error(e.getMessage());}}@Overridepublic ResponseData allSearch(SearchDocDto searchDocDto) {try {int pageNo = searchDocDto.getPageNo();int pageSize = searchDocDto.getPageSize();int startIndex = (pageNo - 1) * pageSize;//获取索引名称String index = searchDocDto.getIndex();IPage<Map<String, Object>> page = new Page<>(pageNo, pageSize);List<Map<String, Object>> searchList;SearchRequest searchRequest = new SearchRequest(index);SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();String[] fieldNames = getQueryFieldNames(index);// 模糊匹配MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery(searchDocDto.getKeywords(), fieldNames);// TODO 若设置matchQueryBuilder.fuzziness(Fuzziness.AUTO) 高亮查询失效,待解决sourceBuilder.query(matchQueryBuilder.maxExpansions(10));sourceBuilder.from(startIndex);sourceBuilder.size(pageSize);if (searchDocDto.getIsHighlight()) {HighlightBuilder highlightBuilder = new HighlightBuilder();Arrays.stream(fieldNames).forEach(e -> {highlightBuilder.field(e).highlighterType("unified").preTags("<font color='red'>").postTags("</font>");});sourceBuilder.highlighter(highlightBuilder);}searchRequest.source(sourceBuilder);SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);RestStatus restStatus = searchResponse.status();if (RestStatus.OK.equals(restStatus)) {SearchHits hits = searchResponse.getHits();TotalHits totalHits = hits.getTotalHits();float maxScore = hits.getMaxScore();log.info("totalHits:{}", totalHits);log.info("maxScore:{}", maxScore);SearchHit[] searchHits = hits.getHits();searchList = getSearchList(searchHits, searchDocDto.getIsHighlight());page.setRecords(searchList);page.setTotal(totalHits.value);}return ResponseData.success(page);} catch (Exception e) {log.error("查询失败", e);throw new BusinessException(e.getMessage());}}@Override@SuppressWarnings("all")public String[] getAllFieldNames(String index) {try {GetIndexRequest getIndexRequest = new GetIndexRequest(index);getIndexRequest.indices();GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);Map<String, Object> map = getIndexResponse.getMappings().get(index).getSourceAsMap();LinkedHashMap<String, LinkedHashMap> linkedHashMap = (LinkedHashMap<String, LinkedHashMap>) (map.get("properties"));return linkedHashMap.keySet().toArray(new String[linkedHashMap.keySet().size()]);} catch (Exception e) {throw new BusinessException(e.getMessage());}}@Override@SuppressWarnings("unchecked")public String[] getQueryFieldNames(String index) {try {GetIndexRequest indexRequest = new GetIndexRequest(index);indexRequest.indices();GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(indexRequest, RequestOptions.DEFAULT);Map<String, Object> map = getIndexResponse.getMappings().get(index).getSourceAsMap();LinkedHashMap<String, LinkedHashMap<String, Object>> linkedHashMap = (LinkedHashMap<String, LinkedHashMap<String, Object>>) map.get("properties");List<String> fieldNames = new ArrayList<>();for (Map.Entry<String, LinkedHashMap<String, Object>> entry : linkedHashMap.entrySet()) {String key = entry.getKey();LinkedHashMap<String, Object> linkedValue = entry.getValue();String typeValue = (String) linkedValue.get("type");if (typeValue != null) {if ("text".equals(typeValue) || "object".equals(typeValue)) {fieldNames.add(key);}} else {fieldNames.add(key);}}int listSize = fieldNames.size();return fieldNames.toArray(new String[listSize]);} catch (Exception e) {throw new BusinessException(e.getMessage());}}@Overridepublic List<Map<String, Object>> getSearchList(SearchHit[] searchHits, Boolean isHighlight) {List<Map<String, Object>> searchList = new ArrayList<>(16);for (SearchHit hit : searchHits) {Map<String, Object> sourceAsMap = hit.getSourceAsMap();if (isHighlight) {//取高亮结果Map<String, HighlightField> highlightFields = hit.getHighlightFields();for (Map.Entry<String, HighlightField> entry : highlightFields.entrySet()) {String key = entry.getKey();HighlightField highlight = entry.getValue();if (highlight != null) {Text[] fragments = highlight.fragments();if (fragments != null) {String fragmentString = fragments[0].string();sourceAsMap.put(key, fragmentString);}}}}searchList.add(sourceAsMap);}return searchList;}
}

Controller

package com.zhiyu.common.controller;import com.zhiyu.common.entity.dto.elasticsearch.IndexDocDto;
import com.zhiyu.common.entity.dto.elasticsearch.IndexDto;
import com.zhiyu.common.entity.dto.elasticsearch.SearchDocDto;
import com.zhiyu.common.service.ElasticsearchService;
import com.zhiyu.common.utils.response.ResponseData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;/*** @author zhiyu* @since 2021/8/31 16:25*/
@RestController
@RequestMapping("/es")
@Slf4j
@Api(tags = "Elasticsearch功能接口")
public class ElasticsearchController {private final ElasticsearchService esService;public ElasticsearchController(ElasticsearchService esService) {this.esService = esService;}@PostMapping(value = "/index")@ApiOperation(value = "创建索引")public ResponseData createIndex(@RequestBody IndexDto indexDto) {return esService.createIndex(indexDto.getIndex(), indexDto.getSettings(), indexDto.getMappings());}@DeleteMapping(value = "/index/{indexName}")@ApiOperation(value = "删除索引")public ResponseData deleteIndex(@PathVariable String indexName) {return esService.deleteIndex(indexName);}@PostMapping(value = "/doc")@ApiOperation(value = "添加文档")public ResponseData createIndexDoc(@RequestBody IndexDocDto indexDocDto) {return esService.createIndexDoc(indexDocDto);}@PutMapping(value = "/doc")@ApiOperation(value = "更新文档")public ResponseData updateIndexDoc(@RequestBody IndexDocDto indexDocDto) {return esService.updateIndexDoc(indexDocDto);}@DeleteMapping(value = "/doc/{index}/{id}")@ApiOperation(value = "删除文档")public ResponseData deleteIndexDoc(@PathVariable String index, @PathVariable String id) {return esService.deleteIndexDoc(index, id);}@PostMapping(value = "/docList")@ApiOperation(value = "批量添加文档")public ResponseData bulkCreateIndexDoc(@RequestBody List<IndexDocDto> indexDocDtoList) {return esService.bulkInsert(indexDocDtoList);}@PostMapping(value = "/search")@ApiOperation(value = "搜索")public ResponseData search(@RequestBody SearchDocDto searchDocDto) {return esService.allSearch(searchDocDto);}}

postman 接口调用

创建索引 post http://127.0.0.1:8055/common-funtion/es/index

{"index": "employee_index","mappings": "{\"properties\": { \"id\": { \"type\": \"integer\" }, \"name\": { \"type\": \"keyword\" }, \"age\": { \"type\": \"integer\" }, \"detail\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\", \"search_analyzer\": \"ik_max_word\" } }}","settings": "{ \"number_of_shards\": 3, \"number_of_replicas\": 0 }"
}

删除索引 DELETE http://127.0.0.1:8055/common-funtion/es/index/employee_index

创建文档 post http://127.0.0.1:8055/common-funtion/es/doc

{"id": 1,"index": "employee_index","source": "{ \"id\": 1, \"name\": \"陈十一\", \"age\": 18, \"detail\": \"琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!\" }"
}

更新文档 put http://127.0.0.1:8055/common-funtion/es/doc

{"id": 1,"index": "employee_index","source": "{ \"id\": 1, \"name\": \"陈十三\", \"age\": 17, \"detail\": \"琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!\" }"
}

批量添加文档 post http://127.0.0.1:8055/common-funtion/es/docList

[{"id": 1,"index": "employee_index","source": "{ \"id\": 1, \"name\": \"陈十一1\", \"age\": 18, \"detail\": \"琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!\" }"},{"id": 2,"index": "employee_index","source": "{ \"id\": 1, \"name\": \"陈十一2\", \"age\": 18, \"detail\": \"琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!\" }"},{"id": 3,"index": "employee_index","source": "{ \"id\": 1, \"name\": \"陈十一3\", \"age\": 18, \"detail\": \"琴音无声,但治愈君却可依稀听到,他抹去嘴角酒水,喃喃道:“一生孤独,方可有一颗求道之心。但这孤独的滋味,又有几人、能真正的品味,就如这酒,入口辛辣,进腹却化作热流”“我不知那些万年修士,如何熬过这万年的孤寂,但却知晓,若内心没有半点感动之处,修道,只不过修的是自以为道,而非天道!天地不仁,逆天而行之修士,若同样心无感动,则依然不仁,以不仁之心修天地不仁之道,怎能称之为逆天修行,何来逆字?那只不过是顺天而行罢了!”“自古顺天者,为天地之宠儿,这宠儿的背后,却是蝼蚁之身!我之道,非顺天,而是以心中之感动,逆天而行,逆仙而修,求的,不仅是长生,更多的,却是摆脱那背后的蝼蚁之身,此,使之为逆!\" }"}
]

删除文档 DELETE http://127.0.0.1:8055/common-funtion/es/doc/employee_index/1

搜索文档 post http://127.0.0.1:8055/common-funtion/es/search

{"index": "employee_index","isHighlight": true,"keywords": "治愈君","pageNo": 1,"pageSize": 10
}

2021最新! Springboot 2.X集成ElasticSearch 7.6.2(入门版)相关推荐

  1. 2021最新 SpringBoot面试题精选(附刷题小程序)

    推荐使用小程序阅读 为了能让您更加方便的阅读 本文所有的面试题目均已整理至小程序<面试手册> 可以通过微信扫描(或长按)下图的二维码享受更好的阅读体验! 文章目录 推荐使用小程序阅读 1. ...

  2. 【SpringBoot笔记26】SpringBoot框架集成ElasticSearch数据库

    这篇文章,主要介绍SpringBoot框架如何集成ElasticSearch数据库. 目录 一.SpringBoot集成ES 1.1.ElasticSearch介绍 1.2.引入ES依赖 1.3.实例 ...

  3. 2021最新 MySQL面试题精选(附刷题小程序)

    推荐使用小程序阅读 为了能让您更加方便的阅读 本文所有的面试题目均已整理至小程序<面试手册> 可以通过微信扫描(或长按)下图的二维码享受更好的阅读体验! 最近梳理汇总了Java面试常遇到的 ...

  4. 史上最简单的Elasticsearch教程:SpringBoot集成Elasticsearch 实时流量监测平台

    SpringBoot集成Elasticsearch 实时流量监测平台 目录: 第一章:初尝 Elasticsearch 第二章:玩转 Kibana 第三章:开发原生 Elasticsearch 案例 ...

  5. GitChat优质文章-SpringBoot集成Elasticsearch

    Elasticsearch 是一个基于 Lucene 库的搜索引擎.Elasticsearch 是目前大数据领域最热门的技术栈之一.目前 Elasticsearch 被广泛应用在搜索.安全.数据分析等 ...

  6. springboot集成Elasticsearch实现各种搜索功能

    springboot集成Elasticsearch各类搜索功能实现 springboot集成Elasticsearch使用completion suggest实现自动关键字补全 建立学生的索引和映射: ...

  7. 【SpringBoot高级篇】SpringBoot集成Elasticsearch搜索引擎

    [SpringBoot高级篇]SpringBoot集成Elasticsearch搜索引擎 1. 什么是Elasticsearch? 2. 安装并运行Elasticsearch 2.1 拉取镜像 2.2 ...

  8. Springboot集成elasticsearch 使用IK+拼音分词

    Springboot集成elasticsearch 使用IK+拼音分词 docker安装ES 下载 docker pull docker.elastic.co/elasticsearch/elasti ...

  9. springboot——集成elasticsearch进行搜索并高亮关键词

    目录 1.elasticsearch概述 3.springboot集成elasticsearch 4.实现搜索并高亮关键词 1.elasticsearch概述 (1)是什么: Elasticsearc ...

最新文章

  1. linux发送email错误 501 Syntax: HELO hostname
  2. 最新Python学习项目Top10!
  3. 马斯克雇机器狗勘察火箭爆炸现场,网友:《黑镜》现实版
  4. Apache+Tomcat+Mysql+php整合jsp,php
  5. 对Keil在线烧录程序弹出“The firmware of the connected J-Link[SN:xxxxxxxx] does not support......的问题解决
  6. GPU代码修改成TPU代码
  7. Javascript – 正则表达式
  8. java隐藏密钥_java – 在Android中隐藏密钥库密码的最佳方法是什么?
  9. jQuery中ready与load事件的区别
  10. python分析政策实施前后_用Python分析春节前后的中国A股市场行情(附源代码)
  11. 图解 MySQL 索引,写得实在太好了!
  12. vs2017+pcl1.8.1配置
  13. 数据压缩算法该如何选择?
  14. Linux LED子系统调试与应用 设备树官方文档与 gpio-leds.c 源码详解
  15. 半波耦合器的设计——RSOFT
  16. 最简单的Greenplum节点扩展操作步骤
  17. LLVM WEEKLY系列停止转载
  18. java 插件大全_Java 常用插件
  19. 报告显示:风险环境和外挂类型关系密切 加速器外挂在模拟器环境里最多
  20. 5G网络逐渐普及TSINGSEE青犀视频云边端架构网页视频实时互动直播系统又将如何发展?

热门文章

  1. matlab计算器设计流程图_基于MATLAB计算器设计与开发
  2. 【已解决】java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class or
  3. 中国计算机发展史 博客,“博客”(Blog)在中国的发展历程
  4. LTspice基础教程-022.从MOS管提取参数生成spice模型
  5. ADS2019学习笔记:三、SPICE model导入
  6. 组网胖模式_胖瘦AP组网优劣对比
  7. android x86还是arm,Android x86是否模拟ARM?(Does Android x86 emulate ARM?)
  8. 移动端web总结(二)——微金所项目总结
  9. 为什么突然变乱码_这样的整理才能结束家里很快变乱的局面。而且整理还能改变运气...
  10. 企业微信可以取消实名认证吗?如何操作