zoukankan      html  css  js  c++  java
  • ElasticSearch6.5.0 【Java客户端之REST Client】

    说明

    High Level Client 是基于 Low Level Client 的。官方文档如下:

    * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html
    * https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

     依赖

    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>transport</artifactId>
        <version>6.5.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.11.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-to-slf4j</artifactId>
        <version>2.11.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.25</version>
    </dependency>
    
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>6.5.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>6.5.0</version>
    </dependency>

     连接

    import org.apache.http.HttpHost;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestHighLevelClient;
    
    /**
     * Java高级REST客户机在Java低级REST客户机之上工作。它的主要目标是公开特定于API的方法,这些方法接受请求对象作为参数并返回响应对象
     * 可以同步或异步调用每个API。同步方法返回一个响应对象,而异步方法(其名称以async后缀结尾)需要一个侦听器参数
     * 一旦接收到响应或错误,侦听器参数(在低层客户机管理的线程池上)将被通知。
     * Java高级REST客户机依赖于Elasticsearch核心项目。它接受与TransportClient相同的请求参数,并返回相同的响应对象。
     * Java高级REST客户机需要Java 1.8
     * 客户机版本与开发客户机的Elasticsearch版本相同
     * 6.0客户端能够与任意6.X节点通信,6.1客户端能够与6.1、6.2和任意6.X通信
     */
    public class RestClientFactory {
    
        private RestClientFactory(){}
    
        private static class Inner{
            private static final RestClientFactory instance = new RestClientFactory();
        }
    
        public static RestClientFactory getInstance(){
            return Inner.instance;
        }
    
        public RestHighLevelClient getClient(){
            RestHighLevelClient client = new RestHighLevelClient(
                    RestClient.builder(
                            //new HttpHost("localhost", 9201, "http"),
                            new HttpHost("localhost", 9200, "http")
                    )
            );
            return client;
        }
    
    }

    【JavaAPI与HTTP请求】

    1. Index

    HTTP请求

    查看所有数据
    GET twitter/t_doc/_search

    ---

    # 添加数据[index]/[type]/[id]
    PUT twitter/t_doc/10
    {
        "user" : "kimchy",
        "post_date" : "2018-12-24T11:32:00",
        "message" : "trying out Elasticsearch"
    }

    结果:

    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "10",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 0,
      "_primary_term" : 1
    }

    Java 

        public static RestHighLevelClient index() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            Map<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("user", "kimchy");
            jsonMap.put("postDate", new Date());
            jsonMap.put("message", "trying out Elasticsearch");
    
            IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "1")
                    .source(jsonMap);
            IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(response.status().name());
            return client;
        }

    结果:

    CREATED

    还有两种形式添加数据

        /**
         * 方式二:XContentBuilder
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient index2() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            XContentBuilder builder = jsonBuilder();
            builder.startObject();
            {
                builder.field("user", "kimchy");
                builder.timeField("postDate", new Date());
                builder.field("message", "trying out Elasticsearch");
            }
            builder.endObject();
            IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "2")
                    .source(builder);
            IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
            System.out.println(response.status().name());
            return client;
        }
    
        /**
         * 方式三:Object key-pairs对象键
         * 同步方法
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient index3() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "3")
                    .source("user", "kimchy",
                            "postDate", new Date(),
                            "message", "trying out Elasticsearch");
            IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);    // 同步方式
            System.out.println(response.status().name());
            return client;
        }

    还能异步创建&添加数据

        /**
         * 异步方法
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient index4() throws IOException, InterruptedException {
            ActionListener listener = new ActionListener<IndexResponse>() {
                @Override
                public void onResponse(IndexResponse indexResponse) {
                    System.out.println("Async:" + indexResponse.status().name());
                    if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
                        // Todo
                    } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
                        // Todo
                    }
                    // 处理成功分片小于总分片的情况
                    ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
                    if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
                        // Todo
                    }
                }
    
                @Override
                public void onFailure(Exception e) {
                    System.out.println("AsyncFailure:" + e.getMessage());
                    e.printStackTrace();
                }
            };
    
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            IndexRequest indexRequest = new IndexRequest("twitter", "t_doc", "4")
                    .source("user", "kimchy",
                            "postDate", new Date(),
                            "message", "trying out Elasticsearch")
                    .routing("my_route");   // 指定路由
    
            client.indexAsync(indexRequest, RequestOptions.DEFAULT, listener);  // 异步方式
            Thread.sleep(2000);
            return client;
        }

    结果:

    Async:CREATED

     2. Get

     HTTP请求

    # 获取数据
    GET twitter/t_doc/1
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "1",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "postDate" : "2018-12-24T03:42:22.787Z",
        "message" : "trying out Elasticsearch",
        "user" : "kimchy"
      }
    }

    可以指定routing

    GET twitter/t_doc/4?routing=my_route
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "4",
      "_version" : 1,
      "_routing" : "my_route",
      "found" : true,
      "_source" : {
        "user" : "kimchy",
        "postDate" : "2018-12-24T06:08:45.178Z",
        "message" : "trying out Elasticsearch"
      }
    }

    可以只要数据信息_source

    GET twitter/t_doc/4/_source?routing=my_route
    结果:
    {
      "user" : "kimchy",
      "postDate" : "2018-12-24T06:08:45.178Z",
      "message" : "trying out Elasticsearch"
    }

    Java

        public static RestHighLevelClient getOne() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetRequest request = new GetRequest("twitter", "t_doc", "4").routing("my_route");   // 指定routing的数据,查询也要指定
            try {
                GetResponse response = client.get(request, RequestOptions.DEFAULT);
                System.out.println(response.getSourceAsString());
            } catch (ElasticsearchException e) {
                // 处理找不到index的异常
                if(e.status() == RestStatus.NOT_FOUND){
                    // TODO
                }
            }
            return client;
        }

    结果:

    {"user":"kimchy","postDate":"2018-12-24T06:08:45.178Z","message":"trying out Elasticsearch"}

     异步获取,并且指定包含/排除的字段

        /**
         * 查询-额外参数
         * 异步获取
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient getOneOp() throws IOException, InterruptedException {
            ActionListener<GetResponse> listener = new ActionListener<GetResponse>() {
                @Override
                public void onResponse(GetResponse documentFields) {
                    System.out.println(documentFields.getSourceAsString());
                }
    
                @Override
                public void onFailure(Exception e) {
                    System.out.println("Error:" + e.getMessage());
                    e.printStackTrace();
                }
            };
    
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetRequest request = new GetRequest("twitter", "t_doc", "1");
            String[] includes = new String[]{"message", "*Date"};   // 包含的字段
            String[] excludes = Strings.EMPTY_ARRAY;                 // 排除的字段
            FetchSourceContext fetchSourceContext =
                    new FetchSourceContext(true, includes, excludes);
            request.fetchSourceContext(fetchSourceContext);
            client.getAsync(request, RequestOptions.DEFAULT, listener);
            Thread.sleep(2000);
            return client;
        }

    结果:

    {"postDate":"2018-12-24T03:42:22.787Z","message":"trying out Elasticsearch"}

    到这里也应该知道,Rest API 对每个操作提供了同步/异步的方法。

    3. Exist API

    Java

        /**
         * 检查是否存在
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient exist() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetRequest request = new GetRequest("twitter", "t_doc", "1");
            request.storedFields("_none_"); // 禁用获取存储字段
            request.fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE); // 禁用抓取_source
            boolean exists = client.exists(request, RequestOptions.DEFAULT);
            System.out.println(exists);
            return client;
        }

    结果:

    true

    4.  Delete API

    HTTP请求

    DELETE twitter/t_doc/1
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "1",
      "_version" : 2,
      "result" : "deleted",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 1
    }

    Java

        /**
         * 删除也可以异步、也可以捕获异常,成功删除的分片数量,版本冲突
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient deleteOne() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            DeleteRequest request = new DeleteRequest("twitter", "t_doc", "1");
            DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
            System.out.println(response.status().name());
            // 处理找不到的情况
            if (response.getResult() == DocWriteResponse.Result.NOT_FOUND) {
                // TODO
            }
            return client;
        }

    结果:

    NOT_FOUND

    5. Delete By Query API

    我这里有4条测试数据

    {"user":"Tom","flag":"1"}
    {"user":"foo","flag":"2"}
    {"user":"bar","flag":"2"}
    {"user":"baz","flag":"2"}

    HTTP 请求

    # 删除flag=2的数据
    POST twitter/_delete_by_query?conflicts=proceed
    {
      "query": { 
        "match": {
          "flag": "2"
        }
      }
    }
    结果:
    {
      "took" : 183,
      "timed_out" : false,
      "total" : 3,
      "deleted" : 3,
      "batches" : 1,
      "version_conflicts" : 0,
      "noops" : 0,
      "retries" : {
        "bulk" : 0,
        "search" : 0
      },
      "throttled_millis" : 0,
      "requests_per_second" : -1.0,
      "throttled_until_millis" : 0,
      "failures" : [ ]
    }

     --扩展

    # 清空索引全部数据
    POST /[索引名]/_delete_by_query
    {
      "query": { 
        "match_all": {}
      }
    }

    Java

        /**
         * 根据查询条件删除
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient deleteByQuery() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            DeleteByQueryRequest request = new DeleteByQueryRequest("twitter");
            request.setConflicts("proceed");    // 发生冲突即略过
            request.setQuery(QueryBuilders.matchQuery("flag","2"));
            BulkByScrollResponse bulkResponse = client.deleteByQuery(request, RequestOptions.DEFAULT);
            TimeValue timeTaken = bulkResponse.getTook();
            boolean timedOut = bulkResponse.isTimedOut();
            long totalDocs = bulkResponse.getTotal();
            long updatedDocs = bulkResponse.getUpdated();
            long deletedDocs = bulkResponse.getDeleted();
            long batches = bulkResponse.getBatches();
            long noops = bulkResponse.getNoops();
            long versionConflicts = bulkResponse.getVersionConflicts();
            System.out.println("花费时间:" + timeTaken + ",是否超时:" + timedOut + ",总文档数:" + totalDocs + ",更新数:" +
                    updatedDocs + ",删除数:" + deletedDocs + ",批量次数:" + batches + ",跳过数:" + noops + ",冲突数:" + versionConflicts);
            List<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();  // 搜索期间的故障
            searchFailures.forEach(e -> {
                System.err.println("Cause:" + e.getReason().getMessage() + "Index:" + e.getIndex() + ",NodeId:" + e.getNodeId() + ",ShardId:" + e.getShardId());
            });
            List<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();   // 批量索引期间的故障
            bulkFailures.forEach(e -> {
                System.err.println("Cause:" + e.getCause().getMessage() + "Index:" + e.getIndex() + ",Type:" + e.getType() + ",Id:" + e.getId());
            });
            return client;
        }

    结果:

    花费时间:97ms,是否超时:false,总文档数:3,更新数:0,删除数:3,批量次数:1,跳过数:0,冲突数:0

    6. Update API

    我有一条测试数据

    {"user":"Tom","flag":"1"}

    HTTP 请求

    # 通过脚本更新
    POST twitter/t_doc/1/_update
    {
        "script" : {
            "source": "ctx._source.msg = params.msg",
            "lang": "painless",
            "params" : {
                "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない"
            }
        }
    }
    # 通过文档更新
    POST twitter/t_doc/1/_update
    {
        "doc" : {
            "user" : "new_name"
        }
    }

    upserts

    # upserts(如果文档不存在,则把upsert里面的内容作为文档插入)
    POST twitter/t_doc/2/_update
    {
        "script" : {
            "source": "ctx._source.counter += params.count",
            "lang": "painless",
            "params" : {
                "count" : 4
            }
        },
        "upsert" : {
            "counter" : 1
        }
    }
    结果【创建新文档】:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "2",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 1,
      "_primary_term" : 1
    }

    如果你再执行的话就是更新了

    结果【更新文档】:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "2",
      "_version" : 2,
      "result" : "updated",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 2,
      "_primary_term" : 1
    }
    查询:
    GET twitter/t_doc/2
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "2",
      "_version" : 2,
      "found" : true,
      "_source" : {
        "counter" : 5
      }
    }

    不用脚本而用文档更新

    # 如果文档不存在,则将doc内容作为新文档插入(因为"doc_as_upsert" : true)
    POST twitter/t_doc/3/_update
    {
        "doc" : {
            "name" : "new_name"
        },
        "doc_as_upsert" : true
    }
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "3",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 5,
      "_primary_term" : 1
    }
    查询:
    GET twitter/t_doc/3
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "3",
      "_version" : 1,
      "found" : true,
      "_source" : {
        "name" : "new_name"
      }
    }

    Java

        /**
         * 通过脚本更新,可以添加字段
         * @return
         */
        public static RestHighLevelClient updateOne() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            UpdateRequest request = new UpdateRequest("twitter", "t_doc", "1");
    
            Map<String, Object> parameters = singletonMap("msg", "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない");
            Script inline = new Script(ScriptType.INLINE, "painless",
                    "ctx._source.msg = params.msg", parameters);
            request.script(inline);
    
            UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
            System.out.println(update.status().name());
            return client;
        }

    输出:OK

    GET twitter/t_doc/1
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "1",
      "_version" : 4,
      "found" : true,
      "_source" : {
        "user" : "Tom",
        "flag" : "1",
        "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない"
      }
    }

    还可以通过XContentBuilder

        /**
         * 通过XContentBuilder更新
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient updateOne2() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
    
            XContentBuilder builder = jsonBuilder()
                    .startObject()
                        .startObject("animal")
                            .field("cat", "阿猫")
                            .field("dog", "阿狗")
                        .endObject()
                    .endObject();
            UpdateRequest request = new UpdateRequest("twitter", "t_doc", "1").doc(builder);
    
            UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
            System.out.println(update.status().name());
            return client;
        }

    输出:OK

    GET twitter/t_doc/1
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "1",
      "_version" : 5,
      "found" : true,
      "_source" : {
        "user" : "Tom",
        "flag" : "1",
        "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない",
        "animal" : {
          "cat" : "阿猫",
          "dog" : "阿狗"
        }
      }
    }

    还可以通过Map

        /**
         * 通过jsonMap更新
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient updateOne3() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
    
            Map<String, Object> jsonMap = new HashMap<>();
            jsonMap.put("updateUser", "Jack Ma");
            UpdateRequest request = new UpdateRequest("posts", "doc", "1").doc(jsonMap);
    
            UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
            System.out.println(update.status().name());
            return client;
        }

    输出:OK

    GET twitter/t_doc/1
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "1",
      "_version" : 6,
      "found" : true,
      "_source" : {
        "user" : "Tom",
        "flag" : "1",
        "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない",
        "animal" : {
          "cat" : "阿猫",
          "dog" : "阿狗"
        },
        "updateUser" : "Jack Ma"
      }
    }

    还可以通过 key-pairs

        /**
         * 通过 key-pairs 更新
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient updateOne4() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
    
            UpdateRequest request = new UpdateRequest("twitter", "t_doc", "1")
                    .doc("favorite","二狗","hate","no Money");
    
            UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
            System.out.println(update.status().name());
            return client;
        }

    输出:OK

    GET twitter/t_doc/1
    结果:
    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "1",
      "_version" : 7,
      "found" : true,
      "_source" : {
        "user" : "Tom",
        "flag" : "1",
        "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない",
        "animal" : {
          "cat" : "阿猫",
          "dog" : "阿狗"
        },
        "updateUser" : "Jack Ma",
        "hate" : "no Money",
        "favorite" : "二狗"
      }
    }

    upserts

        /**
         * 存在即更新【输出:OK】
         * OK
         * {"C":"Carambola","A":"Apple","B":"Banana"}
         * 不存在则创建【输出:CREATED】
         * CREATED
         * {"C":"Carambola"}
         * 开启scriptedUpsert【在文档不存在情况下输出:CREATED】
         * {"A" : "Apple","B" : "Banana","C" : "Carambola"}
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient upserts() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            UpdateRequest request = new UpdateRequest("twitter", "t_doc", "7")
                    .script(new Script(ScriptType.INLINE,"painless",
                            "ctx._source.A='Apple';ctx._source.B='Banana'",Collections.EMPTY_MAP))
                    // 如果文档不存在,使用upsert方法定义一些内容,这些内容将作为新文档插入
                    .upsert(jsonBuilder()
                        .startObject()
                        .field("C","Carambola")
                        .endObject());
            request.timeout(TimeValue.timeValueSeconds(2)); // 2秒超时
            //request.scriptedUpsert(true);   // 无论文档是否存在,脚本都必须运行
            UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
            System.out.println(update.status().name());
            return client;
        }

    --

        /**
         * 存在即更新
         * OK
         * {"C" : "Carambola","A" : "Apple","B" : "Banana","D" : "Dew"}
         * 不存在则创建
         * CREATED
         * {"C" : "Carambola"}
         * 开启docAsUpsert【在文档不存在情况下输出:CREATED】
         * {"A" : "Apple","B" : "Banana","D" : "Dew"}
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient upserts2() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            UpdateRequest request = new UpdateRequest("twitter", "t_doc", "8")
                    .doc(jsonBuilder()
                        .startObject()
                        .field("A","Apple")
                        .field("B","Banana")
                        .field("D","Dew")
                        .endObject())
                    // 如果指定docAsUpsert(true),会忽略upsert方法
                    .upsert(jsonBuilder()
                        .startObject()
                        .field("C","Carambola")
                        .endObject());
            //request.docAsUpsert(true);  // 如果部分文档尚不存在,则必须将doc用作upsert文档
            request.timeout(TimeValue.timeValueSeconds(2)); // 2秒超时
            try {
                UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
                System.out.println(update.status().name());
            } catch (ElasticsearchException e) {
                if (e.status() == RestStatus.NOT_FOUND) {
                    // TODO
                }
            }
    
            return client;
        }

    7. Update By Query API

    HTTP请求

    # 不更改源数据的前提下更新文档
    POST twitter/_update_by_query?conflicts=proceed
    结果:
    {
      "took" : 186,
      "timed_out" : false,
      "total" : 9,
      "updated" : 9,
      "deleted" : 0,
      "batches" : 1,
      "version_conflicts" : 0,
      "noops" : 0,
      "retries" : {
        "bulk" : 0,
        "search" : 0
      },
      "throttled_millis" : 0,
      "requests_per_second" : -1.0,
      "throttled_until_millis" : 0,
      "failures" : [ ]
    }

    --

    我们有数据:

    {
      "_index" : "twitter",
      "_type" : "t_doc",
      "_id" : "9",
      "_version" : 3,
      "found" : true,
      "_source" : {
        "flag" : "2",
        "user" : "foo"
      }
    }
    # 通过脚本更新
    POST twitter/_update_by_query?conflicts=proceed
    {
      "script": {
        "source": "ctx._source.flag++",
        "lang": "painless"
      },
      "query": {
        "term": {
          "user": "foo"
        }
      }
    }
    结果:
    {
      "took" : 102,
      "timed_out" : false,
      "total" : 1,
      "updated" : 1,
      "deleted" : 0,
      "batches" : 1,
      "version_conflicts" : 0,
      "noops" : 0,
      "retries" : {
        "bulk" : 0,
        "search" : 0
      },
      "throttled_millis" : 0,
      "requests_per_second" : -1.0,
      "throttled_until_millis" : 0,
      "failures" : [ ]
    }

    Java

        /**
         * 根据查询条件更新
         * @return
         */
        public static RestHighLevelClient updateByQuery() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            UpdateByQueryRequest request = new UpdateByQueryRequest("twitter");
            request.setConflicts("proceed");
            request.setQuery(QueryBuilders.matchAllQuery())
                    .setBatchSize(50)   // 批处理大小
                    .setSize(100)      // 限制处理文档的数量
                    .setScript(new Script(
                    ScriptType.INLINE, "painless",
                    "if (ctx._source.flag == '2') {ctx._source.extMsg = '小林さんちのメイドラゴン';}", // 增加一个字段extMsg
                    Collections.emptyMap()));
            BulkByScrollResponse bulkResponse = client.updateByQuery(request, RequestOptions.DEFAULT);
            TimeValue timeTaken = bulkResponse.getTook();
            boolean timedOut = bulkResponse.isTimedOut();
            long totalDocs = bulkResponse.getTotal();
            long updatedDocs = bulkResponse.getUpdated();
            long deletedDocs = bulkResponse.getDeleted();
            long batches = bulkResponse.getBatches();
            long noops = bulkResponse.getNoops();
            long versionConflicts = bulkResponse.getVersionConflicts();
            System.out.println("花费时间:" + timeTaken + ",是否超时:" + timedOut + ",总文档数:" + totalDocs + ",更新数:" +
                    updatedDocs + ",删除数:" + deletedDocs + ",批量次数:" + batches + ",跳过数:" + noops + ",冲突数:" + versionConflicts);
            List<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();  // 搜索期间的故障
            searchFailures.forEach(e -> {
                System.err.println("Cause:" + e.getReason().getMessage() + "Index:" + e.getIndex() + ",NodeId:" + e.getNodeId() + ",ShardId:" + e.getShardId());
            });
            List<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();   // 批量索引期间的故障
            bulkFailures.forEach(e -> {
                System.err.println("Cause:" + e.getCause().getMessage() + "Index:" + e.getIndex() + ",Type:" + e.getType() + ",Id:" + e.getId());
            });
            return client;
        }

    结果:【之所以更新了全部文档,是因为matchAllQuery】

    花费时间:218ms,是否超时:false,总文档数:9,更新数:9,删除数:0,批量次数:1,跳过数:0,冲突数:0
    # 查询flag=2的文档
    GET /twitter/_search
    {
      "query": { 
        "match": {
          "flag": "2"
        }
      }
    }
    结果:
    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 2,
        "max_score" : 0.6931472,
        "hits" : [
          {
            "_index" : "twitter",
            "_type" : "t_doc",
            "_id" : "10",
            "_score" : 0.6931472,
            "_source" : {
              "flag" : "2",
              "extMsg" : "小林さんちのメイドラゴン",
              "user" : "bar"
            }
          },
          {
            "_index" : "twitter",
            "_type" : "t_doc",
            "_id" : "11",
            "_score" : 0.2876821,
            "_source" : {
              "flag" : "2",
              "extMsg" : "小林さんちのメイドラゴン",
              "user" : "baz"
            }
          }
        ]
      }
    }

    8. Bulk API

    HTTP请求

    # 批量处理(允许Add,Delete,Update操作)如果包含routing要加上
    POST _bulk
    { "delete" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "9" } }
    { "update" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "4","routing":"my_route" } }
    { "doc" : {"user":"new_user"} }
    { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "21" }}
    { "user":"Tom","flag":"1" }
    { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "22" }}
    { "user":"Tony","flag":"1" }
    { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "23" }}
    { "user":"Mary","flag":"1" }
    { "index" : { "_index" : "twitter", "_type" : "t_doc", "_id" : "24" }}
    { "user":"Jerry","flag":"1" }

    Java

        /**
         * 批量添加
         * @return
         */
        public static RestHighLevelClient bulkAdd() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            BulkRequest request = new BulkRequest();
            request.add(new IndexRequest("twitter", "t_doc", "25")
                    .source(XContentType.JSON,"user", "Tom","flag","1"));
            request.add(new IndexRequest("twitter", "t_doc", "26")
                    .source(XContentType.JSON,"user", "foo","flag","2"));
            request.add(new IndexRequest("twitter", "t_doc", "27")
                    .source(XContentType.JSON,"user", "bar","flag","2"));
            request.add(new IndexRequest("twitter", "t_doc", "28")
                    .source(XContentType.JSON,"user", "baz","flag","2"));
            BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println("Status:" + bulk.status().name() + ",hasFailures:" + bulk.hasFailures());
            // 下面是multiGet
            MultiGetRequest multiGetRequest = new MultiGetRequest()
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "25"))
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "26"))
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "27"))
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "28"));
            MultiGetResponse response = client.mget(multiGetRequest, RequestOptions.DEFAULT);
            MultiGetItemResponse[] itemResponses = response.getResponses();
            for(MultiGetItemResponse r : itemResponses){
                System.out.println(r.getResponse().getSourceAsString());
            }
            return client;
        }

    输出:

    Status:OK,hasFailures:false
    {"user":"Tom","flag":"1"}
    {"user":"foo","flag":"2"}
    {"user":"bar","flag":"2"}
    {"user":"baz","flag":"2"}

    也可以批量更新

        /**
         * 批量更新
         * @return
         */
        public static RestHighLevelClient bulkUpdate() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            BulkRequest request = new BulkRequest();
            // 更新
            request.add(new UpdateRequest("twitter", "t_doc", "27")
                    .doc(XContentType.JSON,"field", "foo","color", "red","size", "100"));
            // 添加
            request.add(new IndexRequest("twitter", "t_doc", "29")
                    .source(XContentType.JSON,"field", "bar","color", "blue","size", "200"));
            // 删除
            request.add(new DeleteRequest("twitter", "t_doc", "28"));
            BulkResponse bulk = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println("Status:" + bulk.status().name() + ",hasFailures:" + bulk.hasFailures());
    
            // 针对不同类型进行处理
            for (BulkItemResponse bulkItemResponse : bulk) {
                DocWriteResponse itemResponse = bulkItemResponse.getResponse();
    
                if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.INDEX
                        || bulkItemResponse.getOpType() == DocWriteRequest.OpType.CREATE) {
                    IndexResponse indexResponse = (IndexResponse) itemResponse;
                    System.out.println(indexResponse.status().name());
                } else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.UPDATE) {
                    UpdateResponse updateResponse = (UpdateResponse) itemResponse;
                    System.out.println(updateResponse.status().name());
                } else if (bulkItemResponse.getOpType() == DocWriteRequest.OpType.DELETE) {
                    DeleteResponse deleteResponse = (DeleteResponse) itemResponse;
                    System.out.println(deleteResponse.status().name());
                }
            }
    
            String[] includes = Strings.EMPTY_ARRAY;
            String[] excludes = new String[] {"flag"};
            // 包含/排除的字段
            FetchSourceContext fetchSourceContext =
                    new FetchSourceContext(true, includes, excludes);
            MultiGetRequest multiGetRequest = new MultiGetRequest()
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "29").fetchSourceContext(fetchSourceContext))
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "28").fetchSourceContext(fetchSourceContext))
                    .add(new MultiGetRequest.Item("twitter", "t_doc", "27").fetchSourceContext(fetchSourceContext));
    
            MultiGetResponse response = client.mget(multiGetRequest, RequestOptions.DEFAULT);
            MultiGetItemResponse[] itemResponses = response.getResponses();
            for(MultiGetItemResponse r : itemResponses){
                System.out.println(r.getResponse().getSourceAsString());
            }
            return client;
        }

    输出:

    Status:OK,hasFailures:false
    OK
    CREATED
    OK
    {"field":"bar","color":"blue","size":"200"}
    null
    {"field":"foo","color":"red","size":"100","user":"bar"}

    bulkProcessor就比较厉害了

        /**
         * BulkProcessor通过提供一个实用程序类来简化Bulk API的使用,它允许索引/更新/删除操作在添加到处理器时透明地执行。
         * 为了执行请求,BulkProcessor需要以下组件:
         * RestHighLevelClient
         * 此客户端用于执行BulkRequest和检索BulkResponse
         * BulkProcessor.Listener
         * 在每个BulkRequest执行之前和之后,或者在BulkRequest失败时,都会调用这个侦听器
         * BulkProcessor.builder方法可用于构建新的BulkProcessor:
         * @return
         */
        public static RestHighLevelClient bulkProcessor() throws InterruptedException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
    
            BulkProcessor.Listener listener = new BulkProcessor.Listener() {
                @Override
                public void beforeBulk(long executionId, BulkRequest request) {
                    int numberOfActions = request.numberOfActions();
                    System.out.println("请求数量:" + numberOfActions);
                }
    
                @Override
                public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
                    if (response.hasFailures()) {
                        System.out.println("Bulk Failures,ID:" + executionId + ",Status:" + response.status().name());
                        for (BulkItemResponse bulkItemResponse : response) {
                            if (bulkItemResponse.isFailed()) {
                                BulkItemResponse.Failure failure = bulkItemResponse.getFailure();
                                System.err.println(failure.getCause().getMessage());
                            }
                        }
                    } else {
                        System.out.println("Bulk "+ executionId +" Complete in" + response.getTook().getMillis() + "s");
                    }
                }
    
                @Override
                public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
                    System.out.println("Failed to execute bulk:" + failure);
                }
            };
    
            BiConsumer<BulkRequest, ActionListener<BulkResponse>> bulkConsumer =
                    (request, bulkListener) -> client.bulkAsync(request, RequestOptions.DEFAULT, bulkListener);
            BulkProcessor bulkProcessor = BulkProcessor.builder(bulkConsumer, listener)
                    .setBulkActions(500)    // 请求(Index,Update,Delete)的数量达到500,就刷新一次bulk request【默认1000】
    //                .setBulkSize(new ByteSizeValue(1L, ByteSizeUnit.MB))    // 累计请求所占的空间达到1M,就刷新一次bulk request【默认5M】
                    .setConcurrentRequests(0)   // 设置允许执行的并发请求数量(默认为1,使用0只允许执行单个请求)
    //                .setFlushInterval(TimeValue.timeValueSeconds(10L))  // 每隔一段时间刷新一次【默认未设置】
                    .setBackoffPolicy(BackoffPolicy
                            .constantBackoff(TimeValue.timeValueSeconds(1L), 3))// 设置一个初始等待1秒并重试3次的Backoff策略
                    .build();
            for(int i = 1; i <= 2000; i++){
                bulkProcessor.add(new IndexRequest("books", "java", ""+i)
                        .source(XContentType.JSON,"title","title_"+i,"user","user_"+i));
            }
    
            bulkProcessor.flush();
            Thread.sleep(2000);
            bulkProcessor.close();
            return client;
        }

    输出:【警告可忽略,因为默认分片数量在7.0.0版本会改变,这里提醒一下用户。也就是说,最好先去建立索引(设置好参数),再来添加数据】

    请求数量:500
    十二月 25, 2018 11:24:06 上午 org.elasticsearch.client.RestClient logResponse
    警告: request [POST http://localhost:9200/_bulk?timeout=1m] returned 1 warnings: [299 Elasticsearch-6.5.0-816e6f6 "the default number of shards will change from [5] to [1] in 7.0.0; if you wish to continue using the default of [5] shards, you must manage this on the create index request or with an index template" "Tue, 25 Dec 2018 03:24:04 GMT"]
    Bulk 1 Complete in2044s
    请求数量:500
    Bulk 2 Complete in333s
    请求数量:500
    Bulk 3 Complete in235s
    请求数量:500
    Bulk 4 Complete in244s

     查看:

    GET books/_search
    结果:
    {
      "took" : 18,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 2000,
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "books",
            "_type" : "java",
            "_id" : "14",
            "_score" : 1.0,
            "_source" : {
              "title" : "title_14",
              "user" : "user_14"
            }
          },
          ....
        ]
      }
    }

    9. Multi-Get API

    HTTP 请求 

    GET /_mget
    {
        "docs" : [
            {
                "_index" : "books",
                "_type" : "java",
                "_id" : "1"
            },
            {
                "_index" : "twitter",
                "_type" : "t_doc",
                "_id" : "1"
            }
        ]
    }
    结果:
    {
      "docs" : [
        {
          "_index" : "books",
          "_type" : "java",
          "_id" : "1",
          "_version" : 1,
          "found" : true,
          "_source" : {
            "title" : "title_1",
            "user" : "user_1"
          }
        },
        {
          "_index" : "twitter",
          "_type" : "t_doc",
          "_id" : "1",
          "_version" : 13,
          "found" : true,
          "_source" : {
            "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない",
            "flag" : "1",
            "user" : "new_name"
          }
        }
      ]
    }
    GET /twitter/t_doc/_mget
    {
        "docs" : [
            {
                "_id" : "1"
            },
            {
                "_id" : "2"
            }
        ]
    }
    GET /twitter/t_doc/_mget
    {
        "ids" : ["1", "2"]
    }
    # 两个方式效果一样
    结果:
    {
      "docs" : [
        {
          "_index" : "twitter",
          "_type" : "t_doc",
          "_id" : "1",
          "_version" : 13,
          "found" : true,
          "_source" : {
            "msg" : "達に携帯で連絡取ろうと思ったら 電池が切れてて動かない",
            "flag" : "1",
            "user" : "new_name"
          }
        },
        {
          "_index" : "twitter",
          "_type" : "t_doc",
          "_id" : "2",
          "_version" : 5,
          "found" : true,
          "_source" : {
            "counter" : 5,
            "user" : "new_user"
          }
        }
      ]
    }

     Java代码在bulk里面有体现,这里就不赘述了。

    10. Reindex API

     Reindex不尝试设置目标索引。它不复制源索引的设置。您应该在运行_reindex操作之前设置目标索引,包括设置映射、碎片计数、副本等。

    # 复制源索引twitter到目标索引new_twitter
    POST _reindex
    {
      "source": {
        "index": "twitter"
      },
      "dest": {
        "index": "new_twitter"
      }
    }
    结果:
    {
      "took" : 1626,
      "timed_out" : false,
      "total" : 16,
      "updated" : 0,
      "created" : 16,
      "deleted" : 0,
      "batches" : 1,
      "version_conflicts" : 0,
      "noops" : 0,
      "retries" : {
        "bulk" : 0,
        "search" : 0
      },
      "throttled_millis" : 0,
      "requests_per_second" : -1.0,
      "throttled_until_millis" : 0,
      "failures" : [ ]
    }
    # 查询
    GET /new_twitter/_search
    结果:
    {
      "took" : 9,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 16,
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "new_twitter",
            "_type" : "t_doc",
            "_id" : "22",
            "_score" : 1.0,
            "_source" : {
              "user" : "Tony",
              "flag" : "1"
            }
          },
          ...
        ]
      }
    }

    为了避免出现冲突导致进程停止,指定:conflicts:proceed

    POST _reindex
    {
      "conflicts": "proceed",
      "source": {
        "index": "twitter"
      },
      "dest": {
        "index": "new_twitter",
        "op_type": "create"
      }
    }

    还可以查询出指定的内容,然后送进目标索引

    POST _reindex
    {
      "source": {
        "index": "twitter",
        "type": "t_doc",
        "query": {
          "term": {
            "user": "kimchy"
          }
        }
      },
      "dest": {
        "index": "new_twitter"
      }
    }

    和可以合并多个索引到目标索引

    #合并两个索引,跳过冲突【conflicts】,只转移10000条数据【size】
    POST _reindex
    {
      "conflicts": "proceed",
      "size": 10000,
      "source": {
        "index": ["twitter", "new_twitter"],
        "type": ["t_doc", "post"]
      },
      "dest": {
        "index": "all_together",
        "type": "all_doc"
      }
    }

    还可以使用脚本、从远程服务器reindex、修改目标字段名称,请参考官方文档

    Java

        /**
         * reIndex可用于将文档从一个或多个索引复制到目标索引
         * DocWriteRequest.OpType.CREATE    跳过已有的文档
         * DocWriteRequest.OpType.INDEX     已有相同id的会被覆盖
         * @return
         */
        public static RestHighLevelClient reIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            ReindexRequest reindexRequest = new ReindexRequest()
                    .setSourceIndices("twitter","new_twitter")
                    .setDestIndex("all_together")
                    .setDestOpType(DocWriteRequest.OpType.INDEX.getLowercase())
                    .setDestDocType("all_doc")
    //                .setSize(10)    // copy的文档数
    //                .setScript(new Script(ScriptType.INLINE, "painless",
    //                        "if (ctx._source.user == 'kimchy') {ctx._source.likes++;}",
    //                        Collections.emptyMap()))  // 脚本
                    .setSourceBatchSize(500);   // 默认批量为1000,你可以自己设置批次获取的数量
            reindexRequest.setConflicts("proceed"); // 默认情况下,版本冲突会中止_reindex进程(abort)
            BulkByScrollResponse bulkResponse = client.reindex(reindexRequest, RequestOptions.DEFAULT);
            TimeValue timeTaken = bulkResponse.getTook();
            boolean timedOut = bulkResponse.isTimedOut();
            long totalDocs = bulkResponse.getTotal();
            long updatedDocs = bulkResponse.getUpdated();
            long createdDocs = bulkResponse.getCreated();
            long deletedDocs = bulkResponse.getDeleted();
            long batches = bulkResponse.getBatches();
            long noops = bulkResponse.getNoops();   // 跳过的文档数
            long versionConflicts = bulkResponse.getVersionConflicts(); // 版本冲突的数量
            long bulkRetries = bulkResponse.getBulkRetries();   // bulk重试次数
            long searchRetries = bulkResponse.getSearchRetries();   // 搜索重试次数
            System.out.println("花费时间:" + timeTaken + ",是否超时:" + timedOut + ",总文档数:" + totalDocs + ",更新数:" +
                    updatedDocs + ",创建数:" + createdDocs + ",删除数:" + deletedDocs + ",批量次数:" + batches + ",跳过数:" +
                    noops + ",冲突数:" + versionConflicts + ",bulk重试次数:" + bulkRetries + ",搜索重试次数:" + searchRetries);
            List<ScrollableHitSource.SearchFailure> searchFailures = bulkResponse.getSearchFailures();  // 搜索期间的故障
            searchFailures.forEach(e -> {
                System.err.println("Cause:" + e.getReason().getMessage() + "Index:" + e.getIndex() + ",NodeId:" + e.getNodeId() + ",ShardId:" + e.getShardId());
            });
            List<BulkItemResponse.Failure> bulkFailures = bulkResponse.getBulkFailures();   // 批量索引期间的故障
            bulkFailures.forEach(e -> {
                System.err.println("Cause:" + e.getCause().getMessage() + "Index:" + e.getIndex() + ",Type:" + e.getType() + ",Id:" + e.getId());
            });
            return client;
        }

    因为这两个索引内容一样,所以会出现 更新数:16,创建数:16

    花费时间:1.6s,是否超时:false,总文档数:32,更新数:16,创建数:16,删除数:0,批量次数:1,跳过数:0,冲突数:0,bulk重试次数:0,搜索重试次数:0

    查看目标索引(总文档数16

    GET /all_together/_search
    结果:
    {
      "took" : 4,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 16,
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "all_together",
            "_type" : "all_doc",
            "_id" : "22",
            "_score" : 1.0,
            "_source" : {
              "user" : "Tony",
              "flag" : "1"
            }
          },
          ...
        ]
      }
    }

    --

    11. Query

    HTTP请求

    RequestBodySearch 示例

    # sort--mode:min、max、sum、avg、median
    # sort--order:asc、desc
    # 过滤_source:如果要禁用,"_source": false
    # Doc格式化:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-docvalue-fields.html
    # 高亮参数:写在外面是全局的,写在field里面是局部的
    GET /_search
    {
        "query" : {
            "term" : { "user" : "Tony" }
        },
        "_source": [ "obj1.*", "obj2.*" ],
        "from" : 0, "size" : 10,
        "sort" : [
            {"price" : {"order" : "asc", "mode" : "avg"}}
        ],
        "script_fields" : {
            "my_field1" : {
                "script" : {
                    "lang": "painless",
                    "source": "doc['flag'].value * params.factor",
                    "params" : {
                        "factor"  : 2.0
                    }
                }
            }
        },
        "docvalue_fields" : [
            {
                "field": "postDate", 
                "format": "yyyy-MM-dd" 
            }
        ],
        "highlight" : {
            "order" : "score",
            "pre_tags" : ["<tag1>"],
            "post_tags" : ["</tag1>"],
            "fields" : {
                "_all" : {},
                "message" : {"fragment_size" : 150, "number_of_fragments" : 3}
            }
        }
    }

    QueryDSL

     **Match 与 Match Phrase【这里使用了ik分词器

    # 准备测试数据
    PUT test
    {
        "settings" : {
            "number_of_shards" : 1,
            "number_of_replicas" : 1
        },
        "mappings" : {
            "msg" : {
                "properties" : {
                    "message" : { "type" : "text","analyzer": "ik_max_word" }
                }
            }
        }
    }
    PUT test/msg/100
    {"message" : "她过山车一般的跌宕人生,成了 2018 年我听过的最精彩、也最让人感叹唏嘘的真人真事。"}
    PUT test/msg/101
    {"message" : "她就是我们今天的主人公,伊丽莎白·福尔摩斯(Elizabeth Holmes)。"}
    # match query
    GET /_search
    {
        "query": {
            "match" : {
                "message" : {
                    "query" : "今天的主人公",
                    "analyzer" : "ik_max_word"
                }
            }
        }
    }
    
    # Match Phrase Query 短语查询
    GET /_search
    {
        "query": {
            "match_phrase" : {
                "message" : {
                    "query" : "今天的主人公",
                    "analyzer" : "ik_max_word"
                }
            }
        }
    }

    执行match的结果:

    执行match phrase的结果

     

    分词器:

    POST _analyze
    {
      "analyzer": "ik_max_word",
      "text":     "今天的主人公"
    }
    ---
    {
      "tokens" : [
        {
          "token" : "今天",
          "start_offset" : 0,
          "end_offset" : 2,
          "type" : "CN_WORD",
          "position" : 0
        },
        {
          "token" : "的",
          "start_offset" : 2,
          "end_offset" : 3,
          "type" : "CN_CHAR",
          "position" : 1
        },
        {
          "token" : "主人公",
          "start_offset" : 3,
          "end_offset" : 6,
          "type" : "CN_WORD",
          "position" : 2
        },
        {
          "token" : "主人",
          "start_offset" : 3,
          "end_offset" : 5,
          "type" : "CN_WORD",
          "position" : 3
        },
        {
          "token" : "公",
          "start_offset" : 5,
          "end_offset" : 6,
          "type" : "CN_CHAR",
          "position" : 4
        }
      ]
    }

    结论:match会查出包含所有token的结果,而matchPhrase则只会查询“今天的主人公”这一个词组

     **Match Phrase Prefix Query,短语前缀查询,顾名思义:以查询关键字为前缀的查询

    # Match Phrase Prefix Query 短语前缀查询
    GET /_search
    {
        "query": {
            "match_phrase_prefix" : {
                "message" : {
                    "query" : "她就是",
                    "analyzer" : "ik_max_word"
                }
            }
        }
    }
    ---
    {
      "took" : 9,
      "timed_out" : false,
      "_shards" : {
        "total" : 28,
        "successful" : 28,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 3.2103658,
        "hits" : [
          {
            "_index" : "test",
            "_type" : "msg",
            "_id" : "101",
            "_score" : 3.2103658,
            "_source" : {
              "message" : "她就是我们今天的主人公,伊丽莎白·福尔摩斯(Elizabeth Holmes)。"
            }
          }
        ]
      }
    }

    **Query String Query

    # 字符串查询 如果多个字段:"fields" : ["content", "name"] 代替default_field
    GET /_search
    {
        "query": {
            "query_string" : {
                "default_field" : "message",
                "query" : "(过山车) OR (伊丽莎白)" 
            }
        }
    }
    ---
    {
      "took" : 5,
      "timed_out" : false,
      "_shards" : {
        "total" : 28,
        "successful" : 28,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 2,
        "max_score" : 0.80259144,
        "hits" : [
          {
            "_index" : "test",
            "_type" : "msg",
            "_id" : "101",
            "_score" : 0.80259144,
            "_source" : {
              "message" : "她就是我们今天的主人公,伊丽莎白·福尔摩斯(Elizabeth Holmes)。"
            }
          },
          {
            "_index" : "test",
            "_type" : "msg",
            "_id" : "100",
            "_score" : 0.6099695,
            "_source" : {
              "message" : "她过山车一般的跌宕人生,成了 2018 年我听过的最精彩、也最让人感叹唏嘘的真人真事。"
            }
          }
        ]
      }
    }

    以下查询的字段类型都为keyword,适合精确查询

    **TermQuery

    # Term Query 适合关键字的查询,字段类型为keyword
    GET /_search
    {
      "query": {
        "term": {
          "exact_value": "Quick Foxes!" 
        }
      }
    }

    **Terms Query

    # Terms Query 对同一个字段匹配多个关键字
    GET /_search
    {
        "query": {
            "terms" : { "user" : ["kimchy", "elasticsearch"]}
        }
    }

     **Range Query

    # Range Query 范围查询【gt:大于,gte:大于等于,lt:小于,lte:小于等于】
    GET _search
    {
        "query": {
            "range" : {
                "age" : {
                    "gte" : 10,
                    "lte" : 20,
                    "boost" : 2.0
                }
            }
        }
    }
    # Range Query 日期【y-年,M-月,w-周,d-日,h-小时,H-小时,m-分钟,s-秒。+1h:+1小时,-1d:-1天,/d:四舍五入到最近的日期,now:当前时间】比如:now = 2018-12-23 17:17:00 now/d = 2018-12-24 00:00:00
    GET _search
    {
        "query": {
            "range" : {
                "date" : {
                    "gte" : "now-1d/d",
                    "lt" :  "now/d"
                }
            }
        }
    }
    GET _search
    {
        "query": {
            "range" : {
                "birthday" : {
                    "gte": "01/01/2012",
                    "lte": "2013",
                    "format": "dd/MM/yyyy||yyyy"
                }
            }
        }
    }

    **Exists Query

    # Exist Query 返回在原始字段 message 中至少有一个非空值的文档
    GET /_search
    {
        "query": {
            "exists" : { "field" : "message" }
        }
    }

     **Prefix Query

    # Prefix Query 前缀查询
    GET /_search
    { "query": {
        "prefix" : { "user" : "ki" }
      }
    }

     **Wildcard Query

    # Wildcard Query 不建议以通配符开头,因为那样性能最低
    GET /_search
    {
        "query": {
            "wildcard" : { "user" : "ki*y" }
        }
    }

     **Regexp Query

    # Regexp Query 正则查询,你可以使用任何正则表达式,同样不建议以通配符开头
    GET /_search
    {
        "query": {
            "regexp":{
                "name.first": "s.*y"
            }
        }
    }

     **Fuzzy Query

    # Fuzzy Query 模糊查询【与SQL的模糊查询不一样,更多信息请自行查阅资料】
    GET /_search
    {
        "query": {
           "fuzzy" : { "user" : "ki" }
        }
    }

     **Type Query

    # Type Query 查询type下的所有文档
    GET /_search
    {
        "query": {
            "type" : {
                "value" : "t_doc"
            }
        }
    }

     **Ids Query

    # Ids Query 根据id列表查询
    GET /_search
    {
        "query": {
            "ids" : {
                "type" : "t_doc",
                "values" : ["1", "4", "100"]
            }
        }
    }

    下面是复合查询

    # bool查询【它有must、filter、should、must_not四个可选条件】
    POST _search
    {
      "query": {
        "bool" : {
          "must" : {
            "term" : { "user" : "kimchy" }
          },
          "filter": {
            "term" : { "tag" : "tech" }
          },
          "must_not" : {
            "range" : {
              "age" : { "gte" : 10, "lte" : 20 }
            }
          },
          "should" : [
            { "term" : { "tag" : "wow" } },
            { "term" : { "tag" : "elasticsearch" } }
          ],
          "minimum_should_match" : 1,
          "boost" : 1.0
        }
      }
    }

    下面是地理查询,初始化数据 参见 19.2 geo_bounding_box查询 地图选点:这里

    **地理边界查询【根据两个点确定的矩形,查询落在矩形内的坐标】

    # 地理边界查询
    GET /china_index/_search
    {
        "query": {
            "bool" : {
                "must" : {
                    "match_all" : {}
                },
                "filter" : {
                    "geo_bounding_box" : {
                        "location" : {
                            "top_left" : "23.1706638271,113.0383300781",
                            "bottom_right" : "22.9760953044,113.5025024414"
                        }
                    }
                }
            }
        }
    }

    结果:

    **地理半径查询【根据指定的坐标为中心,查询半径范围内的坐标】

    # 地理半径查询
    GET /china_index/_search
    {
        "query": {
            "bool" : {
                "must" : {
                    "match_all" : {}
                },
                "filter" : {
                    "geo_distance" : {
                        "distance" : "20km",
                        "location" : {
                            "lat" : 39.6733703918,
                            "lon" : 116.4111328125
                        }
                    }
                }
            }
        }
    }
    ---
    {
      "took" : 6,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "china_index",
            "_type" : "city",
            "_id" : "150",
            "_score" : 1.0,
            "_source" : {
              "pName" : "北京市",
              "cName" : "大兴区",
              "location" : {
                "lat" : 39.72684,
                "lon" : 116.34159
              }
            }
          }
        ]
      }
    }

    **地理多边形查询【查找指定的坐标围成的多边形内的坐标】

    # 地理多边形查询
    GET /china_index/_search
    {
        "query": {
            "bool" : {
                "must" : {
                    "match_all" : {}
                },
                "filter" : {
                   "geo_polygon" : {
                        "location" : {
                            "points" : [
                                "20.4270128143,110.2807617188",
                                "19.6632802200,109.7094726563",
                                "19.6839702359,110.8520507813"
                            ]
                        }
                    }
                }
            }
        }
    }
    ---
    {
      "took" : 39,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 4,
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "china_index",
            "_type" : "city",
            "_id" : "1555",
            "_score" : 1.0,
            "_source" : {
              "pName" : "海南省",
              "cName" : "海口",
              "location" : {
                "lat" : 20.02,
                "lon" : 110.35
              }
            }
          },
          {
            "_index" : "china_index",
            "_type" : "city",
            "_id" : "1556",
            "_score" : 1.0,
            "_source" : {
              "pName" : "海南省",
              "cName" : "琼山",
              "location" : {
                "lat" : 19.98,
                "lon" : 110.33
              }
            }
          },
          {
            "_index" : "china_index",
            "_type" : "city",
            "_id" : "1558",
            "_score" : 1.0,
            "_source" : {
              "pName" : "海南省",
              "cName" : "定安",
              "location" : {
                "lat" : 19.68,
                "lon" : 110.31
              }
            }
          },
          {
            "_index" : "china_index",
            "_type" : "city",
            "_id" : "1562",
            "_score" : 1.0,
            "_source" : {
              "pName" : "海南省",
              "cName" : "澄迈",
              "location" : {
                "lat" : 19.75,
                "lon" : 110.0
              }
            }
          }
        ]
      }
    }

    **地理形状查询 geo_shape【这个资料比较少,所以我重点研究了一下】

    # 存储地理形状的索引
    # tree参数:geohash和quadtree,默认geohash
    # strategy参数:recursive和term,默认recursive【支持查询:INTERSECTS,DISJOINT,WITHIN,CONTAINS】
    # precision参数:精度,单位有in, inch, yd, yard, mi, miles, km, kilometers, m,meters, cm,centimeters, mm, millimeters
    # 形状类型解释                  |  GeoJSON Type   |      WKT Type  |      Elasticsearch Type
    # 单个地理坐标                     Point              POINT              point
    # 给出两个或多个点的任意一条线        LineString         LINESTRING        linestring
    # 闭合的多边形,第一个和最后一个点必须匹配  Polygon       POLYGON            polygon
    # 一系列未连接但可能相关的点         MultiPoint         MULTIPOINT         multipoint
    # 一系列独立的线                   MultiLineString    MULTILINESTRING    multilinestring
    # 一系列单独的多边形                MultiPolygon       MULTIPOLYGON       multipolygon
    # 类似于multi系列,但是多种类型不可以共存  GeometryCollection  GEOMETRYCOLLECTION  geometrycollection
    # 仅指定左上角和右下角的矩形         无                 BBOX                  envelope
    # 指定中心和半径的圆,默认单位是米    无                 无                     circle
    PUT china_shape_index
    {
        "settings" : {
            "number_of_shards" : 1,
            "number_of_replicas" : 1
        },
        "mappings" : {
            "info" : {
                "properties" : {
                    "remark" : { "type" : "keyword" },
                    "location" : { 
                      "type" : "geo_shape",
                      "tree" : "geohash",
                      "precision": "100m"
                    }
                }
            }
        }
    }

    添加不同类型的数据

    # 注意,如果是数组[经度,纬度]
    # 添加一个点
    POST /china_shape_index/info
    {
        "location" : {
            "type" : "point",
            "coordinates" : [109.1162109375,37.2653099556]
        }
    }
    # 添加一条线
    POST /china_shape_index/info
    {
        "location" : {
            "type" : "linestring",
            "coordinates" : [[109.1162109375,37.2653099556], [117.6855468750,35.5322262277]]
        }
    }
    # 添加一个形状【我画了个三角形】
    POST /china_shape_index/info
    {
        "location" : {
            "type" : "polygon",
            "coordinates" : [
                [ [114.0380859375, 31.9148675033], [116.6748046875, 30.0690939644], 
                [111.4453125000,29.7643773752], [114.0380859375, 31.9148675033] ]
            ]
        }
    }
    # 多个坐标
    POST /china_shape_index/info
    {
        "location" : {
            "type" : "multipoint",
            "coordinates" : [
                [111.4453125000,29.7643773752], [117.6855468750,35.5322262277]
            ]
        }
    }
    # 由leftTop和bottomRight围成的矩形
    POST /china_shape_index/info
    {
        "location" : {
            "type" : "envelope",
            "coordinates" : [ [120.2783203125,25.2049411536], [122.2119140625,23.4430889311] ]
        }
    }
    # 圆形
    POST /china_shape_index/info
    {
        "location" : {
            "type" : "circle",
            "coordinates" : [116.5429687500,39.7071866568],
            "radius" : "10km"
        }
    }

    形状查询【这里与我们测试数据(以北京为中心画一个圆)相交了】

    # 查询相交的形状。relation可选:intersects, disjoint, within, contains【相交,不相交,内部,包含】
    GET /china_shape_index/_search
    {
        "query":{
            "bool": {
                "must": {
                    "match_all": {}
                },
                "filter": {
                    "geo_shape": {
                        "location": {
                            "shape": {
                                "type": "envelope",
                                "coordinates" : [[114.9169921875,40.5137991550], [118.6083984375,38.7883453551]]
                            },
                            "relation": "intersects"
                        }
                    }
                }
            }
        }
    }
    ---
    {
      "took" : 1,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 1,
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "china_shape_index",
            "_type" : "info",
            "_id" : "FbvH82cBOwlg01SCD5ab",
            "_score" : 1.0,
            "_source" : {
              "location" : {
                "type" : "circle",
                "coordinates" : [
                  116.54296875,
                  39.7071866568
                ],
                "radius" : "10km"
              }
            }
          }
        ]
      }
    }

    ..

    Java【太多了,我只选择部分示例】

    全文索引系列:matchQuery、matchAllQuery、matchPhraseQuery、matchPhrasePrefixQuery、multiMatchQuery、commonTermsQuery、queryStringQuery

    Term系列:termQuery、termsQuery、rangeQuery、existsQuery、prefixQuery、wildcardQuery、regexpQuery、fuzzyQuery、typeQuery、idsQuery

    地理系列:geoDistanceQuery、geoBoundingBoxQuery、geoPolygonQuery、geoShapeQuery

    --

        /**
         * matchQuery
    * 排序,高亮查询 *
    @return * @throws IOException */ public static RestHighLevelClient search() throws IOException { RestHighLevelClient client = RestClientFactory.getInstance().getClient(); try { SearchResponse search = client.search(new SearchRequest("test") .source(new SearchSourceBuilder() .query(QueryBuilders.matchQuery("message", "今天的主人公")) .sort("_score", SortOrder.DESC) // 根据分数倒序排序 .from(0) // 返回结果开始位置 .size(5) // 返回结果数量 .timeout(TimeValue.timeValueSeconds(10)) // 超时 .highlighter(new HighlightBuilder() .field("message",200) .preTags("<pre>").postTags("</pre>")) ), RequestOptions.DEFAULT); System.out.println("Hits:" + search.getHits().totalHits); search.getHits().forEach(e -> { System.out.println("分数:" + e.getScore() + ",结果:" + e.getSourceAsString()); Map<String, HighlightField> highlightFields = e.getHighlightFields(); for (String key : highlightFields.keySet()){ HighlightField field = highlightFields.get(key); System.out.println(key + ":" + field.fragments()[0]/* + "," + field.fragments().length*/); } }); } catch (ElasticsearchException e) { if(e.status() == RestStatus.NOT_FOUND){ // TODO System.out.println("Index Not Found-" + e.getIndex()); } } return client; }

    输出:

    Hits:2
    分数:3.421475,结果:{"message":"她就是我们今天的主人公,伊丽莎白·福尔摩斯(Elizabeth Holmes)。"}
    message:她就是我们<pre>今天</pre><pre>的</pre><pre>主人</pre><pre>公</pre>,伊丽莎白·福尔摩斯(Elizabeth Holmes)。
    分数:0.26740497,结果:{"message":"她过山车一般的跌宕人生,成了 2018 年我听过的最精彩、也最让人感叹唏嘘的真人真事。"}
    message:她过山车一般<pre>的</pre>跌宕人生,成了 2018 年我听过<pre>的</pre>最精彩、也最让人感叹唏嘘<pre>的</pre>真人真事。

     --

        /**
         * matchPhraseQuery
         * 排序,高亮查询
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient search() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            try {
                SearchResponse search = client.search(new SearchRequest("test")
                        .source(new SearchSourceBuilder()
                                .query(QueryBuilders.matchPhraseQuery("message", "今天的主人公"))
                                .sort("_score", SortOrder.DESC) // 根据分数倒序排序
                                .from(0)    // 返回结果开始位置
                                .size(5)    // 返回结果数量
                                .timeout(TimeValue.timeValueSeconds(10))    // 超时
                                .highlighter(new HighlightBuilder()
                                        .field("message",200)
                                        .preTags("<pre>").postTags("</pre>"))
                        ), RequestOptions.DEFAULT);
                System.out.println("Hits:" + search.getHits().totalHits);
                search.getHits().forEach(e -> {
                    System.out.println("分数:" + e.getScore() + ",结果:" + e.getSourceAsString());
                    Map<String, HighlightField> highlightFields = e.getHighlightFields();
                    for (String key : highlightFields.keySet()){
                        HighlightField field = highlightFields.get(key);
                        System.out.println(key + ":" + field.fragments()[0]/* + "," + field.fragments().length*/);
                    }
    
                });
            } catch (ElasticsearchException e) {
                if(e.status() == RestStatus.NOT_FOUND){
                    // TODO
                    System.out.println("Index Not Found-" + e.getIndex());
                }
            }
            return client;
        }

     结果:

    Hits:1
    分数:3.421475,结果:{"message":"她就是我们今天的主人公,伊丽莎白·福尔摩斯(Elizabeth Holmes)。"}
    message:她就是我们<pre>今天</pre><pre>的</pre><pre>主人</pre><pre>公</pre>,伊丽莎白·福尔摩斯(Elizabeth Holmes)。

    --

        /**
         * queryStringQuery
         * 排序,高亮查询
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient search() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            try {
                SearchResponse search = client.search(new SearchRequest("test")
                        .source(new SearchSourceBuilder()
                                .query(QueryBuilders.queryStringQuery("今天的主人公").field("message"))
                                .sort("_score", SortOrder.DESC) // 根据分数倒序排序
                                .from(0)    // 返回结果开始位置
                                .size(5)    // 返回结果数量
                                .timeout(TimeValue.timeValueSeconds(10))    // 超时
                                .highlighter(new HighlightBuilder()
                                        .field("message",200)
                                        .preTags("<pre>").postTags("</pre>"))
                        ), RequestOptions.DEFAULT);
                System.out.println("Hits:" + search.getHits().totalHits);
                search.getHits().forEach(e -> {
                    System.out.println("分数:" + e.getScore() + ",结果:" + e.getSourceAsString());
                    Map<String, HighlightField> highlightFields = e.getHighlightFields();
                    for (String key : highlightFields.keySet()){
                        HighlightField field = highlightFields.get(key);
                        System.out.println(key + ":" + field.fragments()[0]/* + "," + field.fragments().length*/);
                    }
    
                });
            } catch (ElasticsearchException e) {
                if(e.status() == RestStatus.NOT_FOUND){
                    // TODO
                    System.out.println("Index Not Found-" + e.getIndex());
                }
            }
            return client;
        }

    结果:

    Hits:2
    分数:3.421475,结果:{"message":"她就是我们今天的主人公,伊丽莎白·福尔摩斯(Elizabeth Holmes)。"}
    message:她就是我们<pre>今天</pre><pre>的</pre><pre>主人</pre><pre>公</pre>,伊丽莎白·福尔摩斯(Elizabeth Holmes)。
    分数:0.26740497,结果:{"message":"她过山车一般的跌宕人生,成了 2018 年我听过的最精彩、也最让人感叹唏嘘的真人真事。"}
    message:她过山车一般<pre>的</pre>跌宕人生,成了 2018 年我听过<pre>的</pre>最精彩、也最让人感叹唏嘘<pre>的</pre>真人真事。

    下面测试term系列

    # 准备测试数据
    PUT users
    {
        "settings" : {
            "number_of_shards" : 1,
            "number_of_replicas" : 1
        },
        "mappings" : {
            "info" : {
                "properties" : {
                    "username" : { "type" : "keyword" },
                    "address" : { "type" : "text","analyzer": "ik_max_word" }
                }
            }
        }
    }
    PUT users/info/1
    {"username" : "孙行者","address" : "软件产业基地1栋B座大堂","age": 15}
    PUT users/info/2
    {"username" : "孙大圣","address" : "万达北路710号戈雅公寓105号商铺","age": 26}
    PUT users/info/3
    {"username" : "西蒙·胡塞·德·拉·桑迪西玛·特里尼达·玻利瓦尔·帕拉修斯·伊·布兰科","address" : "滨河大道7009号","age": 7}
    PUT users/info/4
    {"username" : "奥斯特洛夫斯基","address" : "光谷二路225号食堂","age": 30}
    PUT users/info/5
    {"username" : "Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b","address" : "海淀紫竹院路甲2号商业05号","age": 18}
    # 查看
    GET /users/_search

    --

        /**
         * termQuery
         * rangeQuery
         * prefixQuery
         * wildcardQuery
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient termSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("users");
            String[] includeFields = new String[] {"username", "age"};
            String[] excludeFields = new String[] {"addr*"};
            request.source(new SearchSourceBuilder()
                    // 关键字查询
                    //.query(QueryBuilders.termsQuery("username", "奥斯特洛夫斯基"))
                    // 范围查询
                    //.query(QueryBuilders.rangeQuery("age").lt(20))
                    // 前缀查询
                    //.query(QueryBuilders.prefixQuery("username", "孙"))
                    // 通配符查询
                    .query(QueryBuilders.wildcardQuery("username", "西蒙*"))
                    .fetchSource(includeFields, excludeFields)  // 过滤源
                    .from(0)
                    .size(5)
                    .sort("age", SortOrder.ASC)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            return client;
        }

    结果:

    Hits:1
    {"age":7,"username":"西蒙·胡塞·德·拉·桑迪西玛·特里尼达·玻利瓦尔·帕拉修斯·伊·布兰科"}

     下面测试聚合查询 Aggregation

        /**
         * 聚合查询
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient aggSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("users");
            request.source(new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.avg("ageAVG").field("age"))
                    .from(0)
                    .size(5)
                    .sort("age", SortOrder.ASC)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            Avg avg = search.getAggregations().get("ageAVG");
            System.out.println("平均值:" + avg.getValue());
            return client;
        }

    结果:

    Hits:5
    {"username":"西蒙·胡塞·德·拉·桑迪西玛·特里尼达·玻利瓦尔·帕拉修斯·伊·布兰科","address":"滨河大道7009号","age":7}
    {"username":"孙行者","address":"软件产业基地1栋B座大堂","age":15}
    {"username":"Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b","address":"海淀紫竹院路甲2号商业05号","age":18}
    {"username":"孙大圣","address":"万达北路710号戈雅公寓105号商铺","age":26}
    {"username":"奥斯特洛夫斯基","address":"光谷二路225号食堂","age":30}
    平均值:19.2

    下面测试复合查询 bool

        /**
         * 复合查询
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient boolSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("users");
            request.source(new SearchSourceBuilder()
                    .query(QueryBuilders.boolQuery()
                            .must(QueryBuilders.rangeQuery("age").gt(20))
                            .mustNot(QueryBuilders.termQuery("username","孙大圣"))
                    )
                    .from(0)
                    .size(5)
                    .sort("age", SortOrder.ASC)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            return client;
        }

    结果:

    Hits:1
    {"username":"奥斯特洛夫斯基","address":"光谷二路225号食堂","age":30}

    下面测试地理查询

    --矩形

        public static RestHighLevelClient geoSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("china_index");
            request.source(new SearchSourceBuilder()
                    // 地理边界查询,设置字段名,top Left和bottom Right
                    .query(QueryBuilders.geoBoundingBoxQuery("location").setCorners(23.1706638271,113.0383300781,22.9760953044,113.5025024414))
                    .from(0)
                    .size(100)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            return client;
        }

    结果:

    Hits:9
    {"pName":"广东省","cName":"广州","location":{"lat":23.12908,"lon":113.26436}}
    {"pName":"广东省","cName":"越秀","location":{"lat":23.12901,"lon":113.2668}}
    {"pName":"广东省","cName":"荔湾","location":{"lat":23.12586,"lon":113.24428}}
    {"pName":"广东省","cName":"海珠","location":{"lat":23.08331,"lon":113.3172}}
    {"pName":"广东省","cName":"天河","location":{"lat":23.12463,"lon":113.36199}}
    {"pName":"广东省","cName":"白云","location":{"lat":23.157032,"lon":113.273238}}
    {"pName":"广东省","cName":"佛山","location":{"lat":23.02185,"lon":113.12192}}
    {"pName":"广东省","cName":"禅城","location":{"lat":23.00944,"lon":113.12249}}
    {"pName":"广东省","cName":"南海","location":{"lat":23.02882,"lon":113.14278}}

    --圆形

        public static RestHighLevelClient geoSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("china_index");
            List<GeoPoint> list = new ArrayList<>();
            list.add(new GeoPoint(20.4270128143,110.2807617188));
            list.add(new GeoPoint(19.6632802200,109.7094726563));
            list.add(new GeoPoint(19.6839702359,110.8520507813));
            request.source(new SearchSourceBuilder()
                    // 地理半径查询,设置字段名,纬度,经度,距离,距离类型
                    .query(QueryBuilders.geoDistanceQuery("location").point(39.6733703918,116.4111328125).distance(50, DistanceUnit.KILOMETERS))
                    .from(0)
                    .size(100)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            return client;
        }

     结果:

    Hits:15
    {"pName":"北京市","cName":"东城区","location":{"lat":39.92855,"lon":116.41637}}
    {"pName":"北京市","cName":"西城区","location":{"lat":39.91231,"lon":116.36611}}
    {"pName":"北京市","cName":"朝阳区","location":{"lat":39.927289,"lon":116.4498}}
    {"pName":"北京市","cName":"丰台区","location":{"lat":39.85856,"lon":116.28616}}
    {"pName":"北京市","cName":"石景山区","location":{"lat":39.90569,"lon":116.22299}}
    {"pName":"北京市","cName":"海淀区","location":{"lat":39.95933,"lon":116.29845}}
    {"pName":"北京市","cName":"通州区","location":{"lat":39.916195,"lon":116.662852}}
    {"pName":"北京市","cName":"大兴区","location":{"lat":39.72684,"lon":116.34159}}
    {"pName":"北京市","cName":"房山区","location":{"lat":39.74788,"lon":116.14294}}
    {"pName":"北京市","cName":"门头沟区","location":{"lat":39.94048,"lon":116.10146}}
    {"pName":"河北省","cName":"涿县","location":{"lat":39.48,"lon":115.98}}
    {"pName":"河北省","cName":"廊坊","location":{"lat":39.53,"lon":116.7}}
    {"pName":"河北省","cName":"安次","location":{"lat":39.52,"lon":116.69}}
    {"pName":"河北省","cName":"固安","location":{"lat":39.44,"lon":116.29}}
    {"pName":"河北省","cName":"永清","location":{"lat":39.32,"lon":116.48}}

     --多边形

        public static RestHighLevelClient geoSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("china_index");
            List<GeoPoint> list = new ArrayList<>();
            list.add(new GeoPoint(20.4270128143,110.2807617188));
            list.add(new GeoPoint(19.6632802200,109.7094726563));
            list.add(new GeoPoint(19.6839702359,110.8520507813));
            request.source(new SearchSourceBuilder()
                    // 地理形状查询,设置字段名,围成多边形状的坐标列表
                    .query(QueryBuilders.geoPolygonQuery("location", list))
                    .from(0)
                    .size(100)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            return client;
        }

     结果:

    Hits:4
    {"pName":"海南省","cName":"海口","location":{"lat":20.02,"lon":110.35}}
    {"pName":"海南省","cName":"琼山","location":{"lat":19.98,"lon":110.33}}
    {"pName":"海南省","cName":"定安","location":{"lat":19.68,"lon":110.31}}
    {"pName":"海南省","cName":"澄迈","location":{"lat":19.75,"lon":110.0}}

    -- geo_shape查询

        /**
         * 地理形状查询
         * https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html
         * 已知Builder实现:CircleBuilder, EnvelopeBuilder, GeometryCollectionBuilder, LineStringBuilder, MultiLineStringBuilder, MultiPointBuilder, MultiPolygonBuilder, PointBuilder, PolygonBuilder
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient geoShapeSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            SearchRequest request = new SearchRequest("china_shape_index");
            request.source(new SearchSourceBuilder()
                    .query(QueryBuilders.geoShapeQuery("location",
                            // 查询类型为envelope就用EnvelopeBuilder. topLeft,bottomRight. new Coordinate(经度,纬度)
                            new EnvelopeBuilder(new Coordinate(114.9169921875,40.5137991550),new Coordinate(118.6083984375,38.7883453551)))
                            .relation(ShapeRelation.INTERSECTS)
                    )
                    // ShapeBuilders已经过时,不推荐使用了
                    //.query(QueryBuilders.geoShapeQuery("location",ShapeBuilders.newEnvelope(new Coordinate(114.9169921875,40.5137991550),new Coordinate(118.6083984375,38.7883453551))))
                    .from(0)
                    .size(100)
            );
            SearchResponse search = client.search(request, RequestOptions.DEFAULT);
            System.out.println("Hits:" + search.getHits().totalHits);
            search.getHits().forEach(e -> {
                System.out.println(e.getSourceAsString());
            });
            return client;
        }

    结果:

    Hits:1
    {"location":{"type":"circle","coordinates":[116.54296875,39.7071866568],"radius":"10km"}}

    12. Search

    **search scroll

        /**
         * scrollSearch
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient scrollSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            // 设置超时
            final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
            SearchRequest request = new SearchRequest("books");
            request.source(new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .sort("_id",SortOrder.ASC)
                    .size(500)) // 每批大小
                    .scroll(scroll);    // 设置scroll
            SearchResponse searchResponse = client.search(request, RequestOptions.DEFAULT); // 执行查询
            String scrollId = searchResponse.getScrollId();
            SearchHit[] hits = searchResponse.getHits().getHits();
            while(hits != null && hits.length > 0) {
                System.out.println("========Begin=======");
                for (SearchHit hit : hits) {
                    System.out.println(hit.getSourceAsString());
                }
                System.out.println("========End=======");
    
                System.out.println("Size:" + hits.length + ",Scroll:" + scrollId);
                SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId)
                        .scroll(scroll);    // 设置SearchScrollRequest
                searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);  // 拉取新的数据
                scrollId = searchResponse.getScrollId();
                hits = searchResponse.getHits().getHits();
            };
            // 当scroll超时时,Search Scroll API使用的搜索上下文将自动删除
            ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
            clearScrollRequest.addScrollId(scrollId);
            ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
            boolean succeeded = clearScrollResponse.isSucceeded();
            System.out.println("ClearScroll:" + succeeded);
            return client;
        }

    结果:【一共2000条,省略了部分结果】

    ========Begin=======
    {"title":"title_1","user":"user_1"}
    {"title":"title_10","user":"user_10"}
    {"title":"title_100","user":"user_100"}
    {"title":"title_1000","user":"user_1000"}
    ...
    {"title":"title_1448","user":"user_1448"}
    ========End=======
    Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB
    ========Begin=======
    ...
    {"title":"title_1899","user":"user_1899"}
    ========End=======
    Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB
    ========Begin=======
    {"title":"title_19","user":"user_19"}
    ...
    {"title":"title_548","user":"user_548"}
    ========End=======
    Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB
    ========Begin=======
    {"title":"title_549","user":"user_549"}
    ...
    {"title":"title_6","user":"user_6"}
    {"title":"title_60","user":"user_60"}
    {"title":"title_600","user":"user_600"}
    ...
    {"title":"title_699","user":"user_699"}
    {"title":"title_7","user":"user_7"}
    {"title":"title_70","user":"user_70"}
    {"title":"title_700","user":"user_700"}
    ...
    {"title":"title_799","user":"user_799"}
    {"title":"title_8","user":"user_8"}
    {"title":"title_80","user":"user_80"}
    {"title":"title_800","user":"user_800"}
    ...
    {"title":"title_899","user":"user_899"}
    {"title":"title_9","user":"user_9"}
    {"title":"title_90","user":"user_90"}
    {"title":"title_900","user":"user_900"}
    ...
    {"title":"title_999","user":"user_999"}
    ========End=======
    Size:500,Scroll:DnF1ZXJ5VGhlbkZldGNoBQAAAAAAAM7QFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADOzxZ3Q3I2VXowalR2R2FUSGg1YWNOeEtBAAAAAAAAztEWd0NyNlV6MGpUdkdhVEhoNWFjTnhLQQAAAAAAAM7SFndDcjZVejBqVHZHYVRIaDVhY054S0EAAAAAAADO0xZ3Q3I2VXowalR2R2FUSGg1YWNOeEtB
    ClearScroll:true

    **Multi-Search

    HTTP请求

    # 格式:一行header一行body
    GET users/_msearch
    {}
    {"query": {"terms" : { "username" : ["孙行者", "孙大圣"]}}}
    {}
    {"query": {"term" : { "username" : "Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b"}}}
    ---
    {
      "responses" : [
        {
          "took" : 0,
          "timed_out" : false,
          "_shards" : {
            "total" : 1,
            "successful" : 1,
            "skipped" : 0,
            "failed" : 0
          },
          "hits" : {
            "total" : 2,
            "max_score" : 1.0,
            "hits" : [
              {
                "_index" : "users",
                "_type" : "info",
                "_id" : "1",
                "_score" : 1.0,
                "_source" : {
                  "username" : "孙行者",
                  "address" : "软件产业基地1栋B座大堂",
                  "age" : 15
                }
              },
              {
                "_index" : "users",
                "_type" : "info",
                "_id" : "2",
                "_score" : 1.0,
                "_source" : {
                  "username" : "孙大圣",
                  "address" : "万达北路710号戈雅公寓105号商铺",
                  "age" : 26
                }
              }
            ]
          },
          "status" : 200
        },
        {
          "took" : 0,
          "timed_out" : false,
          "_shards" : {
            "total" : 1,
            "successful" : 1,
            "skipped" : 0,
            "failed" : 0
          },
          "hits" : {
            "total" : 1,
            "max_score" : 1.3862944,
            "hits" : [
              {
                "_index" : "users",
                "_type" : "info",
                "_id" : "5",
                "_score" : 1.3862944,
                "_source" : {
                  "username" : "Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b",
                  "address" : "海淀紫竹院路甲2号商业05号",
                  "age" : 18
                }
              }
            ]
          },
          "status" : 200
        }
      ]
    }

    Java

    public static RestHighLevelClient multiSearch() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            MultiSearchRequest request = new MultiSearchRequest();
            // 第一个查询
            SearchRequest firstSearchRequest = new SearchRequest("users");
            firstSearchRequest.source(new SearchSourceBuilder().query(QueryBuilders.termsQuery("username","孙大圣")));
            request.add(firstSearchRequest);
            // 第二个查询
            SearchRequest secondSearchRequest = new SearchRequest("users");
            secondSearchRequest.source(new SearchSourceBuilder().query(QueryBuilders.prefixQuery("username", "Brfxx")));
            request.add(secondSearchRequest);
    
            MultiSearchResponse msearch = client.msearch(request, RequestOptions.DEFAULT);
            MultiSearchResponse.Item[] responses = msearch.getResponses();
            for (MultiSearchResponse.Item i : responses){
                System.out.println("========" + i.getResponse().status().name());
                i.getResponse().getHits().forEach(e -> {
                    System.out.println(e.getSourceAsString());
                });
            }
            return client;
        }

    结果:

    ========OK
    {"username":"孙大圣","address":"万达北路710号戈雅公寓105号商铺","age":26}
    ========OK
    {"username":"Brfxxccxxmnpcccclllmmnprxvclmnckssqlbb1111b","address":"海淀紫竹院路甲2号商业05号","age":18}

    13. Cluster

    HTTP请求

    GET _cluster/health
    ---
    {
      "cluster_name" : "my-elasticsearch",
      "status" : "yellow",
      "timed_out" : false,
      "number_of_nodes" : 1,
      "number_of_data_nodes" : 1,
      "active_primary_shards" : 15,
      "active_shards" : 15,
      "relocating_shards" : 0,
      "initializing_shards" : 0,
      "unassigned_shards" : 14,
      "delayed_unassigned_shards" : 0,
      "number_of_pending_tasks" : 0,
      "number_of_in_flight_fetch" : 0,
      "task_max_waiting_in_queue_millis" : 0,
      "active_shards_percent_as_number" : 51.724137931034484
    }

     获取集群状态

    GET /_cluster/state
    ---
    {
      "cluster_name" : "my-elasticsearch",
      "compressed_size_in_bytes" : 14766,
      "cluster_uuid" : "QmDZ773JR_ip0AN6jEdWtA",
      "version" : 33,
      "state_uuid" : "l8WJu9BzTfGsIKba_gsodA",
      "master_node" : "wCr6Uz0jTvGaTHh5acNxKA",
      "blocks" : { },
      "nodes" : {
        "wCr6Uz0jTvGaTHh5acNxKA" : {
          "name" : "wCr6Uz0",
          "ephemeral_id" : "qFZoP0iWQDm3EWM3TDb_vg",
          "transport_address" : "127.0.0.1:9300",
          "attributes" : {
            "ml.machine_memory" : "8510087168",
            "xpack.installed" : "true",
            "ml.max_open_jobs" : "20",
            "ml.enabled" : "true"
          }
        }
      },
    ...
    }
    GET /_cluster/stats?human&pretty
    
    GET /_cluster/settings
    
    # 设置集群settings
    # 1. transient cluster settings
    # 2. persistent cluster settings
    # 3. settings in the elasticsearch.yml configuration file.
    PUT /_cluster/settings
    {
        "persistent" : {
            "indices.recovery.max_bytes_per_sec" : "50mb"
        }
    }
    
    # explain索引【三个参数必须的】
    GET /_cluster/allocation/explain
    {
      "index": "china_index",
      "shard": 0,
      "primary": true
    }
    
    # 节点统计数据
    GET /_nodes/stats
    GET /_nodes/nodeId1,nodeId2/stats
    
    # return just indices
    GET /_nodes/stats/indices
    
    # return just os and process
    GET /_nodes/stats/os,process
    
    # return just process for node with IP address 10.0.0.1
    GET /_nodes/10.0.0.1/stats/process
    
    # 每个节点的实用信息
    GET _nodes/usage
    GET _nodes/nodeId1,nodeId2/usage

    Java

        /**
         * 集群信息
         * @return
         */
        public static RestHighLevelClient info() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            boolean ping = client.ping(RequestOptions.DEFAULT);
            System.out.println("Ping:" + ping);
            MainResponse info = client.info(RequestOptions.DEFAULT);
            ClusterName clusterName = info.getClusterName();
            String clusterUuid = info.getClusterUuid();
            String nodeName = info.getNodeName();
            Version version = info.getVersion();
            Build build = info.getBuild();
            System.out.println("集群名称:" + clusterName.value());
            System.out.println("Uuid:" + clusterUuid);
            System.out.println("节点名称:" + nodeName);
            System.out.println("Version:" + version.toString());
            System.out.println("Bulid:" + build.toString());
            return client;
        }

    结果:

    Ping:true
    集群名称:my-elasticsearch
    Uuid:QmDZ773JR_ip0AN6jEdWtA
    节点名称:wCr6Uz0
    Version:6.5.0
    Bulid:[default][zip][816e6f6][2018-11-09T18:58:36.352602Z]

    14. Indices

    14.1 分词器

    # 标准分词器
    GET _analyze
    {
      "analyzer" : "standard",
      "text" : ["this is a test", "the second text"]
    }
    # IK分词器
    GET _analyze
    {
      "analyzer" : "ik_smart",
      "text" : ["真好玩", "一个叫yado的博士找到他,希望buzzo和他的团伙去帮他散布一种叫做joy的毒品"]
    }

    --

        /**
         * 分词器
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient analyze() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            AnalyzeRequest request = new AnalyzeRequest();
            request.text("真好玩", "一个叫yado的博士找到他,希望buzzo和他的团伙去帮他散布一种叫做joy的毒品");
            request.analyzer("ik_smart");
            AnalyzeResponse response = client.indices().analyze(request, RequestOptions.DEFAULT);
            List<AnalyzeResponse.AnalyzeToken> tokens = response.getTokens();
    
            for(AnalyzeResponse.AnalyzeToken t : tokens){
                int endOffset = t.getEndOffset();
                int position = t.getPosition();
                int positionLength = t.getPositionLength();
                int startOffset = t.getStartOffset();
                String term = t.getTerm();
                String type = t.getType();
                System.out.println("Start:" + startOffset + ",End:" + endOffset + ",Position:" + position + ",Length:" + positionLength +
                        ",Term:" + term + ",Type:" + type);
            }
            return client;
        }

    结果:

    Start:0,End:3,Position:0,Length:1,Term:真好玩,Type:CN_WORD
    Start:4,End:6,Position:1,Length:1,Term:一个,Type:CN_WORD
    Start:6,End:7,Position:2,Length:1,Term:叫,Type:CN_CHAR
    Start:7,End:11,Position:3,Length:1,Term:yado,Type:ENGLISH
    Start:11,End:12,Position:4,Length:1,Term:的,Type:CN_CHAR
    Start:12,End:14,Position:5,Length:1,Term:博士,Type:CN_WORD
    Start:14,End:15,Position:6,Length:1,Term:找,Type:CN_CHAR
    Start:15,End:17,Position:7,Length:1,Term:到他,Type:CN_WORD
    Start:18,End:20,Position:8,Length:1,Term:希望,Type:CN_WORD
    Start:20,End:25,Position:9,Length:1,Term:buzzo,Type:ENGLISH
    Start:25,End:27,Position:10,Length:1,Term:和他,Type:CN_WORD
    Start:27,End:28,Position:11,Length:1,Term:的,Type:CN_CHAR
    Start:28,End:30,Position:12,Length:1,Term:团伙,Type:CN_WORD
    Start:30,End:31,Position:13,Length:1,Term:去,Type:CN_CHAR
    Start:31,End:32,Position:14,Length:1,Term:帮,Type:CN_CHAR
    Start:32,End:33,Position:15,Length:1,Term:他,Type:CN_CHAR
    Start:33,End:35,Position:16,Length:1,Term:散布,Type:CN_WORD
    Start:35,End:37,Position:17,Length:1,Term:一种,Type:CN_WORD
    Start:37,End:39,Position:18,Length:1,Term:叫做,Type:CN_WORD
    Start:39,End:42,Position:19,Length:1,Term:joy,Type:ENGLISH
    Start:42,End:43,Position:20,Length:1,Term:的,Type:CN_CHAR
    Start:43,End:45,Position:21,Length:1,Term:毒品,Type:CN_WORD

    14.2 Create Index

    创建索引限制

    小写字母
    
    不能包含 \, /, *, ?, ", <, >, |, ` ` (space character), ,, #
    
    7.0之前的索引可能包含冒号(:),但是不赞成这样做,7.0+不支持这样做
    
    不能以-,_,+开头
    
    不能. or ..
    
    长度不能超过255字节

    HTTP请求

    # 创建索引
    PUT twitter
    {
        "settings" : {
            "number_of_shards" : 3,
            "number_of_replicas" : 2
        },
        "mappings" : {
            "my_doc" : {
                "properties" : {
                    "field1" : { "type" : "text" }
                }
            }
        }
    }

     Java

        public static RestHighLevelClient createIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            CreateIndexRequest request = new CreateIndexRequest("twitter");
            request.settings(Settings.builder()
                    .put("index.number_of_shards", 3)
                    .put("index.number_of_replicas", 2))
                    // 设置mapping
                    //.mapping("t_doc", "field1","type=keyword,store=true")    // Object key-pairs
                    .mapping("t_doc", jsonBuilder()
                    .startObject()
                        .startObject("t_doc")
                            .startObject("properties")
                                .startObject("msg")
                                    .field("type","text")
                                .endObject()
                            .endObject()
                        .endObject()
                    .endObject())
                    // 别名
                    .alias(new Alias("my_index_alias"))
                    // 创建超时
                    .timeout(TimeValue.timeValueMinutes(2))
                    // 连接到主节点超时时间
                    .masterNodeTimeout(TimeValue.timeValueMinutes(1))
                    // 在创建索引返回响应之前等待的活动碎片副本的数量
                    .waitForActiveShards(2);
            CreateIndexResponse indexResponse = client.indices().create(request, RequestOptions.DEFAULT);
            boolean acknowledged = indexResponse.isAcknowledged();
            boolean shardsAcknowledged = indexResponse.isShardsAcknowledged();
            System.out.println(acknowledged);
            return client;
        }

    14.3 Delete Index

    # 删除索引
    DELETE /twitter

    Java

        public static RestHighLevelClient deleteIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            DeleteIndexRequest request = new DeleteIndexRequest();  
            // 使用_all或者通配符*可以删除所有索引。如果要禁用:action.destructive_requires_name=true
            request.indices("twitter","it_book","car","school","story");
    
            try {
                AcknowledgedResponse acknowledgedResponse = client.indices().delete(request, RequestOptions.DEFAULT);
                boolean acknowledged = acknowledgedResponse.isAcknowledged();
                System.out.println(acknowledged);
            } catch (ElasticsearchException exception) {
                if (exception.status() == RestStatus.NOT_FOUND) {
                    System.err.println("Index Not Found");
                }
            }
            return client;
        }

    14.4 Indices Exists

    # 索引是否存在
    HEAD /china_index
    # Type是否存在
    HEAD /china_index/_mapping/city

    Java

        public static RestHighLevelClient existIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetIndexRequest request = new GetIndexRequest();
            request.indices("china_index");
            boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
            System.out.println(exists);
            return client;
        }


    14.5 Open Index

    # 开启索引
    POST /twitter/_open

    Java

        public static RestHighLevelClient openIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            OpenIndexRequest request = new OpenIndexRequest("twitter");
            request.timeout(TimeValue.timeValueMinutes(2));
            OpenIndexResponse open = client.indices().open(request, RequestOptions.DEFAULT);
            boolean acknowledged = open.isAcknowledged();
            boolean shardsAcked = open.isShardsAcknowledged();
            System.out.println(acknowledged);
            return client;
        }


    14.6 Close Index

    # 关闭索引
    POST /twitter/_close

    Java

        public static RestHighLevelClient closeIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            CloseIndexRequest request = new CloseIndexRequest("twitter");
            request.timeout(TimeValue.timeValueMinutes(2));
            AcknowledgedResponse closeIndexResponse = client.indices().close(request, RequestOptions.DEFAULT);
            boolean acknowledged = closeIndexResponse.isAcknowledged();
            System.out.println(acknowledged);
            return client;
        }

    14.7 Shrink Index【压缩索引】

    # 准备源索引
    PUT my_source_index
    {
        "settings" : {
            "number_of_shards" : 4,
            "number_of_replicas" : 2,
            "index.blocks.write": true
        }
    }
    --
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "my_source_index"
    }

    压缩操作

    POST my_source_index/_shrink/my_target_index?copy_settings=true
    {
      "settings": {
        "index.number_of_shards": 1, 
        "index.number_of_replicas": 1,
        "index.codec": "best_compression" 
      },
      "aliases": {
        "my_search_indices": {}
      }
    }
    --
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "my_target_index"
    }

    查看索引信息

    GET my_source_index
    结果:
    {
      "my_source_index" : {
        "aliases" : { },
        "mappings" : { },
        "settings" : {
          "index" : {
            "number_of_shards" : "4",
            "blocks" : {
              "write" : "true"
            },
            "provided_name" : "my_source_index",
            "creation_date" : "1546589291669",
            "number_of_replicas" : "2",
            "uuid" : "tSYNLldWQNCOlR5NJGaH9g",
            "version" : {
              "created" : "6050099"
            }
          }
        }
      }
    }
    ---
    GET my_target_index
    结果:
    {
      "my_target_index" : {
        "aliases" : {
          "my_search_indices" : { }
        },
        "mappings" : { },
        "settings" : {
          "index" : {
            "allocation" : {
              "max_retries" : "1"
            },
            "shrink" : {
              "source" : {
                "name" : "my_source_index",
                "uuid" : "tSYNLldWQNCOlR5NJGaH9g"
              }
            },
            "blocks" : {
              "write" : "true"
            },
            "provided_name" : "my_target_index",
            "creation_date" : "1546589354014",
            "number_of_replicas" : "1",
            "uuid" : "F976xviGQ965JU9patwQnA",
            "version" : {
              "created" : "6050099",
              "upgraded" : "6050099"
            },
            "codec" : "best_compression",
            "routing" : {
              "allocation" : {
                "initial_recovery" : {
                  "_id" : "wCr6Uz0jTvGaTHh5acNxKA"
                }
              }
            },
            "number_of_shards" : "1",
            "routing_partition_size" : "1",
            "resize" : {
              "source" : {
                "name" : "my_source_index",
                "uuid" : "tSYNLldWQNCOlR5NJGaH9g"
              }
            }
          }
        }
      }
    }

    Java

        /**
         * 压缩索引(将索引压缩为主分片数更少的新索引)
         * 目标索引中请求的主碎片数量必须是源索引中碎片数量的一个因数。例如,有8个主碎片的索引可以压缩为4个、2个或1个主碎片;
         * 或者有15个主碎片的索引可以压缩为5个、3个或1个主碎片。
         * 过程:
         *      首先,它创建一个新的目标索引,其定义与源索引相同,但是主碎片的数量较少
         *      然后它将段从源索引硬链接到目标索引
         *      最后,它将目标索引恢复为一个刚刚重新打开的closed index
         * @return
         */
        public static RestHighLevelClient shrinkIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            ResizeRequest resizeRequest = new ResizeRequest("target_index", "source_index");
            resizeRequest.getTargetIndexRequest()
                    .alias(new Alias("target_index_alias"))
                    .settings(Settings.builder()
                            .put("index.number_of_shards", 2)
                    );
            ResizeResponse resizeResponse = client.indices().shrink(resizeRequest, RequestOptions.DEFAULT);
            boolean acknowledged = resizeResponse.isAcknowledged();
            boolean shardsAcked = resizeResponse.isShardsAcknowledged();
            System.out.println(acknowledged);
            return client;
        }

    14.8 Split Index

    准备数据

    # index.number_of_routing_shards must be >= index.number_of_shards
    PUT my_source_index2
    {
        "settings" : {
            "number_of_shards" : 2,
            "index.number_of_routing_shards" : 8,
            "index.blocks.write": true
        }
    }
    --
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "my_source_index2"
    }

    拆分

    # 拆分索引
    POST my_source_index2/_split/my_target_index2?copy_settings=true
    {
      "settings": {
        "index.number_of_shards": 4
      },
      "aliases": {
        "my_search_indices": {}
      }
    }
    --
    {
      "acknowledged" : true,
      "shards_acknowledged" : true,
      "index" : "my_target_index2"
    }

    查看索引

    GET my_source_index2
    结果:
    {
      "my_source_index2" : {
        "aliases" : { },
        "mappings" : { },
        "settings" : {
          "index" : {
            "number_of_shards" : "2",
            "blocks" : {
              "write" : "true"
            },
            "provided_name" : "my_source_index2",
            "creation_date" : "1546590226265",
            "number_of_replicas" : "1",
            "uuid" : "iuDENl3uQku0Ef6flu8S-Q",
            "version" : {
              "created" : "6050099"
            }
          }
        }
      }
    }
    ---
    GET my_target_index2
    结果:
    {
      "my_target_index2" : {
        "aliases" : {
          "my_search_indices" : { }
        },
        "mappings" : { },
        "settings" : {
          "index" : {
            "number_of_shards" : "4",
            "routing_partition_size" : "1",
            "blocks" : {
              "write" : "true"
            },
            "provided_name" : "my_target_index2",
            "resize" : {
              "source" : {
                "name" : "my_source_index2",
                "uuid" : "iuDENl3uQku0Ef6flu8S-Q"
              }
            },
            "creation_date" : "1546590255143",
            "number_of_replicas" : "1",
            "uuid" : "ZBnocs2bSker45kb2lXoRw",
            "version" : {
              "created" : "6050099",
              "upgraded" : "6050099"
            }
          }
        }
      }
    }

    Java

        /**
         * 拆分索引(每个原始的主碎片被拆分为新索引中的两个或多个主碎片)
         * 重要:源索引必须在创建的时候指定number_of_routing_shards参数,以便将来有拆分的需要。在Elasticsearch 7.0这个前提被移除。
         * 索引能被拆分的次数以及每个主分片能被拆分的个数取决于index.number_of_routing_shards参数的设置
         * 过程:
         *      首先,它创建一个新的目标索引,其定义与源索引相同,但是具有更多的主碎片
         *      然后它将段从源索引硬链接到目标索引
         *      创建了低级文件之后,所有文档将再次散列以删除属于不同碎片的文档
         *      最后,它将目标索引恢复为一个刚刚重新打开的closed index
         * @return
         */
        public static RestHighLevelClient  splitIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            ResizeRequest resizeRequest = new ResizeRequest("target_index", "source_index");
            resizeRequest.timeout(TimeValue.timeValueSeconds(2))
                    .masterNodeTimeout(TimeValue.timeValueMinutes(1))
                    .setResizeType(ResizeType.SPLIT);  // 类型是拆分
            resizeRequest.getTargetIndexRequest()
                    .alias(new Alias("target_index_alias"))
                    .settings(Settings.builder()
                    .put("index.number_of_shards", 4));
            ResizeResponse resizeResponse = client.indices().split(resizeRequest, RequestOptions.DEFAULT);
            boolean acknowledged = resizeResponse.isAcknowledged();
            boolean shardsAcked = resizeResponse.isShardsAcknowledged();
            return client;
        }

    14.9 Refresh

    # 刷新索引【默认定期刷新】
    POST /kimchy,elasticsearch/_refresh
    POST /_refresh

    --

        /**
         * 刷新索引
         * 默认情况下,刷新是定期调度的
         * @return
         */
        public static RestHighLevelClient refreshIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            RefreshRequest refreshRequest = new RefreshRequest("index_1","index_2");
            
            try {
                RefreshResponse refresh = client.indices().refresh(refreshRequest, RequestOptions.DEFAULT);
                int totalShards = refresh.getTotalShards();
                int successfulShards = refresh.getSuccessfulShards();
                int failedShards = refresh.getFailedShards();
                DefaultShardOperationFailedException[] failures = refresh.getShardFailures();
            } catch (ElasticsearchException exception) {
                if (exception.status() == RestStatus.NOT_FOUND) {
                    // TODO
                }
            }
            return client;
        }


    14.10 Flush

    POST twitter/_flush

    ---

        /**
         * https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-flush.html
         * 索引的刷新进程通过将数据刷新到索引存储并清除内部事务日志,基本上将内存从索引中释放出来
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient flushIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            FlushRequest requestMultiple = new FlushRequest("index1", "index2");
            try {
                FlushResponse flushResponse = client.indices().flush(requestMultiple, RequestOptions.DEFAULT);
                int totalShards = flushResponse.getTotalShards();
                int successfulShards = flushResponse.getSuccessfulShards();
                int failedShards = flushResponse.getFailedShards();
                DefaultShardOperationFailedException[] failures = flushResponse.getShardFailures();
            } catch (ElasticsearchException exception) {
                if (exception.status() == RestStatus.NOT_FOUND) {
                    // TODO
                }
            }
            return client;
        }

    14.11 Clear Cache

    # 清空缓存
    POST /twitter/_cache/clear

    ---

        /**
         * 清除索引的缓存
         * @return
         */
        public static RestHighLevelClient clearCacheIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            ClearIndicesCacheRequest cacheRequest = new ClearIndicesCacheRequest("index1", "index2");
            cacheRequest.queryCache(true);       // 查询
            cacheRequest.fieldDataCache(true);   // 字段数据
            cacheRequest.requestCache(true);     // 请求
            cacheRequest.fields("field1", "field2", "field3");
            
            try {
                ClearIndicesCacheResponse clearCache = client.indices().clearCache(cacheRequest, RequestOptions.DEFAULT);
                int totalShards = clearCache.getTotalShards();
                int successfulShards = clearCache.getSuccessfulShards();
                int failedShards = clearCache.getFailedShards();
                DefaultShardOperationFailedException[] failures = clearCache.getShardFailures();
            } catch (ElasticsearchException exception) {
                if (exception.status() == RestStatus.NOT_FOUND) {
                    // TODO
                }
            }
            return client;
        }

    14.12 Force Merge 

    Http

    # 合并
    POST /kimchy/_forcemerge?only_expunge_deletes=false&max_num_segments=100&flush=true
    # max_num_segments=1,所有的段都重写为一个新的
    POST /kimchy,elasticsearch/_forcemerge

    Java

        /**
         * 合并一个或多个索引
         * 此调用将阻塞,直到合并完成。如果http连接丢失,请求将在后台继续,任何新请求都将阻塞,直到前一个强制合并完成
         * **强制合并只能对只读索引调用。对读写索引执行强制合并会导致产生非常大的段(每段大于5GB)
         * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-force-merge.html
         * https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-forcemerge.html
         * @return
         */
        public static RestHighLevelClient ForceMergeIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            ForceMergeRequest requestMultiple = new ForceMergeRequest("index1", "index2");
            // 要合并的分片数。要完全合并索引,请将其设置为1
            requestMultiple.maxNumSegments(1);
            // 合并过程是否删除标记为删除的段。在Lucene中,一个文档不是从一个段中删除,而是标记为已删除。在段的合并过程中,将创建一个没有这些删除的新段。
            // 此标志只允许合并具有删除的段。默认值为false
            requestMultiple.onlyExpungeDeletes(true);
            requestMultiple.flush(true);
            
            try {
                ForceMergeResponse forceMergeResponse = client.indices().forcemerge(requestMultiple, RequestOptions.DEFAULT);
                int totalShards = forceMergeResponse.getTotalShards();
                int successfulShards = forceMergeResponse.getSuccessfulShards();
                int failedShards = forceMergeResponse.getFailedShards();
                DefaultShardOperationFailedException[] failures = forceMergeResponse.getShardFailures();
            } catch (ElasticsearchException exception) {
                if (exception.status() == RestStatus.NOT_FOUND) {
                    // TODO
                }
            }
            return client;
        }

    14.13 Put Mapping

     HTTP

    # 增加一个不带type的索引
    PUT twitter 
    {}
    # 增加type
    PUT twitter/_mapping/_doc 
    {
      "properties": {
        "email": {
          "type": "keyword"
        }
      }
    }

    Java

        /**
         * 添加mapping(不能更新已存在的字段类型)
         * @return
         */
        public static RestHighLevelClient putMapping() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            PutMappingRequest request = new PutMappingRequest("twitter");
            request.type("_doc");
            // 我更喜欢Object key-pairs 的形式
            request.source("message","type=text","name","type=keyword");
            request.timeout(TimeValue.timeValueMinutes(2));
            request.masterNodeTimeout(TimeValue.timeValueMinutes(1));
            AcknowledgedResponse putMappingResponse = client.indices().putMapping(request, RequestOptions.DEFAULT);
            boolean acknowledged = putMappingResponse.isAcknowledged();
            System.out.println(acknowledged);
            return client;
        }

    14.14 Get Mappings

     HTTP

    # 获取全部索引的Mapping,可以精确到type
    GET /_all/_mapping/[Type]
    #获取指定索引的Mapping
    GET /twitter/_mapping/[Type]
    # 例如:
    GET /china_index/_mapping
    ...
    {
      "china_index" : {
        "mappings" : {
          "city" : {
            "properties" : {
              "cName" : {
                "type" : "text"
              },
              "location" : {
                "type" : "geo_point"
              },
              "pName" : {
                "type" : "keyword"
              }
            }
          }
        }
      }
    }

    Java

        /**
         * 获取mapping
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient getMapping() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetMappingsRequest request = new GetMappingsRequest();
            request.indices("china_index");
            request.types("city");
            request.masterNodeTimeout(TimeValue.timeValueMinutes(1));
            GetMappingsResponse getMappingResponse = client.indices().getMapping(request, RequestOptions.DEFAULT);
            getMappingResponse.getMappings().forEach(e -> {
                String key = e.key;
                ImmutableOpenMap<String, MappingMetaData> value = e.value;
                value.forEach(v -> {
                    System.out.println(key + "|" + v.key + "|" + v.value.getSourceAsMap());
                });
            });
            return client;
        }

    结果:

    china_index|city|{properties={pName={type=keyword}, cName={type=text}, location={type=geo_point}}}


    14.15 Get Field Mappings

     HTTP

    # 查看具体字段的Mapping信息
    GET [索引]/_mapping/field/[field1,field2]
    GET china_index/_mapping/field/pName,location
    ..
    {
      "china_index" : {
        "mappings" : {
          "city" : {
            "pName" : {
              "full_name" : "pName",
              "mapping" : {
                "pName" : {
                  "type" : "keyword"
                }
              }
            },
            "location" : {
              "full_name" : "location",
              "mapping" : {
                "location" : {
                  "type" : "geo_point"
                }
              }
            }
          }
        }
      }
    }

    Java

        /**
         * 获取指定字段的Mapping
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient getFieldMappings() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetFieldMappingsRequest request = new GetFieldMappingsRequest();
            request.indices("china_index");   // 可以多个索引
            request.types("city");             // 多个类型
            request.fields("pName","location");  // 多个字段
            GetFieldMappingsResponse response = client.indices().getFieldMapping(request, RequestOptions.DEFAULT);
            Map<String, Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>>> mappings = response.mappings();
            mappings.keySet().forEach(e -> {
                Map<String, Map<String, GetFieldMappingsResponse.FieldMappingMetaData>> mapMap = mappings.get(e);
                mapMap.keySet().forEach(i -> {
                    Map<String, GetFieldMappingsResponse.FieldMappingMetaData> metaDataMap = mapMap.get(i);
                    metaDataMap.keySet().forEach(j -> {
                        GetFieldMappingsResponse.FieldMappingMetaData fieldMappingMetaData = metaDataMap.get(j);
                        System.out.println(e + "|" + i + "|" + j + "|" + fieldMappingMetaData.sourceAsMap());
                    });
                });
            });
            return client;
        }

    结果:

    china_index|city|pName|{pName={type=keyword}}
    china_index|city|location|{location={type=geo_point}}


    14.16 Index Aliases

     HTTP

    # 添加别名
    POST /_aliases
    {
        "actions" : [
            { "remove" : { "index" : "test1", "alias" : "alias1" } },
            { "add" : { "index" : "test2", "alias" : "alias1" } }
        ]
    }
    # 例子
    POST /_aliases
    {
        "actions" : [
            { "add" : { "index" : "my_source_index", "alias" : "alias111" } },
            { "add" : { "index" : "my_source_index2", "alias" : "alias222" } }
        ]
    }
    ...
    {
      "acknowledged" : true
    }

    Java

        /**
         * 添加别名,这个方法只是列出了一些情况,如果要运行请先根据实际情况修改
         * @return
         */
        public static RestHighLevelClient indexAlias() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            IndicesAliasesRequest request = new IndicesAliasesRequest();
            IndicesAliasesRequest.AliasActions aliasAction =
                    new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD)
                            .index("index1")
                            .alias("alias1");
            // 添加别名,并指定routing
            IndicesAliasesRequest.AliasActions addIndicesAction =
                    new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.ADD)
                            .indices("index1", "index2")
                            .alias("alias2")
                            .routing("my_routing");
            // 移除别名
            IndicesAliasesRequest.AliasActions removeAction =
                    new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE)
                            .index("index3")
                            .alias("alias3");
            // 删除索引
            IndicesAliasesRequest.AliasActions removeIndexAction =
                    new IndicesAliasesRequest.AliasActions(IndicesAliasesRequest.AliasActions.Type.REMOVE_INDEX)
                            .index("index4");
            request.addAliasAction(aliasAction);
            AcknowledgedResponse indicesAliasesResponse =
                    client.indices().updateAliases(request, RequestOptions.DEFAULT);
            boolean acknowledged = indicesAliasesResponse.isAcknowledged();
            System.out.println(acknowledged);
            return client;
        }

    14.17 Exists Alias

     HTTP

    # 检查
    HEAD /my_source_index/_alias/alias111
    # 从所有索引里面找别名为2016的
    HEAD /_alias/2016
    # 还可以使用通配符
    HEAD /_alias/20*
    ---
    存在的话
    200 - OK
    不存在
    404 - Not Found

    Java

        /**
         * 判断别名是否存在
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient aliasExist() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetAliasesRequest request = new GetAliasesRequest();
            request.aliases("alias222");
            request.indices("my_source_index2");
    //        GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1");   // 单个
    //        GetAliasesRequest requestWithAliases =
    //                new GetAliasesRequest(new String[]{"alias1", "alias2"});        // 多个
            boolean exists = client.indices().existsAlias(request, RequestOptions.DEFAULT);
            System.out.println(exists);
            return client;
        }

    结果:true


    14.18 Get Alias

    HTTP

    # 获取
    GET /my_source_index/_alias/alias111
    --
    {
      "my_source_index" : {
        "aliases" : {
          "alias111" : { }
        }
      }
    }
    # 从所有索引里面找别名为alias222的
    GET /_alias/alias222
    --
    {
      "my_source_index2" : {
        "aliases" : {
          "alias222" : { }
        }
      }
    }
    # 还可以使用通配符
    GET /_alias/20*
    # 显示索引的所有别名
    GET /my_source_index/_alias/*
    # 所有别名
    GET /_alias/*
    --
    {
      "my_target_index2" : {
        "aliases" : {
          "my_search_indices" : { }
        }
      },
      "my_source_index2" : {
        "aliases" : {
          "alias222" : { }
        }
      },
      ".kibana_1" : {
        "aliases" : {
          ".kibana" : { }
        }
      },
      "my_source_index" : {
        "aliases" : {
          "alias111" : { }
        }
      },
      "my_target_index" : {
        "aliases" : {
          "my_search_indices" : { }
        }
      }
    }

     如果要删除

    # 删除别名
    DELETE /my_source_index/_alias/alias111
    --
    {
      "acknowledged" : true
    }

    Java

        /**
         * 获取别名
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient getAlias() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetAliasesRequest request = new GetAliasesRequest();
            request.aliases("alias222");
            request.indices("my_source_index2");
    //        GetAliasesRequest requestWithAlias = new GetAliasesRequest("alias1");
    //        GetAliasesRequest requestWithAliases =
    //                new GetAliasesRequest(new String[]{"alias1", "alias2"});
            GetAliasesResponse response = client.indices().getAlias(request, RequestOptions.DEFAULT);
            Map<String, Set<AliasMetaData>> aliases = response.getAliases();
            aliases.keySet().forEach(e -> {
                Set<AliasMetaData> aliasMetaData = aliases.get(e);
                System.out.println(e + ":" + aliasMetaData.toString());
            });
            return client;
        }

    结果:

    my_source_index2:[{
      "alias222" : { }
    }]

    14.19 Update Indices Settings

     HTTP

    # 更新setting
    PUT /twitter/_settings
    {
        "index" : {
            "number_of_replicas" : 2,
            "refresh_interval" : "1s"
        }
    }

    Java

        /**
         * 更新setting
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient updateSetting() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            // 更新单个
            UpdateSettingsRequest request = new UpdateSettingsRequest("index1");
            // 更新多个
            //UpdateSettingsRequest requestMultiple =
            //        new UpdateSettingsRequest("index1", "index2");
            // 全部更新
            //UpdateSettingsRequest requestAll = new UpdateSettingsRequest();
            Settings settings =
                    Settings.builder()
                            .put("index.number_of_replicas", 2)
                            .build();
            request.settings(settings);
            AcknowledgedResponse updateSettingsResponse =
                    client.indices().putSettings(request, RequestOptions.DEFAULT);
            boolean acknowledged = updateSettingsResponse.isAcknowledged();
            System.out.println(acknowledged);
            return client;
        }

    14.20 Get Settings

     HTTP

    # 获取指定索引的settings
    GET /twitter,kimchy/_settings
    # 获取全部settings
    GET /_all/_settings

    Java

        /**
         * 获取setting
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient getSetting() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetSettingsRequest request = new GetSettingsRequest().indices("china_index");
            GetSettingsResponse getSettingsResponse = client.indices().getSettings(request, RequestOptions.DEFAULT);
            ImmutableOpenMap<String, Settings> settings = getSettingsResponse.getIndexToSettings();
            settings.forEach(e -> {
                System.out.println(e.key);
                Settings value = e.value;
                value.keySet().forEach(k -> {
                    System.out.println(k + ":" + value.get(k));
                });
            });
            return client;
        }

    结果:

    china_index
    index.creation_date:1545294776325
    index.number_of_replicas:1
    index.number_of_shards:1
    index.provided_name:china_index
    index.uuid:LYn6XQ_sRZCazMtweW31ZA
    index.version.created:6050099

    14.21 Put Template & Get Templates

    # 索引模板
    PUT _template/template_1
    {
      "index_patterns": ["te*", "bar*"],
      "settings": {
        "number_of_shards": 1
      },
      "mappings": {
        "my_doc": {
          "_source": {
            "enabled": false
          },
          "properties": {
            "host_name": {
              "type": "keyword"
            },
            "created_at": {
              "type": "date",
              "format": "EEE MMM dd HH:mm:ss Z YYYY"
            }
          }
        }
      }
    }
    # 删除模板
    DELETE /_template/template_1
    # 获取模板
    GET /_template/template_1
    # 获取所有模板
    GET /_template
    # 模板是否存在
    HEAD _template/template_1


    14.22 Validate Query

        public static RestHighLevelClient validateQuery() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            // ValidateQueryRequest需要一个或多个索引来验证查询。如果没有提供索引,则在所有索引上执行请求。
            ValidateQueryRequest request = new ValidateQueryRequest("twitter");
            QueryBuilder builder = QueryBuilders
                    .boolQuery()
                    .must(QueryBuilders.queryStringQuery("*:*"))
                    .filter(QueryBuilders.termQuery("user", "kimchy"));
            request.query(builder);
            request.allShards(true);// 默认情况下,请求只在一个随机选择的分片上执行
            request.explain(true);
            request.rewrite(true);
            ValidateQueryResponse response = client.indices().validateQuery(request, RequestOptions.DEFAULT);
            boolean isValid = response.isValid();
            int totalShards = response.getTotalShards();
            int successfulShards = response.getSuccessfulShards();
            int failedShards = response.getFailedShards();
            System.out.println("isValid:" + isValid + ",totalShards:" + totalShards + ",successfulShards:" + successfulShards + ",failedShards:" + failedShards);
            if (failedShards > 0) {
                for(DefaultShardOperationFailedException failure: response.getShardFailures()) {
                    String failedIndex = failure.index();
                    int shardId = failure.shardId();
                    String reason = failure.reason();
                    System.out.println("failedIndex:" + failedIndex + ",shardId:" + shardId + ",reason:" + reason);
                }
            }
            for(QueryExplanation explanation: response.getQueryExplanation()) {
                String explanationIndex = explanation.getIndex();
                int shardId = explanation.getShard();
                String explanationString = explanation.getExplanation();
                System.out.println("explanationIndex:" + explanationIndex + ",shardId:" + shardId + ",explanationString:" + explanationString);
            }
            return client;
        }

    结果:

    isValid:true,totalShards:5,successfulShards:5,failedShards:0
    explanationIndex:twitter,shardId:0,explanationString:ConstantScore(user:kimchy)
    explanationIndex:twitter,shardId:1,explanationString:ConstantScore(user:kimchy)
    explanationIndex:twitter,shardId:2,explanationString:ConstantScore(user:kimchy)
    explanationIndex:twitter,shardId:3,explanationString:ConstantScore(user:kimchy)
    explanationIndex:twitter,shardId:4,explanationString:ConstantScore(user:kimchy)

    14.23 Get Index

     HTTP

    # 获取所有索引信息
    GET /_all
    # 单个索引信息
    GET /twitter

    Java

        /**
         * 获取索引详细信息
         * @return
         * @throws IOException
         */
        public static RestHighLevelClient getIndex() throws IOException {
            RestHighLevelClient client = RestClientFactory.getInstance().getClient();
            GetIndexRequest request = new GetIndexRequest().indices("_all");    // _all是关键字,列出所有索引信息。也可以是通配符*
            GetIndexResponse indexResponse = client.indices().get(request, RequestOptions.DEFAULT);
    
            // Mappings
            ImmutableOpenMap<String, ImmutableOpenMap<String, MappingMetaData>> mappings = indexResponse.getMappings();
            mappings.forEach(e -> {
                String key = e.key;
                ImmutableOpenMap<String, MappingMetaData> map = e.value;
                System.out.println("Index:" + key);
                map.forEach(n -> {
                    String type = n.key;
                    MappingMetaData metaData = n.value;
                    System.out.println(type + "|" + metaData.getSourceAsMap());
                });
            });
    
            // Aliases
            System.out.println("**********************************");
            ImmutableOpenMap<String, List<AliasMetaData>> aliases = indexResponse.getAliases();
            aliases.forEach(e -> {
                String key = e.key;
                List<AliasMetaData> value = e.value;
                System.out.println("----" + key + "----");
                value.forEach(a -> {
                    System.out.println(a.alias());
                });
            });
            // Settings
            System.out.println("**********************************");
            ImmutableOpenMap<String, Settings> defaultSettings = indexResponse.defaultSettings();
            defaultSettings.forEach(e -> {
                String key = e.key;
                Settings value = e.value;
                System.out.println("----" + key + "----");
                value.keySet().forEach(k -> {
                    System.out.println(k + ":" + value.get(k));
                });
            });
            ImmutableOpenMap<String, Settings> settings = indexResponse.getSettings();
            settings.forEach(e -> {
                String key = e.key;
                Settings value = e.value;
                System.out.println("----" + key + "----");
                value.keySet().forEach(k -> {
                    System.out.println(k + ":" + value.get(k));
                });
            });
            return client;
        }

    结果:

    Index:china_shape_index
    info|{properties={location={precision=100.0m, type=geo_shape}, remark={type=keyword}}}
    Index:china_index
    city|{properties={pName={type=keyword}, cName={type=text}, location={type=geo_point}}}
    Index:books
    java|{properties={title={type=text, fields={keyword={ignore_above=256, type=keyword}}}, user={type=text, fields={keyword={ignore_above=256, type=keyword}}}}}
    Index:my_source_index2
    Index:my_target_index2
    Index:my_source_index
    Index:users
    info|{properties={address={analyzer=ik_max_word, type=text}, age={type=long}, username={type=keyword}}}
    Index:my_target_index
    Index:test
    msg|{properties={message={analyzer=ik_max_word, type=text}}}
    Index:.kibana_1
    doc|{dynamic=strict, properties={server={properties={uuid={type=keyword}}}, visualization={properties={savedSearchId={type=keyword}, description={type=text}, uiStateJSON={type=text}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, visState={type=text}}}, graph-workspace={properties={numVertices={type=integer}, description={type=text}, numLinks={type=integer}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, wsState={type=text}}}, kql-telemetry={properties={optInCount={type=long}, optOutCount={type=long}}}, type={type=keyword}, space={properties={color={type=keyword}, _reserved={type=boolean}, initials={type=keyword}, name={type=text, fields={keyword={ignore_above=2048, type=keyword}}}, description={type=text}}}, url={properties={accessCount={type=long}, accessDate={type=date}, url={type=text, fields={keyword={ignore_above=2048, type=keyword}}}, createDate={type=date}}}, migrationVersion={dynamic=true, type=object}, index-pattern={properties={notExpandable={type=boolean}, fieldFormatMap={type=text}, sourceFilters={type=text}, typeMeta={type=keyword}, timeFieldName={type=keyword}, intervalName={type=keyword}, fields={type=text}, title={type=text}, type={type=keyword}}}, search={properties={hits={type=integer}, columns={type=keyword}, description={type=text}, sort={type=keyword}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}}}, updated_at={type=date}, canvas-workpad={dynamic=false, properties={@created={type=date}, @timestamp={type=date}, name={type=text, fields={keyword={type=keyword}}}, id={index=false, type=text}}}, namespace={type=keyword}, telemetry={properties={enabled={type=boolean}}}, timelion-sheet={properties={hits={type=integer}, timelion_sheet={type=text}, timelion_interval={type=keyword}, timelion_columns={type=integer}, timelion_other_interval={type=keyword}, timelion_rows={type=integer}, description={type=text}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, timelion_chart_height={type=integer}}}, config={dynamic=true, properties={buildNum={type=keyword}}}, dashboard={properties={hits={type=integer}, timeFrom={type=keyword}, timeTo={type=keyword}, refreshInterval={properties={display={type=keyword}, section={type=integer}, value={type=integer}, pause={type=boolean}}}, description={type=text}, uiStateJSON={type=text}, timeRestore={type=boolean}, title={type=text}, version={type=integer}, kibanaSavedObjectMeta={properties={searchSourceJSON={type=text}}}, optionsJSON={type=text}, panelsJSON={type=text}}}}}
    Index:twitter
    t_doc|{properties={msg={type=text, fields={keyword={ignore_above=256, type=keyword}}}, A={type=text, fields={keyword={ignore_above=256, type=keyword}}}, B={type=text, fields={keyword={ignore_above=256, type=keyword}}}, C={type=text, fields={keyword={ignore_above=256, type=keyword}}}, flag={type=text, fields={keyword={ignore_above=256, type=keyword}}}, D={type=text, fields={keyword={ignore_above=256, type=keyword}}}, color={type=text, fields={keyword={ignore_above=256, type=keyword}}}, updateUser={type=text, fields={keyword={ignore_above=256, type=keyword}}}, extMsg={type=text, fields={keyword={ignore_above=256, type=keyword}}}, counter={type=long}, message={type=text, fields={keyword={ignore_above=256, type=keyword}}}, field={type=text, fields={keyword={ignore_above=256, type=keyword}}}, size={type=text, fields={keyword={ignore_above=256, type=keyword}}}, post_date={type=date}, name={type=text, fields={keyword={ignore_above=256, type=keyword}}}, animal={properties={cat={type=text, fields={keyword={ignore_above=256, type=keyword}}}, dog={type=text, fields={keyword={ignore_above=256, type=keyword}}}}}, postDate={type=date}, hate={type=text, fields={keyword={ignore_above=256, type=keyword}}}, favorite={type=text, fields={keyword={ignore_above=256, type=keyword}}}, user={type=text, fields={keyword={ignore_above=256, type=keyword}}}}}
    **********************************
    ----china_shape_index----
    ----.kibana_1----
    .kibana
    ----china_index----
    ----users----
    ----my_source_index----
    ----my_source_index2----
    alias222
    ----my_target_index2----
    my_search_indices
    ----my_target_index----
    my_search_indices
    ----test----
    ----twitter----
    ----books----
    **********************************
    ----my_target_index----
    index.allocation.max_retries:1
    index.blocks.write:true
    index.codec:best_compression
    index.creation_date:1546589354014
    index.number_of_replicas:1
    index.number_of_shards:1
    index.provided_name:my_target_index
    index.resize.source.name:my_source_index
    index.resize.source.uuid:tSYNLldWQNCOlR5NJGaH9g
    index.routing.allocation.initial_recovery._id:wCr6Uz0jTvGaTHh5acNxKA
    index.routing_partition_size:1
    index.shrink.source.name:my_source_index
    index.shrink.source.uuid:tSYNLldWQNCOlR5NJGaH9g
    index.uuid:F976xviGQ965JU9patwQnA
    index.version.created:6050099
    index.version.upgraded:6050099
    ----twitter----
    index.creation_date:1545622508123
    index.number_of_replicas:1
    index.number_of_shards:5
    index.provided_name:twitter
    index.uuid:TLReCXTSSe6tvI7yNveWgw
    index.version.created:6050099
    ----books----
    index.creation_date:1545708244767
    index.number_of_replicas:1
    index.number_of_shards:5
    index.provided_name:books
    index.uuid:leQWEGe8So6B10awTItCNg
    index.version.created:6050099
    ----users----
    index.creation_date:1545967628013
    index.number_of_replicas:1
    index.number_of_shards:1
    index.provided_name:users
    index.uuid:tyxNGtSsThOFDaTBBy7jKQ
    index.version.created:6050099
    ----my_source_index----
    index.blocks.write:true
    index.creation_date:1546589291669
    index.number_of_replicas:2
    index.number_of_shards:4
    index.provided_name:my_source_index
    index.uuid:tSYNLldWQNCOlR5NJGaH9g
    index.version.created:6050099
    ----my_source_index2----
    index.blocks.write:true
    index.creation_date:1546590226265
    index.number_of_replicas:1
    index.number_of_shards:2
    index.provided_name:my_source_index2
    index.uuid:iuDENl3uQku0Ef6flu8S-Q
    index.version.created:6050099
    ----test----
    index.creation_date:1545791918478
    index.number_of_replicas:1
    index.number_of_shards:1
    index.provided_name:test
    index.uuid:qF3UiIqHTLK_X7FSUUhlGw
    index.version.created:6050099
    ----china_shape_index----
    index.creation_date:1545981755548
    index.number_of_replicas:1
    index.number_of_shards:1
    index.provided_name:china_shape_index
    index.uuid:jhwyVqR0RQywyf3n7W0maQ
    index.version.created:6050099
    ----china_index----
    index.creation_date:1545294776325
    index.number_of_replicas:1
    index.number_of_shards:1
    index.provided_name:china_index
    index.uuid:LYn6XQ_sRZCazMtweW31ZA
    index.version.created:6050099
    ----.kibana_1----
    index.auto_expand_replicas:0-1
    index.creation_date:1542353618696
    index.number_of_replicas:0
    index.number_of_shards:1
    index.provided_name:.kibana_1
    index.uuid:IvzG6JhgRJ-GgwTDWmmirQ
    index.version.created:6050099
    ----my_target_index2----
    index.blocks.write:true
    index.creation_date:1546590255143
    index.number_of_replicas:1
    index.number_of_shards:4
    index.provided_name:my_target_index2
    index.resize.source.name:my_source_index2
    index.resize.source.uuid:iuDENl3uQku0Ef6flu8S-Q
    index.routing_partition_size:1
    index.uuid:ZBnocs2bSker45kb2lXoRw
    index.version.created:6050099
    index.version.upgraded:6050099
    
    Process finished with exit code 0



  • 相关阅读:
    java类型与Hadoop类型之间的转换
    Elasticsearch之四种查询类型和搜索原理(博主推荐)
    Eclipse/MyEclipse如何快速提取变量(最强帮手)
    8592 KMP算法
    SDUT 1304-取数字问题(DFS)
    堆排序(小根堆)
    Android显示GIF图片
    HDU 1007 近期点对
    java 显示目录下全部文件
    UVa 11292
  • 原文地址:https://www.cnblogs.com/LUA123/p/10157386.html
Copyright © 2011-2022 走看看