zoukankan      html  css  js  c++  java
  • 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("{
    " +
                    "	"properties": {
    " +
                    "		"username": {
    " +
                    "			"type": "text"
    " +
                    "		},
    " +
                    "		"city": {
    " +
                    "			"type": "keyword"
    " +
                    "		}
    " +
                    "	}
    " +
                    "}", 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);
    
        }
  • 相关阅读:
    HttpClient调用RestFul接口(post和get方式)
    mysql权限异常
    javascript:用法
    Java哈希值HashCode理解
    Java的CountDownLatch和CyclicBarrier的理解和区别
    Java并发编程与技术内幕:ThreadGroup线程组应用
    面试官: 谈谈什么是守护线程以及作用 ?
    java 成员变量 静态成员变量 方法 静态方法初始化顺序
    【java并发核心一】Semaphore 的使用思路
    threadlocal原理及常用应用场景
  • 原文地址:https://www.cnblogs.com/Unlimited-Blade-Works/p/12572212.html
Copyright © 2011-2022 走看看