天天看點

ES7.6基本操作以及SpringBoot整合ES7.6的API(RestHighLevelClient)

# ik_smart最少切分
GET _analyze
{
  "analyzer": "ik_smart",
  "text": "河南科技大學"
}

# ik_max_word 最細粒度劃分!窮盡詞庫所有可能
GET _analyze
{
  "analyzer": "ik_max_word",
  "text": "河南科技大學"
}

# ===================ES索引相關的基本操作=======================
# 建立索引(資料庫)
# 索引庫名稱:csp ,文檔類型名稱:mytype ,文檔id:1
PUT /csp/mytype/1
{
  "name":"興趣使然的草帽路飛",
  "age":"22"
}

# 建立一個csp2索引庫:
# 索引庫名稱:csp2
# 索引庫中3個字段:name,age,birthday
# 3個字段的類型為:text,integer,date
PUT /csp2
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "age":{
        "type": "integer"
      },
      "birthday":{
        "type": "date"
      }
    }
  }
}

# 獲得索引csp2的相關資訊
GET csp2

# 建立索引csp3,文檔類型使用預設的_doc,文檔id:1
# 資料為:nage,age,birthday
PUT /csp3/_doc/1
{
  "name":"興趣使然的草帽路飛",
  "age":22,
  "birthday":"1999-01-29"
}

# 檢視索引csp3預設的資訊
GET csp3

# 檢視es健康狀态
GET _cat/health

# 檢視所有索引庫簡要資訊
GET _cat/indices?v

# 修改索引csp3資料
# 修改的字段name
POST /csp3/_doc/1/_update
{
  "doc":{
    "name":"海賊王路飛"
  }
}

# 删除csp索引庫
DELETE csp

# ===================ES文檔相關的基本操作=======================
# 建立索引my_index,文檔類型user,文檔id:1
# user:1
PUT /my_index/user/1
{
  "name":"草帽路飛",
  "age":22,
  "description":"海賊王,我當定了!",
  "tags":["吃貨","船長","未來的海賊王","橡膠果實能力者"]
}
# user:2
PUT /my_index/user/4
{
  "name":"海賊獵人索隆1",
  "age":22,
  "description":"背後的傷疤,是劍士的恥辱!",
  "tags":["路癡","副船長","未來的世界第一大劍豪","三刀流劍客"]
}
PUT /my_index/user/5
{
  "name":"海賊獵人索隆2",
  "age":25,
  "description":"背後的傷疤,是劍士的恥辱!",
  "tags":["路癡","副船長","未來的世界第一大劍豪","三刀流劍客"]
}
PUT /my_index/user/2
{
  "name":"海賊獵人索隆3",
  "age":24,
  "description":"背後的傷疤,是劍士的恥辱!",
  "tags":["路癡","副船長","未來的世界第一大劍豪","三刀流劍客"]
}
# user:3
PUT /my_index/user/3
{
  "name":"黑足山治",
  "age":22,
  "description":"為了天下女性而活!",
  "tags":["色胚","廚師","未來海賊王船上的初始","踢技炫酷"]
}

# 擷取資料 
# 擷取user:1
GET /my_index/user/1

# 搜尋資料
GET /my_index/user/_search?q=name:路飛

# 搜尋資料,通過json建構查詢參數
# 搜尋得到的結果中:
# hits: 表示索引和文檔相關資訊
#     "total":
#           "value": 查詢到的結果的總記錄數
#           "relation":  搜尋結果和搜尋參數的關系:eq表示相等 lt小于 gt大于
#     "_index": 表示索引名稱
#     "_tyoe": 表示文檔類型
#     "_id": 表示文檔id
#     "_score": 表示搜尋結果的權重
#     "_source": 表示文檔中的資料
#             文檔中資料的字段名稱以及值
GET /my_index/user/_search
{
  "query": {
    "match": {
      "name": "索隆"
    }
  }
}

# 搜尋資料,通過json建構查詢參數,加上結果過濾
# query:建構要搜尋的條件,match:建構要比對的内容
# _source: 結果過濾,隻擷取name和age字段資料
# sort: 排序條件 age:要排序的字段 order:desc 降序
# from:從第幾條資料開始0表示第一條,size:每頁顯示幾條資料
GET /my_index/user/_search
{
  "query": {
    "match": {
      "name": "索隆"
    }
  },
  "_source": ["name","age"],
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ],
  "from": 0,
  "size": 1
}

# 搜尋資料:使用bool多條件精确查詢
# 查詢22歲的所有使用者,且名字中帶有索隆的
# bool: 多條件精确查詢
#   must: [] 數組中的所有條件都需要符合  === 且and的關系
GET /my_index/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "age": "22"
          }
        },
        {
          "match": {
            "name": "索隆"
          }
        }
      ]
    }
  }
}

# 搜尋資料:使用bool多條件精确查詢
# 查詢22歲的所有使用者,或者名字中帶有索隆的所有使用者
# bool: 多條件精确查詢
#   shoud: [] 數組中的所有條件隻要有一個符合就行  === 或or的關系
GET /my_index/user/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "age": "22"
          }
        },
        {
          "match": {
            "name": "索隆"
          }
        }
      ]
    }
  }
}

# 搜尋資料:使用bool多條件精确查詢,filter過濾
# 查詢所有使用者,名字中有索隆的,且年齡在22-25之間
# bool: 多條件精确查詢,filter:按照字段過濾 === gt lt eq gte大于等于 lte 小于等于
GET /my_index/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "索隆"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lt": 22,
            "gt": 25
          }
        }
      }
    }
  }
}

# 根據tags數組中的内容搜尋,以空格分割查詢條件
# 結果:可以得到路飛和山治的資訊
GET /my_index/user/_search
{
  "query": {
    "match": {
      "tags": "廚師 船長"
    }
  }
}

# 精确查詢:
# term: 精确查詢,直接通過反向索引指定的詞條進行精确查找
# match: 會使用分詞器解析(先分析文檔,然後再通過分析的文檔進行查詢)
# 兩個類型: text 和 keyword

# 建立一個索引
PUT my_index2
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "description":{
        "type": "keyword"
      }
    }
  }
}

# 向my_index2插入資料
PUT /my_index2/_doc/1
{
  "name":"蒙奇D路飛",
  "description":"海賊王我當定了!"
}

# 使用分詞器查詢
#  "analyzer": "keyword" 使用ik分詞器查詢
GET _analyze
{
  "analyzer": "keyword",
  "text": "海賊王我當定了!"
}

# 使用分詞器查詢
#  "analyzer": "standard" 使用預設分詞器查詢
# 該分詞器會逐個拆分每個詞(字)
GET _analyze
{
  "analyzer": "standard",
  "text": "海賊王我當定了!"
}

# term 精确查詢
# 由結果得出:
# keyword類型(description)的字段不會被分詞器解析
# text類型(name)的字段會被分詞器解析
GET /my_index2/_search
{
  "query": {
    "term": {
      "name": {
        "value": "路"
      }
    }
  }
}

# 插入模拟資料
PUT /my_index2/_doc/3
{
  "t1":"33",
  "t2":"2020-1-17"
}
PUT /my_index2/_doc/4
{
  "t1":"44",
  "t2":"2020-1-18"
}
PUT /my_index2/_doc/5
{
  "t1":"55",
  "t2":"2020-1-19"
}
PUT /my_index2/_doc/6
{
  "t1":"66",
  "t2":"2020-1-20"
}

# 精确查詢多個值
GET /my_index2/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "t1": {
              "value": "44"
            }
          }
        },
        {
          "term": {
            "t1": {
              "value": "55"
            }
          }
        }
      ]
    }
  }
}

# (重點)高亮查詢:
# highlight:搜尋結果高亮展示
#     fields:對應的字段數組
#     pre_tags: 高亮展示結果的标簽字首,預設是<em>
#     post_tags: 高亮展示結果的标簽字尾,預設是</em>
GET /my_index/user/_search
{
  "query": {
    "match": {
      "name": "索隆"
    }
  },
  "highlight": {
    "pre_tags": "<p class='key' style='color:red'>",
    "post_tags": "</p>", 
    "fields": {
      "name":{}
    }
  }
}
      

SpringBoot整合ES

pom.xml

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

可以在application.yml中配置,也可以使用下面的方法配置:

ElasticSearchConfig.java

/**
 * @Auther: csp1999
 * @Date: 2020/07/11/15:16
 * @Description: ES 用戶端配置
 */
@Configuration // 相當于xml 配置 bean
public class ElasticSearchConfig {

    // spring <beans id="restHighLevelClient" class="RestHighLevelClient">
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("127.0.0.1", 9200, "http")));
        return client;
    }
}
      

SpringBoot測試類

/**
 * @Auther: csp1999
 * @Date: 2020/07/11/15:16
 * @Description: es7.6.x用戶端測試 API
 */
@SpringBootTest
class HaustEsApiApplicationTests {

    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    /**
     * 索引的建立 Request: PUT csp_index
     *
     * @throws IOException
     */
    @Test
    void testCreateIndex() throws IOException {
        // 1.建立索引請求
        CreateIndexRequest request = new CreateIndexRequest("csp_index");
        // 2.執行建立請求 IndicesClient 請求後獲得響應
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(createIndexResponse);// org.elasticsearch.client.indices.CreateIndexResponse@cd831c72
    }

    /**
     * 擷取索引 GET
     *
     * @throws IOException
     */
    @Test
    void testExistIndex() throws IOException {
        // 1.擷取索引庫的請求
        GetIndexRequest request = new GetIndexRequest("csp_index");
        // 2.執行擷取索引庫的請求
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(exists);// 如果索引庫存在,則輸出:true,否則輸出false
    }

    /**
     * 删除索引 DELETE
     *
     * @throws IOException
     */
    @Test
    void testDeleteIndex() throws IOException {
        // 1.删除索引庫的請求
        DeleteIndexRequest request = new DeleteIndexRequest("csp_index");
        // 2.執行删除索引庫的請求
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(delete.isAcknowledged());// 删除成功輸出true,否則為false
    }

    /**
     * 添加文檔
     *
     * @throws IOException
     */
    @Test
    void testAddDocument() throws IOException {
        // 1.建立對象
        User user = new User("興趣使然的草帽路飛", 22);
        // 2.建立請求
        IndexRequest request = new IndexRequest("csp_index");

        // 3.建構請求規則:PUT /csp_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        //request.timeout("1s");

        // 4.将user對象資料放入請求,json 資料: 需要用到fastjson
        request.source(JSON.toJSONString(user), XContentType.JSON);

        // 5.用戶端發送請求,擷取響應的結果
        IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);

        // 輸出結果
        // IndexResponse[index=csp_index,type=_doc,id=1,version=1,result=created,seqNo=0,primaryTerm=1,shards={"total":2,"successful":1,"failed":0}]
        System.out.println(indexResponse.toString());
        System.out.println(indexResponse.status());// CREATED:表示建立成功
    }

    /**
     * 擷取文檔,判斷是否存在
     *
     * @throws IOException
     */
    @Test
    void testIsExists() throws IOException {
        // 1.判斷文檔是否存在的請求
        GetRequest request = new GetRequest("csp_index", "1");

        // 2.執行請求:判斷文檔是否存在
        boolean exists = client.exists(request, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(exists);// 存在傳回true,否則傳回false
    }

    /**
     * 擷取文檔資訊
     *
     * @throws IOException
     */
    @Test
    void testGetDocument() throws IOException {
        // 1.擷取文檔資訊的請求
        GetRequest getRequest = new GetRequest("csp_index", "1");
        // 2.執行擷取文檔資訊的請求
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(getResponse.getSourceAsString()); //{"age":22,"name":"興趣使然的草帽路飛"}
        System.out.println(getResponse);// 傳回的全部内容和指令 是一樣的:
        // {"_index":"csp_index","_type":"_doc","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source":{"age":22,"name":"興趣使然的草帽路飛"}}
    }

    /**
     * 更新文檔資訊
     *
     * @throws IOException
     */
    @Test
    void testUpdateDocument() throws IOException {
        // 1.更新文檔請求
        UpdateRequest updateRequest = new UpdateRequest("csp_index", "1");
        // 設定請求逾時時間
        updateRequest.timeout("1s");
        // user資料對象封裝到json中
        User user = new User("興趣使然的諾諾亞索隆", 23);
        updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);

        // 2.執行更新文檔請求
        UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(updateResponse.status());// OK:表示更新成功
    }

    /**
     * 删除文檔記錄
     *
     * @throws IOException
     */
    @Test
    void testDeleteDocument() throws IOException {
        // 1.删除文檔請求
        DeleteRequest deleteRequest = new DeleteRequest("csp_index", "1");
        deleteRequest.timeout("1s");

        // 2.執行删除文檔請求
        DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(deleteResponse.status());// OK:表示删除成功
    }

    /**
     * 批量插入資料
     *
     * @throws IOException
     */
    @Test
    void testBulkRequest() throws IOException {
        // 1.批處理請求
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");

        // user資料集合
        ArrayList<User> list = new ArrayList<>();
        list.add(new User("路飛", 1));
        list.add(new User("索隆", 2));
        list.add(new User("山治", 3));
        list.add(new User("娜美", 4));
        list.add(new User("羅賓", 5));
        list.add(new User("喬巴", 6));
        list.add(new User("烏索普", 7));
        list.add(new User("弗蘭奇", 8));
        list.add(new User("布魯克", 9));
        list.add(new User("甚平", 10));

        for (int i = 0; i < list.size(); i++) {
            // 批量更新,修改,删除 都是在此進行操作
            bulkRequest.add(
                    new IndexRequest("csp_index")
                            // 批量指派文檔id: 如果不在自己指派文檔id,會預設生成随機的文檔id
                            .id("" + (i + 1))
                            // ArrayList轉換成json
                            .source(JSON.toJSONString(list.get(i)), XContentType.JSON)
            );
        }
        // 2.執行批量插入請求
        BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);

        // 輸出結果
        System.out.println(bulkResponse.status());// OK: 表示批量插入成功!
    }

    /**
     * ES中資料搜尋:
     * SearchRequest 搜尋請求
     * SearchRequest 搜尋請求
     * SearchSourceBuilder 條件構造
     * HighlightBuilder 建構高亮
     * TermQueryBuilder 精确查詢
     * XXXQueryBuilder 建構我們需要用到的指令
     *
     * @throws IOException
     */
    @Test
    void testSearch() throws IOException {
        // 1.建立搜尋請求
        SearchRequest searchRequest = new SearchRequest("csp_index");
        // 2.建構搜尋條件:條件構造器SearchSourceBuilder
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 高亮結果的條件構造器
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");// 要高亮的字段
        highlightBuilder.requireFieldMatch(false);// 不需要多個字段高亮,如果需要設定為true
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        // 條件構造器,開啟搜尋結果高亮,并加入高亮結果的條件構造器
        sourceBuilder.highlighter(highlightBuilder);

        /**
         * 查詢條件,使用QueryBuilders工具類來實作:
         *              QueryBuilders.termQuery() 精确查詢
         *              QueryBuilders.matchAllQuery() 比對所有
         */
        //TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "csp");// 精确查詢
        //MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();// 搜尋所有資料
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "路飛");// 搜尋字段name為路飛的資料

        // 查詢條件(matchQueryBuilder)放入條件構造器
        sourceBuilder.query(matchQueryBuilder);

        // 條件構造器,開啟分頁條件: 從第1個資料開始,每頁展示5條結果資料
        sourceBuilder.from(0);
        sourceBuilder.size(5);

        // 條件構造器,搜尋請求逾時時間60s
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        // 将條件構造器放入搜尋請求
        searchRequest.source(sourceBuilder);

        // 執行搜尋請求,并獲得searchResponse響應
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

        // 搜尋得到的所有結果都封裝在hits裡面,拿資料從hits裡面擷取
        SearchHits hits = searchResponse.getHits();
        //System.out.println(JSON.toJSONString(hits));

        // 周遊hits:解析結果,并将結果放入resultList集合
        ArrayList<Map<String, Object>> resultList = new ArrayList<>();
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            // 擷取高亮的字段
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField name = highlightFields.get("name");// 擷取高亮的字段

            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 先擷取原來未高亮的結果

            // 解析高亮的字段, 将原來未高亮的title字段換成高亮的字段
            if (name != null) {
                Text[] fragments = name.fragments();
                String newName = "";
                for (Text text : fragments) {
                    newName += text;
                }
                // 高亮字段替換原來内容
                sourceAsMap.put("name", newName);
            }
            resultList.add(documentFields.getSourceAsMap());
        }

        // 周遊resultList
        resultList.forEach(item -> {
            System.out.println(item);// {name=<span style='color:red'>路</span><span style='color:red'>飛</span>, age=1}
        });
    }
}