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這個對象,然后重復第二步,觀察命令順序,這時會傳入must\must_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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM