Springboot2.x 两种方式操作增删改查Elasticsearch6.8.x

1. 概述

Springboot2 对Elasticsearch进行增删改查有多种方式:
通过ES的9300端口使用TCP的方式操作,该种方式已经逐渐被官方废弃,我们不再进行研究
我们主要使用通过ES的9200端口使用HTTP的方式

  • JestClient:非官方,更新慢
  • RestTemplate:模拟发 HTTP 请求,ES 很多操作需要自己封装,麻烦
  • HttpClient:同上
  • Elasticsearch-Rest-Client:官方 RestClient,封装了 ES 操作,API 层次分明,上手简单

我们选择使用最佳的方式Elasticsearch-Rest-Client
有两种引入依赖的方式:

  1. 只引入Elasticsearch-Rest-Client需要的包
  2. 直接引入Spring-data-elasticsearch,此时自动引入了Elasticsearch-Rest-Client,但是需要注意一下版本对应问题
    区别:使用Spring-data-elasticsearch依赖,可采用ElasticsearchRepository方式操作Entity实体对象,如要操作未知固定列的数据,还需要Elasticsearch-Rest-Client操作数据

关于Elasticsearch版本的选择:




Elasticsearch不同版本对系统的支持

参考链接:https://www.elastic.co/cn/support/matrix

关于Elasticsearch与JVM版本的选择:




Elasticsearch不同版本对JVM的支持

参考链接:https://www.elastic.co/cn/support/matrix#matrix_jvm

关于Spring-data-elasticsearch版本的选择:


版本对照图

参考链接:
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.requirements

2. 代码示例

2.1

我以Elasticsearch6.8.21为例:

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.8/java-rest-high-supported-apis.html

注:使用什么版本的es服务端,就引入相同版本号的依赖文件
1. 引入依赖文件

<dependency>
     <groupId>org.elasticsearch</groupId>
     <artifactId>elasticsearch</artifactId>
     <version>6.8.21</version>
</dependency>
<dependency>
     <groupId>org.elasticsearch.client</groupId>
      <artifactId>elasticsearch-rest-high-level-client</artifactId>
     <version>6.8.21</version>
</dependency>

2. 配置RestHighLevelClient

@Configuration
public class ElasticsearchRestClientConfig {
    public static final RequestOptions COMMON_OPTIONS;
    static {
       RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
       COMMON_OPTIONS = builder.build();
    }

    /**
     * 创建ES实例
     * @return
     */
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        HttpHost httpHost = new HttpHost(
                "127.0.0.1",9200,"http"
        );
        RestClientBuilder restClientBuilder = RestClient.builder(httpHost);
        RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
        return restHighLevelClient;
    }
}

3. 使用RestHighLevelClient操作数据
针对需要存储查询动态属性字段的数据,可采用该种方式;此方式也不需要对Springboot版本进行调整,我使用了Springboot2.6.x版本,依然可行。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ElasticsearchHighLevelClientTest {
    @Resource
    private RestHighLevelClient client;
    
    /**
     * 判断索引是否存在
     */
    @Test
    public void testCheckIndex () {
        try {
            boolean exist = client.indices().exists(new GetIndexRequest("indexName"), RequestOptions.DEFAULT);
            System.out.println(exist);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

   /**
     * 创建索引
     */
    @Test
    public void testCreateIndex (){
        try {
            CreateIndexRequest request = new CreateIndexRequest("indexName");
            CreateIndexResponse createIndexResponse = this.client.indices().create(request, RequestOptions.DEFAULT);
            System.out.println(createIndexResponse.index());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 删除索引
     */
    @Test
    public void testDeleteIndex() {
        try {
            DeleteIndexRequest request = new DeleteIndexRequest("indexName");
            AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
            System.out.println(response.isAcknowledged());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 写入数据
     */
    @Test
    public void testInsertMapData (){
        try {
            // 方法1:
            Map<String,Object> dataMap = new HashMap<>();
            dataMap.put("test", "test1");
            IndexRequest indexRequest = new IndexRequest("xc_course","doc");
            indexRequest.source(dataMap);
            IndexResponse indexResponse = this.client.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(indexResponse.getResult());
            //方法2:该发法采用批量插入的方法
            Map<String,Object> dataMap2 = new HashMap<>();
            dataMap2.put("city", "北京");
            IndexRequest indexRequest2 = new IndexRequest("xc_course","doc");
            indexRequest2.source(dataMap2);
            BulkRequest request = new BulkRequest();
            request.add(indexRequest2);
            BulkResponse bulkResponse = this.client.bulk(request, RequestOptions.DEFAULT);
            System.out.println(JSONObject.toJSONString(bulkResponse));
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 批量写入数据
     */
    @Test
    public void batchInsertMapData (){
        try {
            List<Map<String,Object>> userIndexList = new ArrayList<>();
            Map<String,Object> map1 = new HashMap<>();
            map1.put("test", "test1");
            Map<String,Object> map2 = new HashMap<>();
            map2.put("test", "test2");
            userIndexList.add(map1);
            userIndexList.add(map2);
            BulkRequest request = new BulkRequest();
            for (Map<String,Object> dataMap:userIndexList){
                request.add(new IndexRequest("xc_course","doc").source(dataMap));
            }
            BulkResponse bulkResponse = this.client.bulk(request, RequestOptions.DEFAULT);
            System.out.println(JSONObject.toJSONString(bulkResponse));
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 更新数据,可以直接修改索引结构
     */
    @Test
    public void testUpdateMapData (){
        try {
            Map<String,Object> dataMap = new HashMap<>();
            dataMap.put("test", "test2");
            dataMap.put("test1", "test3");
            UpdateRequest updateRequest = new UpdateRequest("xc_course","doc", "51zYd38BFz6qlQzXYT56");
            updateRequest.doc(dataMap);
            UpdateResponse updateResponse = this.client.update(updateRequest, RequestOptions.DEFAULT);
            System.out.println(updateResponse.getResult());
        } catch (Exception e){
            e.printStackTrace();
        }
    }
   /**
     * 删除数据
     */
    @Test
    public void testDeleteMapData (){
        try {
            //方法1:
            DeleteRequest deleteRequest1 = new DeleteRequest("xc_course","doc", "4VwadH8BFz6qlQzXVD5c");
            DeleteResponse deleteResponse1 = this.client.delete(deleteRequest1, RequestOptions.DEFAULT);
            System.out.println(deleteResponse1.getResult());
            //方法2:
            DeleteRequest deleteRequest2 = new DeleteRequest();
            deleteRequest2.index("xc_course");
            deleteRequest2.type("doc");
            deleteRequest2.id("41zJd38BFz6qlQzXhj71");
            DeleteResponse deleteResponse2 = this.client.delete(deleteRequest2, RequestOptions.DEFAULT);
            System.out.println(deleteResponse2.getResult());
        } catch (Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 查询总数
     */
    @Test
    public void testCount (){
        // 指定创建时间
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
//        queryBuilder.must(QueryBuilders.termQuery("test", "test1"));

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(queryBuilder);

        CountRequest countRequest = new CountRequest("xc_course");
        countRequest.source(sourceBuilder);
        try {
            CountResponse countResponse = client.count(countRequest, RequestOptions.DEFAULT);
            long count = countResponse.getCount();
            System.out.println(count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   /**
     * 查询集合
     */
    @Test
    public void testList () {
        // 查询条件,指定时间并过滤指定字段值
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
//        queryBuilder.must(QueryBuilders.termQuery("test", "test1"));
//        queryBuilder.mustNot(QueryBuilders.termQuery("city","北京"));
        sourceBuilder.query(queryBuilder);
        SearchRequest searchRequest = new SearchRequest("xc_course");
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResp = client.search(searchRequest, RequestOptions.DEFAULT);
            List<Map<String,Object>> data = new ArrayList<>() ;
            SearchHit[] searchHitArr = searchResp.getHits().getHits();
            for (SearchHit searchHit:searchHitArr){
                Map<String,Object> temp = searchHit.getSourceAsMap();
                temp.put("id",searchHit.getId()) ;
                data.add(temp);
            }
            System.out.println(JSONObject.toJSONString(data));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
    /**
     * 分页查询
     */
    @Test
    public void testPage () {
        // 查询条件,指定时间并过滤指定字段值
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(1);
        sourceBuilder.size(20);
        //sourceBuilder.sort("createTime", SortOrder.DESC);
        SearchRequest searchRequest = new SearchRequest("xc_course");
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResp = client.search(searchRequest, RequestOptions.DEFAULT);
            List<Map<String,Object>> data = new ArrayList<>() ;
            SearchHit[] searchHitArr = searchResp.getHits().getHits();
            for (SearchHit searchHit:searchHitArr){
                Map<String,Object> temp = searchHit.getSourceAsMap();
                temp.put("id",searchHit.getId()) ;
                data.add(temp);
            }
            System.out.println(JSONObject.toJSONString(data));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.2

1. 引入依赖文件
① Springboot2.6.x版本过高,与Elasticsearch6.8.x不一致,使用中代码会出错,需要对Springboot版本进行降级处理
如下图:

springboot2.6.x版本的spring-boot-starter-data-elasticsearch引用的是4.3.x版本的spring-data-elasticsearch

4.3.x版本的spring-data-elasticsearch引用的是7.15.2版本的elasticsearch客户端

② 将Springboot版本降级至2.2.x后
依赖选择 spring-boot-starter-data-elasticsearch

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>-->

或者 spring-data-elasticsearch 3.2.x版本

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

2. 配置application.yml文件

spring:
  elasticsearch:
     rest:
        connection-timeout: 30s
        read-timeout: 60s
        uris: 127.0.0.1:9200

3. 使用ElasticsearchRepository操作实体数据

可参考官方文档:
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.repositories

也可以与第一种方式结合使用
官方也给出了相关RestHighLevelClient配置示例


使用RestHighLevelClient

客户端配置: https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.rest
可扩充配置项:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容