ElasticSeach(六、springboot集成ES high level client)

这里之所以选择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);

    }

 

posted @ 2020-03-26 09:17  学霸王先森  阅读(1448)  评论(1编辑  收藏  举报