这里之所以选择high level client方式是因为transportClient在7.X版本中废弃,预计会在8版本彻底删除。
可参考官方文档地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.6/java-rest-high-getting-started-maven.html
配置文件
pom.xml
这里有个小坑,在使用官方文档的依赖包时,发现maven下载的es相关jar包竟然是6.4版本的,导致出现了很多问题。
通过 https://www.jianshu.com/p/acc8e86cc772 可解决jar包版本不一致的问题,再次感谢大佬分享学习的精神。
<!-- es --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.6.1</version> <exclusions> <exclusion> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> </exclusion> <exclusion> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-client</artifactId> <version>7.6.1</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.6.1</version> </dependency>
application.yml
es:
host: 10.32.16.179 port: 9200 schema: http
索引管理
判断索引是否存在
@Service
public class ElasticSearchServiceImpl implements ElasticSearchService { private static final Logger logger = LoggerFactory.getLogger(ElasticSearchServiceImpl.class); @Autowired private RestHighLevelClient restHighLevelClient; /** * 根据索引名称判断索引是否已存在 * @param indexName * @return * @throws IOException */ @Override public boolean isExistsIndex(String indexName) throws IOException { return restHighLevelClient.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT); } }
创建索引
官方提供了三种创建mapping的方式,这里在后端写死了mapping,如果需要索引管理,可通过前端传入参数构建。
/**
* 创建索引
* @param indexName
* @throws IOException
*/
@Override
public void createIndex(String indexName) throws IOException { if(isExistsIndex(indexName)){ logger.error("indexName={} 已存在,无法创建", indexName); return; } CreateIndexRequest request = new CreateIndexRequest(indexName); //设置分片和备份 request.settings(Settings.builder() .put("index.number_of_shards",3) .put("index.number_of_replicas",2) .build()); //第一种,json字符串 request.mapping("{\n" + "\t\"properties\": {\n" + "\t\t\"username\": {\n" + "\t\t\t\"type\": \"text\"\n" + "\t\t},\n" + "\t\t\"city\": {\n" + "\t\t\t\"type\": \"keyword\"\n" + "\t\t}\n" + "\t}\n" + "}", XContentType.JSON); //第二种,Map // Map<String,Object> username = new HashMap<>(); // username.put("type","text"); // Map<String,Object> city = new HashMap<>(); // city.put("type","keyword"); // Map<String,Object> properties = new HashMap<>(); // properties.put("username",username); // properties.put("city",city); // Map<String,Object> mapping = new HashMap<>(); // mapping.put("properties",properties); // request.mapping(mapping); //第三种,XContentBuilder // XContentBuilder builder = XContentFactory.jsonBuilder(); // builder.startObject(); // { // builder.startObject("properties"); // { // builder.startObject("username"); // { // builder.field("type","text"); // } // builder.endObject(); // // builder.startObject("city"); // { // builder.field("type","keyword"); // } // builder.endObject(); // } // builder.endObject(); // } // builder.endObject(); // restHighLevelClient.indices().create(request,RequestOptions.DEFAULT); }
删除索引
/**
* 删除索引
* @param indexName
* @throws IOException
*/
@Override
public void deleteIndex(String indexName) throws IOException { if(!isExistsIndex(indexName)){ logger.error("indexName={} 索引不存在", indexName); return; } restHighLevelClient.indices().delete(new DeleteIndexRequest(indexName),RequestOptions.DEFAULT); }
文档管理
新增或更新文档
id为空则新增,不为空则更新
ElasticEntity
package com.wk.entity;
/**
* 泛型,es入参实体类
* @param <T>
*/
public class ElasticEntity<T> { private String id; private T data; public String getId() { return id; } public void setId(String id) { this.id = id; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
EsTestEntity
package com.wk.entity;
/**
* controller接收实体类
*/
public class EsTestEntity { private String id; private String username; private String city; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } }
业务类
官方新增文档也有三种方式,和创建索引类似,这里不一一列举了
/**
* 新增或更新文档
* @param indexName
* @param elasticEntity
* @throws IOException
*/
@Override
public void insertOrUpdateDocument(String indexName, ElasticEntity elasticEntity) throws IOException { IndexRequest indexRequest = new IndexRequest(indexName); indexRequest.id(elasticEntity.getId()); indexRequest.source(JSONObject.toJSONString(elasticEntity.getData()),XContentType.JSON); restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT); }
controller
还可在插入之前校验一下index是否存在,这里省略了只简单实现了demo
@PostMapping("insertOrUpdateDocument/{indexName}")
public Map<String,String> insertOrUpdateDocument(@PathVariable String indexName,@RequestBody EsTestEntity esTestEntity){
ElasticEntity<EsTestEntity> entity = new ElasticEntity<>();
//注册生成UUID插入实体类的ID
if(StringUtils.isEmpty(esTestEntity.getId())){
String id = UUID.randomUUID().toString();
entity.setId(id);
esTestEntity.setId(id);
}
entity.setId(esTestEntity.getId());
entity.setData(esTestEntity);
try {
elasticSearchServiceImpl.insertOrUpdateDocument(indexName,entity);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
条件查询
controller
@PostMapping("searchDocument/{indexName}")
public List<EsTestEntity> searchDocument(@PathVariable String indexName, @RequestBody EsTestEntity esTestEntity){ try { SearchSourceBuilder builder = new SearchSourceBuilder(); Map<String,Object> requestMap = BeanUtil.convertToMap(esTestEntity); for(Map.Entry<String,Object> entry:requestMap.entrySet()){ builder.query(QueryBuilders.matchQuery(entry.getKey(),entry.getValue())); } //分页 builder.from(0); builder.size(5); //排序 builder.sort("city", SortOrder.ASC); //设置超时时间 builder.timeout(new TimeValue(60, TimeUnit.SECONDS)); return elasticSearchServiceImpl.searchDocument(indexName,builder,EsTestEntity.class); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }
service
/**
* 条件查询
* @param indexName
* @param builder
* @param c
* @param <T>
* @return
* @throws IOException
*/
@Override
public <T> List<T> searchDocument(String indexName, SearchSourceBuilder builder, Class<T> c) throws IOException { SearchRequest searchRequest = new SearchRequest(indexName); searchRequest.source(builder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] searchHits = searchResponse.getHits().getHits(); List<T> res = new ArrayList<>(); for(SearchHit searchHit:searchHits){ res.add(JSONObject.parseObject(searchHit.getSourceAsString(),c)); } return res; }
高亮条件查询
controller
@PostMapping("searchHighlightDocument/{indexName}")
public List<EsTestEntity> searchHighlightDocument(@PathVariable String indexName, @RequestBody EsTestEntity esTestEntity){ try { SearchSourceBuilder builder = new SearchSourceBuilder(); Map<String,Object> requestMap = BeanUtil.convertToMap(esTestEntity); for(Map.Entry<String,Object> entry:requestMap.entrySet()){ builder.query(QueryBuilders.matchQuery(entry.getKey(),entry.getValue())); } builder.from(0); builder.size(5); builder.sort("city", SortOrder.ASC); builder.timeout(new TimeValue(60, TimeUnit.SECONDS)); HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.preTags("<front color = 'red'>"); highlightBuilder.postTags("</front>"); HighlightBuilder.Field field = new HighlightBuilder.Field("username"); highlightBuilder.field(field); builder.highlighter(highlightBuilder); return elasticSearchServiceImpl.searchHighlightDocument(indexName,builder,EsTestEntity.class); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }
service
/**
* 高亮条件查询
* @param indexName
* @param builder
* @param c
* @param <T>
* @return
* @throws IOException
*/
@Override
public <T> List<T> searchHighlightDocument(String indexName, SearchSourceBuilder builder, Class<T> c) throws IOException { SearchRequest searchRequest = new SearchRequest(indexName); searchRequest.source(builder); SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] searchHits = searchResponse.getHits().getHits(); List<T> res = new ArrayList<>(); for(SearchHit searchHit:searchHits){ //返回结果转换成Map Map<String,Object> sourceMap = searchHit.getSourceAsMap(); //获取高亮的返回结果 Map<String, HighlightField> map = searchHit.getHighlightFields(); //循环设置的高亮字段 for(Map.Entry<String, HighlightField> entry:map.entrySet()){ //将高亮字段格式替换原结果中的值 sourceMap.put(entry.getKey(),entry.getValue().getFragments()[0].toString()); } res.add(JSONObject.parseObject(JSONObject.toJSONString(sourceMap),c)); } return res; }
返回结果:
删除文档
/**
* 根据ID删除文档
* @param indexName
* @param id
* @throws IOException
*/
@Override
public void deleteDocumentById(String indexName, String id) throws IOException { DeleteRequest deleteRequest = new DeleteRequest(indexName,id); restHighLevelClient.delete(deleteRequest,RequestOptions.DEFAULT); }
还有条件删除等API,可以参考官方文档,这里不一一列举了
批量操作
批量新增
/**
* 批量新增
* @param indexName
* @param elasticEntities
* @throws IOException
*/
@Override
public void insertDocumentBatch(String indexName, List<ElasticEntity> elasticEntities) throws IOException { BulkRequest bulkRequest = new BulkRequest(); elasticEntities.forEach(item ->{ bulkRequest.add(new IndexRequest(indexName).id(item.getId()).source(JSONObject.toJSONString(item.getData()),XContentType.JSON)); }); restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT); }
批量删除
/**
* 批量删除文档
* @param indexName
* @param idList
* @param <T>
* @throws IOException
*/
public <T> void deleteDocumentBatch(String indexName, Collection<T> idList) throws IOException {
BulkRequest bulkRequest = new BulkRequest(); idList.forEach(item ->{ bulkRequest.add(new DeleteRequest(indexName, item.toString())); }); restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT); }