完整代码地址在结尾??!
第一步,在pom.xml加入依赖,如下
<!-- elasticsearch -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
此处有坑,springboot 2.2.5 版本默认 elasticsearch 版本为 6.8.6 ,根据需要自己修改版本,此处我修改为 7.7.0版本(因为我的 elasticsearch 版本为 7.7.0),如下
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.7.0</elasticsearch.version>
</properties>
第二步,创建 ElasticSearchClientConfig 配置文件,如下
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description:
* @Author: jinhaoxun
* @Date: 2020/7/8 4:23 下午
* @Version: 1.0.0
*/
@Configuration
public class ElasticSearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(
RestClient.builder(
new HttpHost("xxx", 9200, "http"),
new HttpHost("xxx", 9200, "http"),
new HttpHost("xxx", 9200, "http")
));
return restHighLevelClient;
}
}
第三步,创建简单操作实体 User,如下
import lombok.Data;
/**
* @Description:
* @Author: jinhaoxun
* @Date: 2020/7/8 4:57 下午
* @Version: 1.0.0
*/
@Data
public class User {
private Long id;
private String name;
private String description;
private int age;
}
第四步,创建工具类,JsonUtils,如下
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* JsonUtils
*
* @author luoyu
* @date 2018/10/08 19:13
* @description Json工具类,依赖 jackson
*/
@Slf4j
public class JsonUtils {
private static ObjectMapper objectMapper = null;
static {
objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
/**
* 对象转换成json
* @param obj
* @param <T>
* @return
*/
public static <T>String objectToJson(T obj){
if(obj == null){
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
} catch (Exception e) {
log.error("Parse Object to Json error",e);
return null;
}
}
/**
* 将json转换成对象Class
* @param src
* @param clazz
* @param <T>
* @return
*/
public static <T>T jsonToObject(String src,Class<T> clazz){
if(StringUtils.isEmpty(src) || clazz == null){
return null;
}
try {
return clazz.equals(String.class) ? (T) src : objectMapper.readValue(src,clazz);
} catch (Exception e) {
log.warn("Parse Json to Object error",e);
return null;
}
}
/**
* 字符串转换为 Map<String, Object>
*
* @param src
* @return
* @throws Exception
*/
public static <T> Map<String, Object> jsonToMap(String src) {
if(StringUtils.isEmpty(src)){
return null;
}
try {
return objectMapper.readValue(src, Map.class);
} catch (Exception e) {
log.warn("Parse Json to Map error",e);
return null;
}
}
public static <T> List<T> jsonToList(String jsonArrayStr, Class<T> clazz) {
try{
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, clazz);
return (List<T>) objectMapper.readValue(jsonArrayStr, javaType);
}catch (Exception e) {
log.warn("Parse Json to Map error",e);
return null;
}
}
}
第五步,创建服务类,ElasticSearchService,ElasticSearchServiceImpl,如下
ElasticSearchService
import com.luoyu.elasticsearch.entity.User;
import java.util.List;
import java.util.Map;
public interface ElasticSearchService {
/**
* 创建索引
* @param index
*/
boolean createIndex(String index) throws Exception;
/**
* 判断索引是否存在
* @param index
*/
boolean existIndex(String index) throws Exception;
/**
* 删除索引
* @param index
*/
boolean deleteIndex(String index) throws Exception;
/**
* 新增文档
* @param index
* @param id
* @param content
*/
boolean addDocument(String index, String id, String content) throws Exception;
/**
* 判断是否存在文档
* @param index
* @param id
*/
boolean isExistsDocument(String index, String id) throws Exception;
/**
* 获取文档
* @param index
* @param id
*/
String getDocument(String index, String id) throws Exception;
/**
* 更新文档
* @param index
* @param id
* @param content
*/
boolean updateDocument(String index, String id, String content) throws Exception;
/**
* 删除文档
* @param index
* @param id
*/
boolean deleteDocument(String index, String id) throws Exception;
/**
* 批量插入
* @param index
* @param contents
*/
boolean bulkRequest(String index, List<User> contents) throws Exception;
/**
* 搜索请求
* @param index
* @param keyword
*/
List<Map<String, Object>> searchRequest(String index, String keyword) throws Exception;
/**
* 搜索所有id
* @param index
*/
List<Integer> searchAllRequest(String index) throws Exception;
}
ElasticSearchServiceImpl
import com.luoyu.elasticsearch.entity.User;
import com.luoyu.elasticsearch.service.ElasticSearchService;
import com.luoyu.elasticsearch.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
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.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.support.master.AcknowledgedResponse;
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.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
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.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* RabbitMqUtils
* @author luoyu
* @date 2019/03/16 22:08
* @description
*/
@Slf4j
@Component
public class ElasticSearchServiceImpl implements ElasticSearchService {
@Resource
private RestHighLevelClient restHighLevelClient;
/**
* 创建索引
* @param index
*/
@Override
public boolean createIndex(String index) throws Exception {
// 判断索引是否存在
if(this.existIndex(index)){
return true;
}
// 创建索引
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
return createIndexResponse.isAcknowledged();
}
/**
* 判断索引是否存在
* @param index
*/
@Override
public boolean existIndex(String index) throws Exception {
// 判断索引是否存在
GetIndexRequest getIndexRequest = new GetIndexRequest(index);
return restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
}
/**
* 删除索引
* @param index
*/
@Override
public boolean deleteIndex(String index) throws Exception {
// 判断索引是否存在
if(!this.existIndex(index)){
return true;
}
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
return acknowledgedResponse.isAcknowledged();
}
/**
* 新增文档
* @param index
* @param id
* @param content
*/
@Override
public boolean addDocument(String index, String id, String content) throws Exception {
if(!this.createIndex(index)){
return false;
}
IndexRequest indexRequest = new IndexRequest(index);
// 设置超时时间
indexRequest.id(id);
indexRequest.timeout(TimeValue.timeValueSeconds(1));
// 转换为json字符串
indexRequest.source(content, XContentType.JSON);
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
return indexResponse.status().getStatus() == 200;
}
/**
* 判断是否存在文档
* @param index
* @param id
*/
@Override
public boolean isExistsDocument(String index, String id) throws Exception {
// 判断是否存在文档
GetRequest getRequest = new GetRequest(index, id);
// 不获取返回的_source的上下文
getRequest.fetchSourceContext(new FetchSourceContext(false));
getRequest.storedFields("_none_");
return restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
}
/**
* 获取文档
* @param index
* @param id
*/
@Override
public String getDocument(String index, String id) throws Exception {
// 获取文档
GetRequest getRequest = new GetRequest(index, id);
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
return getResponse.getSourceAsString();
}
/**
* 更新文档
* @param index
* @param id
* @param content
*/
@Override
public boolean updateDocument(String index, String id, String content) throws Exception {
// 更新文档
UpdateRequest updateRequest = new UpdateRequest(index, id);
updateRequest.timeout(TimeValue.timeValueSeconds(1));
updateRequest.doc(content, XContentType.JSON);
UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
return updateResponse.status().getStatus() == 200;
}
/**
* 删除文档
* @param index
* @param id
*/
@Override
public boolean deleteDocument(String index, String id) throws Exception {
if(!this.isExistsDocument(index, id)){
return true;
}
// 删除文档
DeleteRequest deleteRequest = new DeleteRequest(index, id);
deleteRequest.timeout(TimeValue.timeValueSeconds(1));
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
return deleteResponse.status().getStatus() == 200;
}
/**
* 批量插入
* @param index
* @param contents
*/
@Override
public boolean bulkRequest(String index, List<User> contents) throws Exception {
// 批量插入
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout(TimeValue.timeValueSeconds(1));
contents.forEach(x -> {
bulkRequest.add(
new IndexRequest(index)
.id(x.getId().toString())
.source(JsonUtils.objectToJson(x), XContentType.JSON));
});
BulkResponse bulkItemResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return !bulkItemResponse.hasFailures();
}
/**
* 搜索请求
* @param index
* @param keyword
*/
@Override
public List<Map<String, Object>> searchRequest(String index, String keyword) throws Exception {
// 搜索请求
SearchRequest searchRequest;
if(StringUtils.isEmpty(index)){
searchRequest = new SearchRequest();
}else {
searchRequest = new SearchRequest(index);
}
// 条件构造
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 第几页
searchSourceBuilder.from(0);
// 每页多少条数据
searchSourceBuilder.size(1000);
// 配置高亮
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("name").field("description");
highlightBuilder.preTags("<span style='color:red'>");
highlightBuilder.postTags("</span>");
searchSourceBuilder.highlighter(highlightBuilder);
// 精确查询
// QueryBuilders.termQuery();
// 匹配所有
// QueryBuilders.matchAllQuery();
// 最细粒度划分:ik_max_word,最粗粒度划分:ik_smart
searchSourceBuilder.query(QueryBuilders.multiMatchQuery(keyword,"name", "description").analyzer("ik_max_word"));
// searchSourceBuilder.query(QueryBuilders.matchQuery("content", keyWord));
searchSourceBuilder.timeout(TimeValue.timeValueSeconds(10));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
List<Map<String, Object>> results = new ArrayList<>();
for (SearchHit searchHit : searchResponse.getHits().getHits()){
Map<String, HighlightField> highlightFieldMap = searchHit.getHighlightFields();
HighlightField title = highlightFieldMap.get("name");
HighlightField description = highlightFieldMap.get("description");
// 原来的结果
Map<String, Object> sourceMap = searchHit.getSourceAsMap();
// 解析高亮字段,替换掉原来的字段
if (title != null){
Text[] fragments = title.getFragments();
StringBuilder n_title = new StringBuilder();
for (Text text : fragments){
n_title.append(text);
}
sourceMap.put("name", n_title.toString());
}
if (description != null){
Text[] fragments = description.getFragments();
StringBuilder n_description = new StringBuilder();
for (Text text : fragments){
n_description.append(text);
}
sourceMap.put("description", n_description.toString());
}
results.add(sourceMap);
}
return results;
}
/**
* 搜索所有id
* @param index
*/
@Override
public List<Integer> searchAllRequest(String index) throws Exception {
// 搜索请求
SearchRequest searchRequest;
if(StringUtils.isEmpty(index)){
searchRequest = new SearchRequest();
}else {
searchRequest = new SearchRequest(index);
}
// 条件构造
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 第几页
searchSourceBuilder.from(0);
// 每页多少条数据
searchSourceBuilder.size(1000);
// 匹配所有
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchSourceBuilder.timeout(TimeValue.timeValueSeconds(10));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
List<Integer> results = new ArrayList<>();
for (SearchHit searchHit : searchResponse.getHits().getHits()){
results.add(Integer.valueOf(searchHit.getId()));
}
return results;
}
}
第六步,编写单元测试类,ElasticsearchApplicationTests,并进行测试,如下
import com.luoyu.elasticsearch.entity.User;
import com.luoyu.elasticsearch.service.ElasticSearchService;
import com.luoyu.elasticsearch.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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;
@Slf4j
// 获取启动类,加载配置,确定装载 Spring 程序的装载方法,它回去寻找 主配置启动类(被 @SpringBootApplication 注解的)
@SpringBootTest
class ElasticsearchApplicationTests {
@Autowired
private ElasticSearchService elasticSearchService;
@Test
void createIndexTest() throws Exception {
// 创建索引
elasticSearchService.createIndex("test_index");
}
@Test
void existIndexTest() throws Exception {
// 判断索引是否存在
elasticSearchService.existIndex("test_index");
}
@Test
void deleteIndexTest() throws Exception {
// 删除索引
elasticSearchService.deleteIndex("test_index");
}
@Test
void addDocumentTest() throws Exception {
// 新增文档
User user = new User();
user.setId(1L);
user.setAge(12);
user.setName("测试name");
user.setDescription("测试des");
elasticSearchService.addDocument("test_index", user.getId().toString(), JsonUtils.objectToJson(user));
}
@Test
void isExistsDocumentTest() throws Exception {
// 判断是否存在文档
elasticSearchService.isExistsDocument("test_index", "1");
}
@Test
void getDocumentTest() throws Exception {
// 获取文档
elasticSearchService.getDocument("test_index", "1");
}
@Test
void updateDocumentTest() throws Exception {
// 更新文档
User user = new User();
user.setId(1L);
user.setAge(33);
user.setName("测试name");
user.setDescription("测试des");
elasticSearchService.updateDocument("test_index", user.getId().toString(), JsonUtils.objectToJson(user));
}
@Test
void deleteDocumentTest() throws Exception {
// 删除文档
elasticSearchService.deleteDocument("test_index", "1");
}
@Test
void bulkRequestTest() throws Exception {
// 批量插入
List<User> users = new ArrayList<>();
for (int i = 0; i < 100; i++) {
User user = new User();
user.setId((long) i);
user.setAge(i);
user.setName("测试name" + i);
user.setDescription("测试des" + i);
users.add(user);
}
elasticSearchService.bulkRequest("test_index", users);
}
@Test
void searchRequestTest() throws Exception {
// 搜索请求
elasticSearchService.searchRequest("test_index", "测试");
}
@Test
void searchAllRequestTest() throws Exception {
// 搜索请求
elasticSearchService.searchAllRequest("test_index");
}
@BeforeEach
void testBefore(){
log.info("测试开始!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
@AfterEach
void testAfter(){
log.info("测试结束!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
}