zoukankan      html  css  js  c++  java
  • ElasticSearch集成SpringBoot与常见使用方法

    一、导包

    image-20200531214301211

    二、核对导入的ES版本

    我的springboot自动导入的是7.6.2的版本,但我搭建的ES是7.7.0,为了避免出异常,需修改导入版本与ES服务版本一致

    image-20200531214554301

    修改导入版本

    1. 查看springboot版本号使用的什么properties标签

      • 打开pom文件->按住ctrl点击artifactId

      image-20200605140346085

      • 在弹出的pom中按住Ctrl点击artifactId

        image-20200531215033287

      • 在弹出的pom中找到elasticsearch版本标签

        image-20200531215150952

      • 在项目的pom文件properties标签中添加需要导入的版本

        image-20200531215247205

      • 这时回到刚才第一张图,看es就会变成了指定的版本了

    三、写配置类

    我是用的是RestHighLevelClient ,通过官方文档得知,它需要返回一个RestHighLevelClient 对象,并且使用完后及时关闭客户端

    image-20200531220239292

    • 我的配置类

      package com.rb.elasticsearch.elasticsearch.conf;
      
      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;
      
      @Configuration
      public class EsConf {
          @Bean
          public RestHighLevelClient restHighLevelClient(){
              RestHighLevelClient client = new RestHighLevelClient(
                      RestClient.builder(
                              //new HttpHost("localhost", 9200, "http"),//如果集群,传入多个地址即可
                              new HttpHost("192.168.100.112", 9200, "http")));//我的ES地址端口
              return client;
          }
      }
      //可以自己写一个自动装配类,将ip写入Yml文件
      

    四、开始测试

    索引操作

    1.创建索引

    注意:索引名字必须小写

    返回值为:{"acknowledged":true,"fragment":false,"shardsAcknowledged":true}

    这个返回值和elasticsearch-head创建索引返回的结果一样

    image-20200531222346753

    代码如下:

    package com.rb.elasticsearch.elasticsearch;
    
    import com.alibaba.fastjson.JSON;
    import org.elasticsearch.client.RequestOptions;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.client.indices.CreateIndexRequest;
    import org.elasticsearch.client.indices.CreateIndexResponse;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.io.IOException;
    
    @SpringBootTest
    class ElasticsearchApplicationTests {
        @Autowired
        RestHighLevelClient restHighLevelClient;
    
        /**
         * 创建索引
         * @throws IOException
         */
        @Test
        void createIndex() throws IOException {
            CreateIndexRequest request = new CreateIndexRequest("java_index");
            CreateIndexResponse createIndexResponse =restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            System.out.println(JSON.toJSONString(createIndexResponse));//返回值
        }
    
    }
    
    

    2.查看索引是否存在

        /**
         * 判断索引是否存在
         * @throws IOException
         */
        @Test
        void checkIndex() throws IOException {
            GetIndexRequest getIndexRequest=new GetIndexRequest("java_index");
            boolean exists = restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            System.out.println(exists);//返回值true:存在 false:不存在
        }
    

    3.删除索引

    acknowledged=true表示删除成功

        /**
         * 判断索引是否存在
         * @throws IOException
         */
        @Test
        void delIndex() throws IOException {
            DeleteIndexRequest deleteIndexRequest=new DeleteIndexRequest("java_index");
            AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            System.out.println(JSON.toJSONString(delete));//返回值{"acknowledged":true,"fragment":false}
        }
    

    文档操作

    官方举例是手拼json串,但工作中很少这么用,大多数都是一个model,然后转成json串,所以先创建一个model

    package com.rb.elasticsearch.model;
    
    import lombok.Data;
    
    @Data
    public class Users {
        String name;
        String remark;
        int age;
    }
    

    1.添加文档

    • 单条添加

      /**
           * 添加文档
           */
      @Test
      void putDoc() throws IOException {
          if(checkIndexIsExist()){//这个方法见下方“查看文档是否存在” 如果不判断是否存在,在没有创建索引的情况下,它会创建索引
              IndexRequest indexRequest=new IndexRequest(Es.INDEX_NAME);
              indexRequest.id("1");
              Users users=new Users();
              users.setAge(15);
              users.setName("张三的名字叫张三");
              users.setRemark("张三的备注");
              indexRequest.source(JSON.toJSONString(users), XContentType.JSON);
              IndexResponse index = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
              System.out.println(JSON.toJSONString(index));
          }else{
              System.out.println("索引不存在");
          }
      }
      
    • 批量添加

       /**
           * 批量添加
           * @throws IOException
           */
          @Test
          void bulkAddDoc() throws IOException {
              if(checkIndexIsExist()){//如果不判断是否存在,在没有创建索引的情况下,它会创建索引
                  BulkRequest request=new BulkRequest();
                  for (int i = 0; i <5 ; i++) {//循环添加五个
                      int id = i+1;
                      IndexRequest indexRequest=new IndexRequest(Es.INDEX_NAME);
                      Users users=new Users();
                      users.setRemark("李"+i+"的备注");
                      users.setName("李"+i+"的名字叫李"+i);
                      users.setAge(i);
                      indexRequest.source(JSON.toJSONString(users),XContentType.JSON);
                      indexRequest.id(String.valueOf(id));
                      request.add(indexRequest);
                  }
                  BulkResponse bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
                  System.out.println(JSON.toJSONString(bulk));
              }
          }
      

    2.查看文档是否存在

        /**
         * 查看文档是否存在
         * @throws IOException
         */
        @Test
        void checkDocIsExist() throws IOException {
            if(checkIndexIsExist()){
                GetRequest getRequest=new GetRequest(Es.INDEX_NAME,"1");
                boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT);
                System.out.println(exists);//true 存在 false 不存在
            }else{
                System.out.println("索引不存在");
            }
        }
    

    3.修改文档

    注意:我的users对象中age是int,默认值是0,如果执行下面批量修改的时候,age不修改的话会默认是0,这样会将相关索引中age字段值全部修改为0,可以使用Integer

    • 单一修改
     /**
         * 单一修改数据
         * @throws IOException
         */
        @Test
        void updateDoc() throws IOException {
            if(checkIndexIsExist()){
                UpdateRequest updateRequest=new UpdateRequest(Es.INDEX_NAME,"1");
                Users users=new Users();
                users.setAge(99);//只修改年龄,其他不动
                updateRequest.doc(JSON.toJSONString(users),XContentType.JSON);
                restHighLevelClient.update(updateRequest,RequestOptions.DEFAULT);
            }
        }
    
    • 批量修改

      /**
           * 批量修改数据
           * @throws IOException
           */
          @Test
          void buleUpdateDoc() throws IOException {
              if(checkIndexIsExist()){
                  BulkRequest bulkRequest=new BulkRequest();
                  for (int i = 0; i <5 ; i++) {
                      int id =i+1;
                      UpdateRequest updateRequest=new UpdateRequest(Es.INDEX_NAME,String.valueOf(id));
                      Users users=new Users();
                      users.setRemark("批量修改的备注"+i);
                      updateRequest.doc(JSON.toJSONString(users),XContentType.JSON);
                      bulkRequest.add(updateRequest);
                  }
                  restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
              }
          }
      

    4.删除文档

    • 单独删除
        /**
         * 删除文档
         * @throws IOException
         */
        @Test
        void delDoc() throws IOException {
            if(checkIndexIsExist()){//只有索引已经创建的时候才可以继续
                DeleteRequest deleteRequest=new DeleteRequest("java_index","1");
                DeleteResponse delete = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
                System.out.println(delete);
            }
        }
    
    • 批量删除
    /**
         * 批量删除
         * @throws IOException
         */
        @Test
        void buleDelDoc() throws IOException {
            if(checkIndexIsExist()){
                BulkRequest bulkRequest=new BulkRequest();
                for (int i = 0; i <5 ; i++) {
                    int id =i+1;
                    DeleteRequest deleteRequest=new DeleteRequest(Es.INDEX_NAME);
                    deleteRequest.id(String.valueOf(id));
                    bulkRequest.add(deleteRequest);
                }
                restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
            }
        }
    

    五.文档常用查询

    单一字段查询

    根据id精准查询

     /**
         * 根据id查询
         * @throws IOException
         */
        @Test
        void termSelectById() throws IOException {
            if(checkIndexIsExist()){
                GetRequest getRequest1 = new GetRequest(Es.INDEX_NAME, "1");
                //也可使用下面的方式
                //GetRequest getRequest=new GetRequest(Es.INDEX_NAME);
                //getRequest.id("1");
                GetResponse documentFields = restHighLevelClient.get(getRequest1, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(documentFields));
            }
        }
    

    根据某字段精准查询

    (select * from users where age=1)

      /**
           * 根据某字段精准查询
           * @throws IOException
           */
          @Test
          void termSelectByField() throws IOException {
              if(checkIndexIsExist()){
                  SearchRequest searchRequest=new SearchRequest(Es.INDEX_NAME);
                  SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
                  searchSourceBuilder.query(QueryBuilders.termQuery("age",1));
                  searchRequest.source(searchSourceBuilder);
                  SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                  System.out.println(JSON.toJSONString(search));
              }
          }
    

    根据某字段模糊查询

    (select * from users where remark like '%0%')

    /**
         * 根据某个字段模糊查询
         * @throws IOException
         */
        @Test
        void matchSelectByField() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest=new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
                searchSourceBuilder.query(QueryBuilders.matchQuery("remark","0"));
                searchRequest.source(searchSourceBuilder);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search.getHits().getHits()));
            }
        }
    

    多条件查询

    多条件And查询

    (select * from users where name like '%因为是match,会被分词%' and age=0)

        /**
         * 多条件查询
         * @throws IOException
         */
        @Test
        void multipleFieldSelectByMust() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest = new SearchRequest(Es.INDEX_NAME);//定义请求
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//构建查询条件器
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//选择返回值(满足查询条件的返回true,不满足是false)
                boolQueryBuilder.must(QueryBuilders.matchQuery("name","李0的名字叫李0"));//查询条件一
                boolQueryBuilder.must(QueryBuilders.termQuery("age","0"));//查询条件二
                System.out.println(boolQueryBuilder.must());//输出构建好的查询条件一、二
                searchSourceBuilder.query(boolQueryBuilder);//将条件完善的对象放入
                searchRequest.source(searchSourceBuilder);//向查询请求中放入查询条件
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);//执行查询
                System.out.println(JSON.toJSONString(search.getHits().getHits()));//查看结果
            }
        }
    

    这一步我认为有点绕,java代码逻辑和上一篇说的命令先后逻辑是一样的,我的研究方式为逆推法(自己这么起的名字)

    • 第一步:restHighLevelClient.search先把这个敲出来,发现这个方法需要一个SearchRequest对象

    • 第二步:new 一个 SearchRequest 这个对象,然后命令顺序下一步是“query”,我就找到了searchSourceBuilder.query()方法,重复第一步,发现query方法需要一个BoolQueryBuilder对象

    • 第三步:new 一个 BoolQueryBuilder这个对象,然后重复第二步,观察命令顺序,这时会传入mustmust_not等信息,我就在官方提供的QueryBuilders中找到了相应的方法boolQueryBuilder.must()

      • 这时,我发现一个卡点,命令上会传入一个多条件数组,java中肯定会传入一个多条件的对象,但是没有在QueryBuilders找到入参为数组的, 愁坏我了,去官网翻了一下,看到了下图,意思是可多调用多次,然后我就调用了两次image-20200606231726697
    • 第四步:因为第三步不确定,但是BoolQueryBuilder这个类中却有返回一个数组的方法,调用看看

      System.out.println(boolQueryBuilder.must());//输出构建好的查询条件一、二
      
    • 结果和我想的一样,成功了

    • 为了加深上面的印象,我将这块命令顺序同步标记了一下java代码的位置,更方便理解:

    GET users/_doc/_search //后的_search就是 SearchRequest 定义请求
    {
      "query":{//searchSourceBuilder.query(boolQueryBuilder);//将条件完善的对象放入
        "bool":{//BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();//选择返回值(满足查询条件的返回true,不满足是false)
          "must":[//boolQueryBuilder.must()
            {
              "term"://QueryBuilders.termQuery("age","0");每调用一次就多一个查询条件
              {
                "name":"张三的名字叫张三"
              }
            } , 
             {
              "match"://QueryBuilders.matchQuery("name","李0的名字叫李0")
              {
                "age":"15"
              }
            }
          ]
        }
      }
    }
    

    多条件OR查询

    (select * from users where remark like '%1%' or age=0) 注:%1%里的1使用了match,会被分词

    /**
         * 多条件查询OR
         * @throws IOException
         */
        @Test
        void multipleFieldSelectByShould() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest = new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                boolQueryBuilder.should(QueryBuilders.matchQuery("remark","1"));
                boolQueryBuilder.should(QueryBuilders.termQuery("age","0"));
                searchSourceBuilder.query(boolQueryBuilder);
                searchRequest.source(searchSourceBuilder);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search.getHits().getHits()));
            }
        }
    

    多条件!=查询

    (select * from users where age !=0 and age !=1)

    /**
         * 多条件查询!=
         * @throws IOException
         */
        @Test
        void multipleFieldSelectByMustNot() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest = new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                boolQueryBuilder.mustNot(QueryBuilders.termQuery("age","1"));//QueryBuilders里面的查询方式可以随意换
                boolQueryBuilder.mustNot(QueryBuilders.termQuery("age","0"));//QueryBuilders里面的查询方式可以随意换
                searchSourceBuilder.query(boolQueryBuilder);
                searchRequest.source(searchSourceBuilder);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search.getHits().getHits()));
            }
        }
    

    范围查询

    (select * from users where age >=0 and age <=2)

    gt 大于
    gte 大于等于
    lt 小于
    lte 小于等于!

     /**
         * 根据字段范围查询
         * @throws IOException
         */
        @Test
        void multipleFieldSelectByRange() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest = new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                //再此处还可以加上面的各种查询条件↓↓↓
                //再此处还可以加上面的各种查询条件↑↑↑
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").gte(0));
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("age").lte(2));
                searchSourceBuilder.query(boolQueryBuilder);
                searchRequest.source(searchSourceBuilder);
                restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search.getHits().getHits()));
            }
        }
    

    自定义字段返回

        /**
         * 显示指定字段
         * @throws IOException
         */
        @Test
        void returnField() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest = new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                String[] includeFields = new String[] {"name", "age"};//要显示的哪些字段
                String[] excludeFields = new String[] {""};//要排除的哪些字段
                searchSourceBuilder.fetchSource(includeFields,excludeFields);
                searchRequest.source(searchSourceBuilder);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search.getHits().getHits()));
            }
        }
    

    排序

    select * from users where remark like '%的备注%' and remark like '%3%' order by _score desc , age desc

    查询包含“的备注”、“3”的记录(传入参数会被分词),并且按照匹配度_score这个字段排序,数值越大的匹配度越高,然后按照年龄age降序排序

    /**
         * 排序
         * @throws IOException
         */
        @Test
        void sort() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest = new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                searchSourceBuilder.query(QueryBuilders.matchQuery("remark","的备注 3"));
                searchSourceBuilder.sort("_score",SortOrder.DESC);
                searchSourceBuilder.sort("age",SortOrder.DESC);
                searchRequest.source(searchSourceBuilder);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search));
            }
        }
    

    高亮查询

    public String test() throws IOException {
            SearchRequest searchRequest=new SearchRequest(Es.INDEX_NAME);
            SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
            //构建查询条件start
            searchSourceBuilder.query(QueryBuilders.matchQuery("name","名 叫"));//模糊搜索
            //searchSourceBuilder.query(QueryBuilders.termQuery("name.keyword","李0的名字叫李0"));//精准搜索
            //构建查询条件end
            //高亮start
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("name");
            //highlightBuilder.field("name.keyword");//与上方设置的name保持一致
            highlightBuilder.preTags("<mytag style='color:red'>");//自定义标签&样式
            highlightBuilder.postTags("</mytag>");//自定义标签&样式
            searchSourceBuilder.highlighter(highlightBuilder);
            //高亮end
            searchRequest.source(searchSourceBuilder);
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            List<Map<String, Object>> list=new ArrayList();
            //高亮条件封装start
            for (SearchHit hit : search.getHits().getHits()) {
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField remark = highlightFields.get("name");
               // HighlightField remark = highlightFields.get("name.keyword");//与上方设置的name保持一致
                Map<String, Object> sourceAsMap = hit.getSourceAsMap();
                if(remark!=null){
                    Text[] fragments = remark.fragments();
                    String desc="";
                    for (Text fragment : fragments) {
                        desc+=fragment;
                    }
                    //sourceAsMap.put("name.keyword",desc);
                    sourceAsMap.put("name",desc);
                    list.add(sourceAsMap);
                }
            }
            //高亮条件封装end
            return JSON.toJSONString(search);
        }
    

    结果如下:

    image-20200607171409906

    获得指定索引下满足条件的总记录数据

        /**
         * 查询指定索引中总共有多少条数据
         * @throws IOException
         */
        @Test
        void getTotalCount() throws IOException {
            CountRequest countRequest = new CountRequest(Es.INDEX_NAME);
            //可以自定义设置上面的一些查询条件start
            //可以自定义设置上面的一些查询条件end
            CountResponse count = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            System.out.println(JSON.toJSONString(count));
        }
    

    分页查询

    from:从第几条数据开始(>关系,非>=)
    size:查询几条数据

    /**
         * 分页查询
         * @throws IOException
         */
        @Test
        void pageSelect() throws IOException {
            if(checkIndexIsExist()){
                SearchRequest searchRequest=new SearchRequest(Es.INDEX_NAME);
                SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
                //设置搜索条件
                searchSourceBuilder.query(QueryBuilders.matchQuery("remark","的备注"));
                searchSourceBuilder.from(2);//从索引第几个开始查找,索引从0 开始
                searchSourceBuilder.size(2);//显示from至from+size的数据
                //例如:查询id1~2的数据,from=0 ,size=2
                //     查询id3-4的数据,from=2,  size=2
                searchRequest.source(searchSourceBuilder);
                SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
                System.out.println(JSON.toJSONString(search.getHits().getHits()));
            }
        }
    

    六、集成好的项目

    https://files-cdn.cnblogs.com/files/rb2010/elasticsearch.zip

  • 相关阅读:
    安装 Ruby, Rails 运行环境
    saas 系统租户个性化域名&&租户绑定自己域名的解决方案
    caddy server 几个常用插件
    caddy server && caddyfile
    caddy server 默认https && http2的验证
    caddy server 了解
    redis 连接池的一些问题
    Hangfire 任务调度
    Spring Cloud feign 服务超时处理
    windows 2016 容器管理
  • 原文地址:https://www.cnblogs.com/rb2010/p/13061353.html
Copyright © 2011-2022 走看看