不講武德,萬字長文詳解SpringBoot 操做 ElasticSearch

你知道的越多,不知道的就越多,業餘的像一棵小草!

你來,咱們一塊兒精進!你不來,我和你的競爭對手一塊兒精進!
java

編輯:業餘草

rrd.me/gBaFy

推薦:https://www.xttblog.com/?p=5120

1、ElasticSearch 簡介

一、簡介

ElasticSearch 是一個基於 Lucene 的搜索服務器。它提供了一個分佈式多員工能力的全文搜索引擎,基於 RESTful web 接口。Elasticsearch 是用 Java 語言開發的,並做爲 Apache 許可條款下的開放源碼發佈,是一種流行的企業級搜索引擎。git

ElasticSearch 用於雲計算中,可以達到實時搜索,穩定,可靠,快速,安裝使用方便。github

二、特性

  • 分佈式的文檔存儲引擎web

  • 分佈式的搜索引擎和分析引擎spring

  • 分佈式,支持PB級數據數據庫

三、使用場景

  • 搜索領域:如百度、谷歌,全文檢索等。apache

  • 門戶網站:訪問統計、文章點贊、留言評論等。json

  • 廣告推廣:記錄員工行爲數據、消費趨勢、員工羣體進行定製推廣等。後端

  • 信息採集:記錄應用的埋點數據、訪問日誌數據等,方便大數據進行分析。數組

2、ElasticSearch 基礎概念

一、ElaticSearch 和 DB 的關係

在 Elasticsearch 中,文檔歸屬於一種類型 type,而這些類型存在於索引 index 中,咱們能夠列一些簡單的不一樣點,來類比傳統關係型數據庫:

  • Relational DB -> Databases -> Tables -> Rows -> Columns

  • Elasticsearch -> Indices -> Types -> Documents -> Fields

Elasticsearch 集羣能夠包含多個索引 indices,每個索引能夠包含多個類型 types,每個類型包含多個文檔 documents,而後每一個文檔包含多個字段 Fields。而在 DB 中能夠有多個數據庫 Databases,每一個庫中能夠有多張表 Tables,沒個表中又包含多行Rows,每行包含多列Columns。

二、索引

索引基本概念(indices):

索引是含義相同屬性的文檔集合,是 ElasticSearch 的一個邏輯存儲,能夠理解爲關係型數據庫中的數據庫,ElasticSearch 能夠把索引數據存放到一臺服務器上,也能夠 sharding 後存到多臺服務器上,每一個索引有一個或多個分片,每一個分片能夠有多個副本。

索引類型(index_type):

索引能夠定義一個或多個類型,文檔必須屬於一個類型。在 ElasticSearch 中,一個索引對象能夠存儲多個不一樣用途的對象,經過索引類型能夠區分單個索引中的不一樣對象,能夠理解爲關係型數據庫中的表。每一個索引類型能夠有不一樣的結構,可是不一樣的索引類型不能爲相同的屬性設置不一樣的類型。

三、文檔

文檔(document):

文檔是能夠被索引的基本數據單位。存儲在 ElasticSearch 中的主要實體叫文檔 document,能夠理解爲關係型數據庫中表的一行記錄。每一個文檔由多個字段構成,ElasticSearch 是一個非結構化的數據庫,每一個文檔能夠有不一樣的字段,而且有一個惟一的標識符。

四、映射

映射(mapping):

ElasticSearch 的 Mapping 很是相似於靜態語言中的數據類型:聲明一個變量爲 int 類型的變量,之後這個變量都只能存儲 int 類型的數據。一樣的,一個 number 類型的 mapping 字段只能存儲 number 類型的數據。

同語言的數據類型相比,Mapping 還有一些其餘的含義,Mapping 不只告訴 ElasticSearch 一個 Field 中是什麼類型的值, 它還告訴 ElasticSearch 如何索引數據以及數據是否能被搜索到。

ElaticSearch 默認是動態建立索引和索引類型的 Mapping 的。這就至關於無需定義 Solr 中的 Schema,無需指定各個字段的索引規則就能夠索引文件,很方便。但有時方便就表明着不靈活。好比,ElasticSearch 默認一個字段是要作分詞的,但咱們有時要搜索匹配整個字段卻不行。若有統計工做要記錄每一個城市出現的次數。對於 name 字段,若記錄 new york 文本,ElasticSearch 可能會把它拆分紅 new 和 york 這兩個詞,分別計算這個兩個單詞的次數,而不是咱們指望的 new york。

3、SpringBoot 項目引入 ElasticSearch 依賴

下面介紹下 SpringBoot 如何經過 elasticsearch-rest-high-level-client 工具操做 ElasticSearch,這裏須要說一下,爲何沒有使用 Spring 家族封裝的 spring-data-elasticsearch。

主要緣由是靈活性和更新速度,Spring 將 ElasticSearch 過分封裝,讓開發者很難跟 ES 的 DSL 查詢語句進行關聯。再者就是更新速度,ES 的更新速度是很是快,可是 spring-data-elasticsearch 更新速度比較緩慢。

因爲上面兩點,因此選擇了官方推出的 Java 客戶端 elasticsearch-rest-high-level-client,它的代碼寫法跟 DSL 語句很類似,懂 ES 查詢的使用其上手很快。

示例項目地址:https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-elasticsearch-example

一、Maven 引入相關依賴

  • lombok:lombok 工具依賴。

  • fastjson:用於將 JSON 轉換對象的依賴。

  • spring-boot-starter-web: SpringBoot 的 Web 依賴。

  • elasticsearch:ElasticSearch:依賴,須要和 ES 版本保持一致。

  • elasticsearch-rest-high-level-client:用於操做 ES 的 Java 客戶端。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>club.mydlq</groupId>
    <artifactId>springboot-elasticsearch-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-elasticsearch-example</name>
    <description>Demo project for Spring Boot ElasticSearch</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.61</version>
        </dependency>
        <!--elasticsearch-->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.5.4</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

二、ElasticSearch 鏈接配置

(1)、application.yml 配置文件

爲了方便更改鏈接 ES 的鏈接配置,因此咱們將配置信息放置於 application.yaml 中:

#base
server:
  port: 8080
#spring
spring:
  application:
    namespringboot-elasticsearch-example
#elasticsearch
elasticsearch:
  schemahttp
  address: 127.0.0.1:9200
  connectTimeout: 5000
  socketTimeout: 5000
  connectionRequestTimeout: 5000
  maxConnectNum: 100
  maxConnectPerRoute: 100

(2)、java 鏈接配置類

這裏須要寫一個 Java 配置類讀取 application 中的配置信息:

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;

/**
 * ElasticSearch 配置
 */

@Configuration
public class ElasticSearchConfig {

    /** 協議 */
    @Value("${elasticsearch.schema:http}")
    private String schema;

    /** 集羣地址,若是有多個用「,」隔開 */
    @Value("${elasticsearch.address}")
    private String address;

    /** 鏈接超時時間 */
    @Value("${elasticsearch.connectTimeout:5000}")
    private int connectTimeout;

    /** Socket 鏈接超時時間 */
    @Value("${elasticsearch.socketTimeout:10000}")
    private int socketTimeout;

    /** 獲取鏈接的超時時間 */
    @Value("${elasticsearch.connectionRequestTimeout:5000}")
    private int connectionRequestTimeout;

    /** 最大鏈接數 */
    @Value("${elasticsearch.maxConnectNum:100}")
    private int maxConnectNum;

    /** 最大路由鏈接數 */
    @Value("${elasticsearch.maxConnectPerRoute:100}")
    private int maxConnectPerRoute;

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        // 拆分地址
        List<HttpHost> hostLists = new ArrayList<>();
        String[] hostList = address.split(",");
        for (String addr : hostList) {
            String host = addr.split(":")[0];
            String port = addr.split(":")[1];
            hostLists.add(new HttpHost(host, Integer.parseInt(port), schema));
        }
        // 轉換成 HttpHost 數組
        HttpHost[] httpHost = hostLists.toArray(new HttpHost[]{});
        // 構建鏈接對象
        RestClientBuilder builder = RestClient.builder(httpHost);
        // 異步鏈接延時配置
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(connectTimeout);
            requestConfigBuilder.setSocketTimeout(socketTimeout);
            requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
            return requestConfigBuilder;
        });
        // 異步鏈接數配置
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(maxConnectNum);
            httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
            return httpClientBuilder;
        });
        return new RestHighLevelClient(builder);
    }

}

4、索引操做示例

這裏示例會指出經過 Kibana 的 Restful 工具操做與對應的 Java 代碼操做的兩個示例。擴展:某小公司RESTful、共用接口、先後端分離、接口約定的實踐

一、Restful 操做示例

建立索引

建立名爲 mydlq-user 的索引與對應 Mapping。

PUT /mydlq-user
{
  "mappings": {
    "doc": {
      "dynamic"true,
      "properties": {
        "name": {
          "type""text",
          "fields": {
            "keyword": {
              "type""keyword"
            }
          }
        },
        "address": {
          "type""text",
          "fields": {
            "keyword": {
              "type""keyword"
            }
          }
        },
        "remark": {
          "type""text",
          "fields": {
            "keyword": {
              "type""keyword"
            }
          }
        },
        "age": {
          "type""integer"
        },
        "salary": {
          "type""float"
        },
        "birthDate": {
          "type""date",
          "format""yyyy-MM-dd"
        },
        "createTime": {
          "type""date"
        }
      }
    }
  }
}

刪除索引

刪除 mydlq-user 索引。

DELETE /mydlq-user

二、Java 代碼示例

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class IndexService2 {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 建立索引
     */

    public void createIndex() {
        try {
            // 建立 Mapping
            XContentBuilder mapping = XContentFactory.jsonBuilder()
                .startObject()
                    .field("dynamic"true)
                    .startObject("properties")
                        .startObject("name")
                            .field("type","text")
                            .startObject("fields")
                                .startObject("keyword")
                                    .field("type","keyword")
                                .endObject()
                            .endObject()
                        .endObject()
                        .startObject("address")
                            .field("type","text")
                            .startObject("fields")
                                .startObject("keyword")
                                    .field("type","keyword")
                                .endObject()
                            .endObject()
                        .endObject()
                        .startObject("remark")
                            .field("type","text")
                            .startObject("fields")
                                .startObject("keyword")
                                    .field("type","keyword")
                                .endObject()
                            .endObject()
                        .endObject()
                        .startObject("age")
                            .field("type","integer")
                        .endObject()
                        .startObject("salary")
                            .field("type","float")
                        .endObject()
                        .startObject("birthDate")
                            .field("type","date")
                            .field("format""yyyy-MM-dd")
                        .endObject()
                        .startObject("createTime")
                            .field("type","date")
                        .endObject()
                    .endObject()
                .endObject();
            // 建立索引配置信息,配置
            Settings settings = Settings.builder()
                    .put("index.number_of_shards"1)
                    .put("index.number_of_replicas"0)
                    .build();
            // 新建建立索引請求對象,而後設置索引類型(ES 7.0 將不存在索引類型)和 mapping 與 index 配置
            CreateIndexRequest request = new CreateIndexRequest("mydlq-user", settings);
            request.mapping("doc", mapping);
            // RestHighLevelClient 執行建立索引
            CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            // 判斷是否建立成功
            boolean isCreated = createIndexResponse.isAcknowledged();
            log.info("是否建立成功:{}", isCreated);
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 刪除索引
     */

    public void deleteIndex() {
        try {
            // 新建刪除索引請求對象
            DeleteIndexRequest request = new DeleteIndexRequest("mydlq-user");
            // 執行刪除索引
            AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
            // 判斷是否刪除成功
            boolean siDeleted = acknowledgedResponse.isAcknowledged();
            log.info("是否刪除成功:{}", siDeleted);
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

5、文檔操做示例

一、Restful 操做示例

增長文檔信息

在索引 mydlq-user 中增長一條文檔信息。

POST /mydlq-user/doc
{
    "address""北京市",
    "age": 29,
    "birthDate""1990-01-10",
    "createTime": 1579530727699,
    "name""張三",
    "remark""來自北京市的張先生",
    "salary": 100
}

獲取文檔信息

獲取 mydlq-user 的索引 id=1 的文檔信息。

GET /mydlq-user/doc/1

更新文檔信息

更新以前建立的 id=1 的文檔信息。

PUT /mydlq-user/doc/1
{
    "address""北京市海淀區",
    "age": 29,
    "birthDate""1990-01-10",
    "createTime": 1579530727699,
    "name""張三",
    "remark""來自北京市的張先生",
    "salary": 100
}

刪除文檔信息

刪除以前建立的 id=1 的文檔信息。

DELETE /mydlq-user/doc/1

二、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.Date;

@Slf4j
@Service
public class IndexService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 增長文檔信息
     */

    public void addDocument() {
        try {
            // 建立索引請求對象
            IndexRequest indexRequest = new IndexRequest("mydlq-user""doc""1");
            // 建立員工信息
            UserInfo userInfo = new UserInfo();
            userInfo.setName("張三");
            userInfo.setAge(29);
            userInfo.setSalary(100.00f);
            userInfo.setAddress("北京市");
            userInfo.setRemark("來自北京市的張先生");
            userInfo.setCreateTime(new Date());
            userInfo.setBirthDate("1990-01-10");
            // 將對象轉換爲 byte 數組
            byte[] json = JSON.toJSONBytes(userInfo);
            // 設置文檔內容
            indexRequest.source(json, XContentType.JSON);
            // 執行增長文檔
            IndexResponse response = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
            log.info("建立狀態:{}", response.status());
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 獲取文檔信息
     */

    public void getDocument() {
        try {
            // 獲取請求對象
            GetRequest getRequest = new GetRequest("mydlq-user""doc""1");
            // 獲取文檔信息
            GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
            // 將 JSON 轉換成對象
            if (getResponse.isExists()) {
                UserInfo userInfo = JSON.parseObject(getResponse.getSourceAsBytes(), UserInfo.class);
                log.info("員工信息:{}", userInfo);
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 更新文檔信息
     */

    public void updateDocument() {
        try {
            // 建立索引請求對象
            UpdateRequest updateRequest = new UpdateRequest("mydlq-user""doc""1");
            // 設置員工更新信息
            UserInfo userInfo = new UserInfo();
            userInfo.setSalary(200.00f);
            userInfo.setAddress("北京市海淀區");
            // 將對象轉換爲 byte 數組
            byte[] json = JSON.toJSONBytes(userInfo);
            // 設置更新文檔內容
            updateRequest.doc(json, XContentType.JSON);
            // 執行更新文檔
            UpdateResponse response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            log.info("建立狀態:{}", response.status());
        } catch (Exception e) {
            log.error("", e);
        }
    }

    /**
     * 刪除文檔信息
     */

    public void deleteDocument() {
        try {
            // 建立刪除請求對象
            DeleteRequest deleteRequest = new DeleteRequest("mydlq-user""doc""1");
            // 執行刪除文檔
            DeleteResponse response = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
            log.info("刪除狀態:{}", response.status());
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

6、插入初始化數據

執行查詢示例前,先往索引中插入一批數據:

一、單條插入

POST mydlq-user/_doc

{"name":"零零","address":"北京市豐臺區","remark":"低層員工","age":29,"salary":3000,"birthDate":"1990-11-11","createTime":"2019-11-11T08:18:00.000Z"}

二、批量插入

POST _bulk

{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"劉一","address":"北京市豐臺區","remark":"低層員工","age":30,"salary":3000,"birthDate":"1989-11-11","createTime":"2019-03-15T08:18:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"陳二","address":"北京市昌平區","remark":"中層員工","age":27,"salary":7900,"birthDate":"1992-01-25","createTime":"2019-11-08T11:15:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"張三","address":"北京市房山區","remark":"中層員工","age":28,"salary":8800,"birthDate":"1991-10-05","createTime":"2019-07-22T13:22:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"李四","address":"北京市大興區","remark":"高層員工","age":26,"salary":9000,"birthDate":"1993-08-18","createTime":"2019-10-17T15:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"王五","address":"北京市密雲區","remark":"低層員工","age":31,"salary":4800,"birthDate":"1988-07-20","createTime":"2019-05-29T09:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"趙六","address":"北京市通州區","remark":"中層員工","age":32,"salary":6500,"birthDate":"1987-06-02","createTime":"2019-12-10T18:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"孫七","address":"北京市朝陽區","remark":"中層員工","age":33,"salary":7000,"birthDate":"1986-04-15","createTime":"2019-06-06T13:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"周八","address":"北京市西城區","remark":"低層員工","age":32,"salary":5000,"birthDate":"1987-09-26","createTime":"2019-01-26T14:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"吳九","address":"北京市海淀區","remark":"高層員工","age":30,"salary":11000,"birthDate":"1989-11-25","createTime":"2019-09-07T13:34:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"鄭十","address":"北京市東城區","remark":"低層員工","age":29,"salary":5000,"birthDate":"1990-12-25","createTime":"2019-03-06T12:08:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"蕭十一","address":"北京市平谷區","remark":"低層員工","age":29,"salary":3300,"birthDate":"1990-11-11","createTime":"2019-03-10T08:17:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"曹十二","address":"北京市懷柔區","remark":"中層員工","age":27,"salary":6800,"birthDate":"1992-01-25","createTime":"2019-12-03T11:09:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"吳十三","address":"北京市延慶區","remark":"中層員工","age":25,"salary":7000,"birthDate":"1994-10-05","createTime":"2019-07-27T14:22:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"馮十四","address":"北京市密雲區","remark":"低層員工","age":25,"salary":3000,"birthDate":"1994-08-18","createTime":"2019-04-22T15:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"蔣十五","address":"北京市通州區","remark":"低層員工","age":31,"salary":2800,"birthDate":"1988-07-20","createTime":"2019-06-13T10:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"苗十六","address":"北京市門頭溝區","remark":"高層員工","age":32,"salary":11500,"birthDate":"1987-06-02","createTime":"2019-11-11T18:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"魯十七","address":"北京市石景山區","remark":"高員工","age":33,"salary":9500,"birthDate":"1986-04-15","createTime":"2019-06-06T14:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"沈十八","address":"北京市朝陽區","remark":"中層員工","age":31,"salary":8300,"birthDate":"1988-09-26","createTime":"2019-09-25T14:00:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"呂十九","address":"北京市西城區","remark":"低層員工","age":31,"salary":4500,"birthDate":"1988-11-25","createTime":"2019-09-22T13:34:00.000Z"}
{"index":{"_index":"mydlq-user","_type":"doc"}}
{"name":"丁二十","address":"北京市東城區","remark":"低層員工","age":33,"salary":2100,"birthDate":"1986-12-25","createTime":"2019-03-07T12:08:00.000Z"}

三、查詢數據

插入完成後再查詢數據,查看以前插入的數據是否存在:

GET mydlq-user/_search

執行後獲得下面記錄:

{
  "took"2,
  "timed_out"false,
  "_shards": {
    "total"1,
    "successful"1,
    "skipped"0,
    "failed"0
  },
  "hits": {
    "total"20,
    "max_score"1,
    "hits": [
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""BeN0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""劉一",
          "address""北京市豐臺區",
          "remark""低層員工",
          "age"30,
          "salary"3000,
          "birthDate""1989-11-11",
          "createTime""2019-03-15T08:18:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""BuN0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""陳二",
          "address""北京市昌平區",
          "remark""中層員工",
          "age"27,
          "salary"7900,
          "birthDate""1992-01-25",
          "createTime""2019-11-08T11:15:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""B-N0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""張三",
          "address""北京市房山區",
          "remark""中層員工",
          "age"28,
          "salary"8800,
          "birthDate""1991-10-05",
          "createTime""2019-07-22T13:22:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""CON0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""李四",
          "address""北京市大興區",
          "remark""高層員工",
          "age"26,
          "salary"9000,
          "birthDate""1993-08-18",
          "createTime""2019-10-17T15:00:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""CeN0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""王五",
          "address""北京市密雲區",
          "remark""低層員工",
          "age"31,
          "salary"4800,
          "birthDate""1988-07-20",
          "createTime""2019-05-29T09:00:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""CuN0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""趙六",
          "address""北京市通州區",
          "remark""中層員工",
          "age"32,
          "salary"6500,
          "birthDate""1987-06-02",
          "createTime""2019-12-10T18:00:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""C-N0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""孫七",
          "address""北京市朝陽區",
          "remark""中層員工",
          "age"33,
          "salary"7000,
          "birthDate""1986-04-15",
          "createTime""2019-06-06T13:00:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""DON0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""周八",
          "address""北京市西城區",
          "remark""低層員工",
          "age"32,
          "salary"5000,
          "birthDate""1987-09-26",
          "createTime""2019-01-26T14:00:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""DeN0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""吳九",
          "address""北京市海淀區",
          "remark""高層員工",
          "age"30,
          "salary"11000,
          "birthDate""1989-11-25",
          "createTime""2019-09-07T13:34:00.000Z"
        }
      },
      {
        "_index""mydlq-user",
        "_type""_doc",
        "_id""DuN0BW8B7BNodGwRFTRj",
        "_score"1,
        "_source": {
          "name""鄭十",
          "address""北京市東城區",
          "remark""低層員工",
          "age"29,
          "salary"5000,
          "birthDate""1990-12-25",
          "createTime""2019-03-06T12:08:00.000Z"
        }
      }
    ]
  }
}

7、查詢操做示例

一、精確查詢(term)

(1)、Restful 操做示例

精確查詢

精確查詢,查詢地址爲 北京市通州區 的人員信息:

查詢條件不會進行分詞,可是查詢內容可能會分詞,致使查詢不到。以前在建立索引時設置 Mapping 中 address 字段存在 keyword 字段是專門用於不分詞查詢的子字段。

GET mydlq-user/_search
{
  "query": {
    "term": {
      "address.keyword": {
        "value""北京市通州區"
      }
    }
  }
}

精確查詢-多內容查詢

精確查詢,查詢地址爲 北京市豐臺區、北京市昌平區 或 北京市大興區 的人員信息:

GET mydlq-user/_search
{
  "query": {
    "terms": {
      "address.keyword": [
        "北京市豐臺區",
        "北京市昌平區",
        "北京市大興區"
      ]
    }
  }
}

(2)、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class TermQueryService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 精確查詢(查詢條件不會進行分詞,可是查詢內容可能會分詞,致使查詢不到)
     */

    public void termQuery() {
        try {
            // 構建查詢條件(注意:termQuery 支持多種格式查詢,如 boolean、int、double、string 等,這裏使用的是 string 的查詢)
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.termQuery("address.keyword""北京市通州區"));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 多個內容在一個字段中進行查詢
     */

    public void termsQuery() {
        try {
            // 構建查詢條件(注意:termsQuery 支持多種格式查詢,如 boolean、int、double、string 等,這裏使用的是 string 的查詢)
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.termsQuery("address.keyword""北京市豐臺區""北京市昌平區""北京市大興區"));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

二、匹配查詢(match)

(1)、Restful 操做示例

匹配查詢所有數據與分頁

匹配查詢符合條件的全部數據,而且設置以 salary 字段升序排序,並設置分頁:

GET mydlq-user/_search
{
  "query": {
    "match_all": {}
  },
  "from"0,
  "size"10,
  "sort": [
    {
      "salary": {
        "order""asc"
      }
    }
  ]
}

匹配查詢數據

匹配查詢地址爲 通州區 的數據:

GET mydlq-user/_search
{
  "query": {
    "match": {
      "address""通州區"
    }
  }
}

詞語匹配查詢

詞語匹配進行查詢,匹配 address 中爲 北京市通州區 的員工信息:

GET mydlq-user/_search
{
  "query": {
    "match_phrase": {
      "address""北京市通州區"
    }
  }
}

內容多字段查詢

查詢在字段 address、remark 中存在 北京 內容的員工信息:

GET mydlq-user/_search
{
  "query": {
    "multi_match": {
      "query""北京",
      "fields": ["address","remark"]
    }
  }
}

(2)、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class MatchQueryService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 匹配查詢符合條件的全部數據,並設置分頁
     */

    public Object matchAllQuery() {
        try {
            // 構建查詢條件
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            // 建立查詢源構造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);
            // 設置分頁
            searchSourceBuilder.from(0);
            searchSourceBuilder.size(3);
            // 設置排序
            searchSourceBuilder.sort("salary", SortOrder.ASC);
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 匹配查詢數據
     */

    public Object matchQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchQuery("address""*通州區"));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 詞語匹配查詢
     */

    public Object matchPhraseQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("address""北京市通州區"));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 內容在多字段中進行查詢
     */

    public Object matchMultiQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery("北京市""address""remark"));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

三、模糊查詢(fuzzy)

(1)、Restful 操做示例

模糊查詢全部以 三 結尾的姓名

GET mydlq-user/_search
{
  "query": {
    "fuzzy": {
      "name""三"
    }
  }
}

(2)、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class FuzzyQueryService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 模糊查詢全部以 「三」 結尾的姓名
     */

    public Object fuzzyQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.fuzzyQuery("name""三").fuzziness(Fuzziness.AUTO));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

四、範圍查詢(range)

(1)、Restful 操做示例

查詢歲數 ≥ 30 歲的員工數據:

GET /mydlq-user/_search
{
  "query": {
    "range": {
      "age": {
        "gte"30
      }
    }
  }
}

查詢生日距離如今 30 年間的員工數據:

GET mydlq-user/_search
{
  "query": {
    "range": {
      "birthDate": {
        "gte""now-30y"
      }
    }
  }
}

(2)、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class RangeQueryService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 查詢歲數 ≥ 30 歲的員工數據
     */

    public void rangeQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.rangeQuery("age").gte(30));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 查詢距離如今 30 年間的員工數據
     * [年(y)、月(M)、星期(w)、天(d)、小時(h)、分鐘(m)、秒(s)]
     * 例如:
     * now-1h 查詢一小時內範圍
     * now-1d 查詢一天內時間範圍
     * now-1y 查詢最近一年內的時間範圍
     */

    public void dateRangeQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // includeLower(是否包含下邊界)、includeUpper(是否包含上邊界)
            searchSourceBuilder.query(QueryBuilders.rangeQuery("birthDate")
                    .gte("now-30y").includeLower(true).includeUpper(true));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

五、通配符查詢(wildcard)

(1)、Restful 操做示例

查詢全部以 「三」 結尾的姓名:

GET mydlq-user/_search
{
  "query": {
    "wildcard": {
      "name.keyword": {
        "value""*三"
      }
    }
  }
}

(2)、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class WildcardQueryService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 查詢全部以 「三」 結尾的姓名
     *
     * *:表示多個字符(0個或多個字符)
     * ?:表示單個字符
     */

    public Object wildcardQuery() {
        try {
            // 構建查詢條件
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.wildcardQuery("name.keyword""*三"));
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

六、布爾查詢(bool)

(1)、Restful 操做示例

查詢出生在 1990-1995 年期間,且地址在 北京市昌平區、北京市大興區、北京市房山區 的員工信息:

GET /mydlq-user/_search
{
  "query": {
    "bool": {
      "filter": {
        "range": {
          "birthDate": {
            "format""yyyy"
            "gte"1990,
            "lte"1995
          }
        }
      },
      "must": [
        {
          "terms": {
            "address.keyword": [
              "北京市昌平區",
              "北京市大興區",
              "北京市房山區"
            ]
          }
        }
      ]
    }
  }
}

(2)、Java 代碼示例

import club.mydlq.elasticsearch.model.entity.UserInfo;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class BoolQueryService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public Object boolQuery() {
        try {
            // 建立 Bool 查詢構建器
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            // 構建查詢條件
            boolQueryBuilder.must(QueryBuilders.termsQuery("address.keyword""北京市昌平區""北京市大興區""北京市房山區"))
                    .filter().add(QueryBuilders.rangeQuery("birthDate").format("yyyy").gte("1990").lte("1995"));
            // 構建查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(boolQueryBuilder);
            // 建立查詢請求對象,將查詢對象配置到其中
            SearchRequest searchRequest = new SearchRequest("mydlq-user");
            searchRequest.source(searchSourceBuilder);
            // 執行查詢,而後處理響應結果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 根據狀態和數據條數驗證是否返回了數據
            if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().totalHits > 0) {
                SearchHits hits = searchResponse.getHits();
                for (SearchHit hit : hits) {
                    // 將 JSON 轉換成對象
                    UserInfo userInfo = JSON.parseObject(hit.getSourceAsString(), UserInfo.class);
                    // 輸出查詢信息
                    log.info(userInfo.toString());
                }
            }
        }catch (IOException e){
            log.error("",e);
        }
    }

}

8、聚合查詢操做示例

一、Metric 聚合分析

(1)、Restful 操做示例

統計員工總數、工資最高值、工資最低值、工資平均工資、工資總和:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_stats": {
      "stats": {
        "field""salary"
      }
    }
  }
}

統計員工工資最低值:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_min": {
      "min": {
        "field""salary"
      }
    }
  }
}

統計員工工資最高值:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_max": {
      "max": {
        "field""salary"
      }
    }
  }
}

統計員工工資平均值:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_avg": {
      "avg": {
        "field""salary"
      }
    }
  }
}

統計員工工資總值:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_sum": {
      "sum": {
        "field""salary"
      }
    }
  }
}

統計員工總數:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "employee_count": {
      "value_count": {
        "field""salary"
      }
    }
  }
}

統計員工工資百分位:

GET /mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_percentiles": {
      "percentiles": {
        "field""salary"
      }
    }
  }
}

(2)、Java 代碼示例

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.metrics.avg.ParsedAvg;
import org.elasticsearch.search.aggregations.metrics.max.ParsedMax;
import org.elasticsearch.search.aggregations.metrics.min.ParsedMin;
import org.elasticsearch.search.aggregations.metrics.percentiles.ParsedPercentiles;
import org.elasticsearch.search.aggregations.metrics.percentiles.Percentile;
import org.elasticsearch.search.aggregations.metrics.stats.ParsedStats;
import org.elasticsearch.search.aggregations.metrics.sum.ParsedSum;
import org.elasticsearch.search.aggregations.metrics.sum.SumAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.valuecount.ParsedValueCount;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;

@Slf4j
@Service
public class AggrMetricService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * stats 統計員工總數、員工工資最高值、員工工資最低值、員工平均工資、員工工資總和
     */

    public Object aggregationStats() {
        String responseResult = "";
        try {
            // 設置聚合條件
            AggregationBuilder aggr = AggregationBuilders.stats("salary_stats").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            // 設置查詢結果不返回,只返回聚合結果
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 Stats 對象
                ParsedStats aggregation = aggregations.get("salary_stats");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                log.info("count:{}", aggregation.getCount());
                log.info("avg:{}", aggregation.getAvg());
                log.info("max:{}", aggregation.getMax());
                log.info("min:{}", aggregation.getMin());
                log.info("sum:{}", aggregation.getSum());
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

    /**
     * min 統計員工工資最低值
     */

    public Object aggregationMin() {
        String responseResult = "";
        try {
            // 設置聚合條件
            AggregationBuilder aggr = AggregationBuilders.min("salary_min").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 Min 對象
                ParsedMin aggregation = aggregations.get("salary_min");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                log.info("min:{}", aggregation.getValue());
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

    /**
     * max 統計員工工資最高值
     */

    public Object aggregationMax() {
        String responseResult = "";
        try {
            // 設置聚合條件
            AggregationBuilder aggr = AggregationBuilders.max("salary_max").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 Max 對象
                ParsedMax aggregation = aggregations.get("salary_max");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                log.info("max:{}", aggregation.getValue());
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

    /**
     * avg 統計員工工資平均值
     */

    public Object aggregationAvg() {
        String responseResult = "";
        try {
            // 設置聚合條件
            AggregationBuilder aggr = AggregationBuilders.avg("salary_avg").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 Avg 對象
                ParsedAvg aggregation = aggregations.get("salary_avg");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                log.info("avg:{}", aggregation.getValue());
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

    /**
     * sum 統計員工工資總值
     */

    public Object aggregationSum() {
        String responseResult = "";
        try {
            // 設置聚合條件
            SumAggregationBuilder aggr = AggregationBuilders.sum("salary_sum").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 Sum 對象
                ParsedSum aggregation = aggregations.get("salary_sum");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                log.info("sum:{}", String.valueOf((aggregation.getValue())));
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

    /**
     * count 統計員工總數
     */

    public Object aggregationCount() {
        String responseResult = "";
        try {
            // 設置聚合條件
            AggregationBuilder aggr = AggregationBuilders.count("employee_count").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 ValueCount 對象
                ParsedValueCount aggregation = aggregations.get("employee_count");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                log.info("count:{}", aggregation.getValue());
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

    /**
     * percentiles 統計員工工資百分位
     */

    public Object aggregationPercentiles() {
        String responseResult = "";
        try {
            // 設置聚合條件
            AggregationBuilder aggr = AggregationBuilders.percentiles("salary_percentiles").field("salary");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.aggregation(aggr);
            searchSourceBuilder.size(0);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status()) || aggregations != null) {
                // 轉換爲 Percentiles 對象
                ParsedPercentiles aggregation = aggregations.get("salary_percentiles");
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Percentile percentile : aggregation) {
                    log.info("百分位:{}:{}", percentile.getPercent(), percentile.getValue());
                }
                log.info("-------------------------------------------");
            }
            // 根據具體業務邏輯返回不一樣結果,這裏爲了方便直接將返回響應對象Json串
            responseResult = response.toString();
        } catch (IOException e) {
            log.error("", e);
        }
        return responseResult;
    }

}

二、Bucket 聚合分析

(1)、Restful 操做示例

按歲數進行聚合分桶,統計各個歲數員工的人數:

GET mydlq-user/_search
{
  "size"0,
  "aggs": {
    "age_bucket": {
      "terms": {
        "field""age",
        "size""10"
      }
    }
  }
}

按工資範圍進行聚合分桶,統計工資在 3000-5000、5000-9000 和 9000 以上的員工信息:

GET mydlq-user/_search
{
  "aggs": {
    "salary_range_bucket": {
      "range": {
        "field""salary",
        "ranges": [
          {
            "key""低級員工"
            "to"3000
          },{
            "key""中級員工",
            "from"5000,
            "to"9000
          },{
            "key""高級員工",
            "from"9000
          }
        ]
      }
    }
  }
}

按照時間範圍進行分桶,統計 1985-1990 年和 1990-1995 年出生的員工信息:

GET mydlq-user/_search
{
  "size"10,
  "aggs": {
    "date_range_bucket": {
      "date_range": {
        "field""birthDate",
        "format""yyyy"
        "ranges": [
          {
            "key""出生日期1985-1990的員工"
            "from""1985",
            "to""1990"
          },{
            "key""出生日期1990-1995的員工"
            "from""1990",
            "to""1995"
          }
        ]
      }
    }
  }
}

按工資多少進行聚合分桶,設置統計的最小值爲 0,最大值爲 12000,區段間隔爲 3000:

GET mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_histogram": {
      "histogram": {
        "field""salary",
        "extended_bounds": {
          "min"0,
          "max"12000
        }, 
        "interval"3000
      }
    }
  }
}

按出生日期進行分桶:

GET mydlq-user/_search
{
  "size"0,
  "aggs": {
    "birthday_histogram": {
      "date_histogram": {
        "format""yyyy"
        "field""birthDate",
        "interval""year"
      }
    }
  }
}

(2)、Java 代碼示例

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;

@Slf4j
@Service
public class AggrBucketService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * 按歲數進行聚合分桶
     */

    public Object aggrBucketTerms() {
        try {
            AggregationBuilder aggr = AggregationBuilders.terms("age_bucket").field("age");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(10);
            searchSourceBuilder.aggregation(aggr);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status())) {
                // 分桶
                Terms byCompanyAggregation = aggregations.get("age_bucket");
                List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
                // 輸出各個桶的內容
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Terms.Bucket bucket : buckets) {
                    log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
                }
                log.info("-------------------------------------------");
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 按工資範圍進行聚合分桶
     */

    public Object aggrBucketRange() {
        try {
            AggregationBuilder aggr = AggregationBuilders.range("salary_range_bucket")
                    .field("salary")
                    .addUnboundedTo("低級員工"3000)
                    .addRange("中級員工"50009000)
                    .addUnboundedFrom("高級員工"9000);
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(0);
            searchSourceBuilder.aggregation(aggr);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status())) {
                // 分桶
                Range byCompanyAggregation = aggregations.get("salary_range_bucket");
                List<? extends Range.Bucket> buckets = byCompanyAggregation.getBuckets();
                // 輸出各個桶的內容
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Range.Bucket bucket : buckets) {
                    log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
                }
                log.info("-------------------------------------------");
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 按照時間範圍進行分桶
     */

    public Object aggrBucketDateRange() {
        try {
            AggregationBuilder aggr = AggregationBuilders.dateRange("date_range_bucket")
                    .field("birthDate")
                    .format("yyyy")
                    .addRange("1985-1990""1985""1990")
                    .addRange("1990-1995""1990""1995");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(0);
            searchSourceBuilder.aggregation(aggr);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status())) {
                // 分桶
                Range byCompanyAggregation = aggregations.get("date_range_bucket");
                List<? extends Range.Bucket> buckets = byCompanyAggregation.getBuckets();
                // 輸出各個桶的內容
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Range.Bucket bucket : buckets) {
                    log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
                }
                log.info("-------------------------------------------");
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 按工資多少進行聚合分桶
     */

    public Object aggrBucketHistogram() {
        try {
            AggregationBuilder aggr = AggregationBuilders.histogram("salary_histogram")
                    .field("salary")
                    .extendedBounds(012000)
                    .interval(3000);
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(0);
            searchSourceBuilder.aggregation(aggr);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status())) {
                // 分桶
                Histogram byCompanyAggregation = aggregations.get("salary_histogram");
                List<? extends Histogram.Bucket> buckets = byCompanyAggregation.getBuckets();
                // 輸出各個桶的內容
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Histogram.Bucket bucket : buckets) {
                    log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
                }
                log.info("-------------------------------------------");
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

    /**
     * 按出生日期進行分桶
     */

    public Object aggrBucketDateHistogram() {
        try {
            AggregationBuilder aggr = AggregationBuilders.dateHistogram("birthday_histogram")
                    .field("birthDate")
                    .interval(1)
                    .dateHistogramInterval(DateHistogramInterval.YEAR)
                    .format("yyyy");
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(0);
            searchSourceBuilder.aggregation(aggr);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status())) {
                // 分桶
                Histogram byCompanyAggregation = aggregations.get("birthday_histogram");

                List<? extends Histogram.Bucket> buckets = byCompanyAggregation.getBuckets();
                // 輸出各個桶的內容
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Histogram.Bucket bucket : buckets) {
                    log.info("桶名:{} | 總數:{}", bucket.getKeyAsString(), bucket.getDocCount());
                }
                log.info("-------------------------------------------");
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

三、Metric 與 Bucket 聚合分析

(1)、Restful 操做示例

按照員工歲數分桶、而後統計每一個歲數員工工資最高值:

GET mydlq-user/_search
{
  "size"0,
  "aggs": {
    "salary_bucket": {
      "terms": {
        "field""age",
        "size""10"
      },
      "aggs": {
        "salary_max_user": {
          "top_hits": {
            "size"1,
            "sort": [
              {
                "salary": {
                  "order""desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

(2)、Java 代碼示例

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.tophits.ParsedTopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.List;

@Slf4j
@Service
public class AggrBucketMetricService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * topHits 按歲數分桶、而後統計每一個員工工資最高值
     */

    public Object aggregationTopHits() {
        try {
            AggregationBuilder testTop = AggregationBuilders.topHits("salary_max_user")
                    .size(1)
                    .sort("salary", SortOrder.DESC);
            AggregationBuilder salaryBucket = AggregationBuilders.terms("salary_bucket")
                    .field("age")
                    .size(10);
            salaryBucket.subAggregation(testTop);
            // 查詢源構建器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.size(0);
            searchSourceBuilder.aggregation(salaryBucket);
            // 建立查詢請求對象,將查詢條件配置到其中
            SearchRequest request = new SearchRequest("mydlq-user");
            request.source(searchSourceBuilder);
            // 執行請求
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            // 獲取響應中的聚合信息
            Aggregations aggregations = response.getAggregations();
            // 輸出內容
            if (RestStatus.OK.equals(response.status())) {
                // 分桶
                Terms byCompanyAggregation = aggregations.get("salary_bucket");
                List<? extends Terms.Bucket> buckets = byCompanyAggregation.getBuckets();
                // 輸出各個桶的內容
                log.info("-------------------------------------------");
                log.info("聚合信息:");
                for (Terms.Bucket bucket : buckets) {
                    log.info("桶名:{}", bucket.getKeyAsString());
                    ParsedTopHits topHits = bucket.getAggregations().get("salary_max_user");
                    for (SearchHit hit:topHits.getHits()){
                        log.info(hit.getSourceAsString());
                    }
                }
                log.info("-------------------------------------------");
            }
        } catch (IOException e) {
            log.error("", e);
        }
    }

}

本文分享自微信公衆號 - 業餘草(yyucao)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索