03.08 萬字長文說透 SpringBoot 使用 ElasticSearch


一、ElasticSearch 簡介

1、簡介

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

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

2、特性

  • 分佈式的文檔存儲引擎
  • 分佈式的搜索引擎和分析引擎
  • 分佈式,支持PB級數據

3、使用場景

  • 搜索領域:如百度、谷歌,全文檢索等。
  • 門戶網站:訪問統計、文章點贊、留言評論等。
  • 廣告推廣:記錄員工行為數據、消費趨勢、員工群體進行定製推廣等。
  • 信息採集:記錄應用的埋點數據、訪問日誌數據等,方便大數據進行分析。

二、ElasticSearch 基礎概念

1、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。

2、索引

索引基本概念(indices):

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

索引類型(index_type):

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

3、文檔

文檔(document):

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

4、映射

映射(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。

三、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 查詢的使用其上手很快。


1、Maven 引入相關依賴

  • lombok 工具依賴。
  • fastjson:用於將 JSON 轉換對象的依賴。
  • spring-boot-starter-web的 Web 依賴。
  • elasticsearch:ElasticSearch:依賴,需要和 ES 版本保持一致。
  • elasticsearch-rest-high-level-client:用於操作 ES 的 Java 客戶端。
<code>
<project>         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> 
    /<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>
        
        <dependency>
            <groupid>org.springframework.boot/<groupid>
            <artifactid>spring-boot-starter-web/<artifactid>
        /<dependency>

        
        <dependency>
            <groupid>org.projectlombok/<groupid>
            <artifactid>lombok/<artifactid>
            <optional>true/<optional>
        /<dependency>
        
        <dependency>
            <groupid>com.alibaba/<groupid>
            <artifactid>fastjson/<artifactid>
            <version>1.2.61/<version>
        /<dependency>
        
        <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>
/<code>

2、ElasticSearch 連接配置

(1)、application.yml 配置文件

為了方便更改連接 ES 的連接配置,所以我們將配置信息放置於 application.yaml 中:

<code>#base
server:
  port: 8080
#spring
spring:
  application:
    name: springboot-elasticsearch-example
#elasticsearch
elasticsearch:
  schema: http
  address: 127.0.0.1:9200
  connectTimeout: 5000
  socketTimeout: 5000
  connectionRequestTimeout: 5000
  maxConnectNum: 100
  maxConnectPerRoute: 100
/<code>

(2)、java 連接配置類

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

<code>

/**
 * 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);
    }


}
/<httphost>/<code>

四、索引操作示例

這裡示例會指出通過 Kibana 工具操作與對應的 Java 代碼操作的兩個示例。

1、Restful 操作示例

創建索引

創建名為 mydlq-user 的索引與對應 Mapping。

<code>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"
        }
      }
    }
  }
}
/<code>

刪除索引

刪除 mydlq-user 索引。

<code>DELETE /mydlq-user
/<code>

2、Java 代碼示例

<code>

@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);
        }
    }

}
/<code>

五、文檔操作示例

1、Restful 操作示例

增加文檔信息

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

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

獲取文檔信息

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

<code>GET /mydlq-user/doc/1
/<code>

更新文檔信息

更新之前創建的 id=1 的文檔信息。

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

刪除文檔信息

刪除之前創建的 id=1 的文檔信息。

<code>DELETE /mydlq-user/doc/1
/<code>

2、Java 代碼示例

<code>

@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);
        }
    }

}
/<code>

六、插入初始化數據

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

1、單條插入

POST mydlq-user/_doc

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

2、批量插入

POST _bulk

<code>{"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"}
/<code>

3、查詢數據

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

<code>GET mydlq-user/_search
/<code>

執行後得到下面記錄:

<code>{
  "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"
        }
      }
    ]
  }
}
/<code>

由於篇幅,請看下半部分


分享到:


相關文章: