1、概述

  Elasticsearch官方为Java提供了三种客户端API

  • TransportClient:这种方式通过TCP与Elasticsearch服务进行交互。
  • Java Low Level REST Client: 低级别的REST客户端,通过http与集群交互,用户需自己编组请求JSON串,及解析响应JSON串。兼容所有ES版本。
  • Java High Level REST Client: 高级别的REST客户端,基于低级别的REST客户端,增加了编组请求JSON串、解析响应JSON串等相关api。使用的版本需要保持和ES服务端的版本一致,否则会有版本问题。

  官方文档地址: https://artifacts.elastic.co/javadoc/org/elasticsearch/client/elasticsearch-rest-high-level-client/7.4.2/index.html

  在 Elasticsearch 7.0 中不建议使用TransportClient,并且在8.0中会完全删除TransportClient。因此,官方更建议我们用Java High Level REST Client。

The well known TransportClient is deprecated as of Elasticsearch 7 and will be removed in Elasticsearch 8. (see the Elasticsearch documentation). Spring Data Elasticsearch will support the TransportClient as long as it is available in the used Elasticsearch version but has deprecated the classes using it since version 4.0. 

  Spring Data Elasticsearch

  Spring Data Elasticsearch作为Spring Data的一个子项目,封装了对EalsticSearch的客户端,现在最新版本是4.1.1,其内核也是由TransportClient变为在后续版本中采用Java High Level REST Client,其支持版本情况如下:

    

   详情如github所示:https://github.com/spring-projects/spring-data-elasticsearch/blob/master/src/main/asciidoc/preface.adoc

  因此我们就直接采用Java High Level REST Client的Elasticsearch客户端进行学习。

2、开发准备

  高级客户端托管在Maven Central上。所需的最低Java版本是1.8。高级客户端与Elasticsearch的发布周期相同。

  1、Maven 依赖

  下面是使用maven作为依赖管理器配置依赖项。 将以下内容添加到您的pom.xml文件中:

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.9.2</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.9.2</version>
</dependency>

  2、Dependencies

  高级客户端依赖于以下部件及其传递依赖关系:

  • org.elasticsearch.client: elasticsearch-rest-client
  • org.elasticsearch: elasticsearch

  3、初始化

RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http"),
                new HttpHost("localhost", 9201, "http")));

  高级客户端内部会创建低级客户端用于基于提供的builder执行请求。低级客户端维护一个连接池,并启动一些线程,因此当你用完以后应该关闭高级客户端,并且在内部它将会关闭低级客户端,以释放这些资源。关闭客户端可以使用close()方法:

client.close();

 3、API文档

  3.1、索引管理

  3.1.1、添加索引

public void createIndex() {
    CreateIndexRequest request = new CreateIndexRequest("testindex");
    request.settings(
            Settings.builder().put("index.analysis.analyzer.default.type", "ik_max_word")
                    .put("number_of_shards", 5)
                    .put("number_of_replicas", 1)
                    .put("refresh_interval", "30s"));
    request.mapping("{\"properties\":{\"testId\":{\"type\":\"text\",\"store\":false,\"index\":true" +
                    ",\"analyzer\":\"standard\"},\"testName\":{\"type\":\"text\",\"store\":false,\"index\":true}" +
                    ",\"testDesc\":{\"type\":\"text\",\"store\":false,\"index\":true}}}"
            , XContentType.JSON);
    // 为索引设置一个别名
    request.alias(new Alias("test_alias"));
    // 超时,等待所有节点被确认(使用TimeValue方式)
    request.setTimeout(TimeValue.timeValueNanos(1000));

    // 连接master节点的超时时间(使用TimeValue方式)
    request.setMasterTimeout(TimeValue.timeValueSeconds(2));

    // 在创建索引API返回响应之前等待的活动分片副本的数量,以int形式表示。
    request.waitForActiveShards(ActiveShardCount.from(1));
    // 在创建索引API返回响应之前等待的活动分片副本的数量,以ActiveShardCount形式表示。
    // request.waitForActiveShards(ActiveShardCount.ONE);

    //同步执行
    CreateIndexResponse createIndexResponse = client.indices().create(request,RequestOptions.DEFAULT);

    /***
     * 异步执行:创建索引请求需要将CreateIndexRequest实例和ActionListener实例传递给异步方法:
     * CreateIndexResponse的典型监听器如下所示:
     * 异步方法不会阻塞并立即返回。
    ActionListener<CreateIndexResponse> listener = new ActionListener<CreateIndexResponse>() {
        @Override
        public void onResponse(CreateIndexResponse createIndexResponse) {
            //如果执行成功,则调用onResponse方法;
        }
        @Override
        public void onFailure(Exception e) {
            //如果失败,则调用onFailure方法。
        }
    };
    client.indices().createAsync(request, listener);//要执行的CreateIndexRequest和执行完成时要使用的ActionListener
    */
    //返回的CreateIndexResponse允许检索有关执行的操作的信息,如下所示:
    // 指示是否所有节点都已确认请求
    boolean acknowledged = createIndexResponse.isAcknowledged();
    // 指示是否在超时之前为索引中的每个分片启动了必需的分片副本数
    boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();
    System.out.println("acknowledged:"+acknowledged+"; shardsAcknowledged:"+shardsAcknowledged);
}

  3.1.2、删除索引

public void deleteIndex() {
    DeleteIndexRequest request = new DeleteIndexRequest("testindex");//指定要删除的索引名称
    //可选参数:
    request.timeout(TimeValue.timeValueMinutes(2)); //设置超时,等待所有节点确认索引删除(使用TimeValue形式)
    // request.timeout("2m"); //设置超时,等待所有节点确认索引删除(使用字符串形式)

    request.masterNodeTimeout(TimeValue.timeValueMinutes(1));////连接master节点的超时时间(使用TimeValue方式)
    // request.masterNodeTimeout("1m");//连接master节点的超时时间(使用字符串方式)

    //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
    request.indicesOptions(IndicesOptions.lenientExpandOpen());

    //同步执行
    AcknowledgedResponse deleteIndexResponse = client.indices().delete(request, RequestOptions.DEFAULT);

    /**
     * 异步执行删除索引请求需要将DeleteIndexRequest实例和ActionListener实例传递给异步方法:DeleteIndexResponse的典型监听器如下所示:
     * 异步方法不会阻塞并立即返回。
     ActionListener<DeleteIndexResponse> listener = new ActionListener<DeleteIndexResponse>() {
    @Override public void onResponse(DeleteIndexResponse deleteIndexResponse) {
    //如果执行成功,则调用onResponse方法;
    }

    @Override public void onFailure(Exception e) {
    //如果失败,则调用onFailure方法。
    }
    };
     * 异步执行删除索引请求需要将DeleteIndexRequest实例和ActionListener实例传递给异步方法:
     client.indices().deleteAsync(request, listener);
     */
    //Delete Index Response
    //返回的DeleteIndexResponse允许检索有关执行的操作的信息,如下所示:
    boolean acknowledged = deleteIndexResponse.isAcknowledged();//是否所有节点都已确认请求

    //如果找不到索引,则会抛出ElasticsearchException:
    try {
        request = new DeleteIndexRequest("does_not_exist");
        client.indices().delete(request,RequestOptions.DEFAULT);
    } catch (ElasticsearchException exception) {
        if (exception.status() == RestStatus.NOT_FOUND) {
            //如果没有找到要删除的索引,要执行某些操作
        }
    }
}

  3.1.3、关闭索引

  针对部分索引,我们暂时不需要对其进行读写,可以临时关闭索引,以减少es服务器的开销。

public void closeIndex(){
    //关闭索引
    CloseIndexRequest request = new CloseIndexRequest("testindex");
    //可选参数:
    //设置超时,等待所有节点确认索引已关闭(使用TimeValue形式)
    request.setTimeout(TimeValue.timeValueMinutes(2));

    //连接master节点的超时时间(使用TimeValue方式)
    request.setMasterTimeout(TimeValue.timeValueMinutes(1));

    //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
    request.indicesOptions(IndicesOptions.lenientExpandOpen());
    //同步执行
    CloseIndexResponse closeIndexResponse = client.indices().close(request,RequestOptions.DEFAULT);

    /** 异步执行打开索引请求需要将CloseIndexRequest实例和ActionListener实例传递给异步方法:
     * CloseIndexResponse的典型监听器如下所示:
     * 异步方法不会阻塞并立即返回。
        ActionListener<CloseIndexResponse> listener = new ActionListener<CloseIndexResponse>() {
            @Override
            public void onResponse(CloseIndexResponse closeIndexResponse) {
                 //如果执行成功,则调用onResponse方法;
            }

            @Override
            public void onFailure(Exception e) {
                 //如果失败,则调用onFailure方法。
            }
        };
        client.indices().closeAsync(request, listener);
     */

    //返回的CloseIndexResponse 允许检索有关执行的操作的信息,指示是否所有节点都已确认请求:
    boolean acknowledged = closeIndexResponse.isAcknowledged();
}

  3.1.4、打开索引

public void openIndex(){
    //关闭索引
    OpenIndexRequest request = new OpenIndexRequest("testindex");
    //可选参数:
    //在打开索引API返回响应之前等待的活动分片副本的数量,以int形式表示。
    request.waitForActiveShards(1);
    //在打开索引API返回响应之前等待的活动分片副本的数量,以ActiveShardCount形式表示。
    //request.waitForActiveShards(ActiveShardCount.ONE);

    //设置IndicesOptions控制如何解决不可用的索引以及如何扩展通配符表达式
    request.indicesOptions(IndicesOptions.strictExpandOpen());

    //同步执行
    OpenIndexResponse openIndexResponse = client.indices().open(request,RequestOptions.DEFAULT);

    /** 异步执行打开索引请求需要将CloseIndexRequest实例和ActionListener实例传递给异步方法:
     * CloseIndexResponse的典型监听器如下所示:
     * 异步方法不会阻塞并立即返回。
         ActionListener<CloseIndexResponse> listener = new ActionListener<CloseIndexResponse>() {
            @Override
            public void onResponse(CloseIndexResponse closeIndexResponse) {
                //如果执行成功,则调用onResponse方法;
            }

            @Override
            public void onFailure(Exception e) {
                //如果失败,则调用onFailure方法。
            }
            };
         client.indices().closeAsync(request, listener);
     */

    //返回的CloseIndexResponse 允许检索有关执行的操作的信息,指示是否所有节点都已确认请求:
    boolean acknowledged = openIndexResponse.isAcknowledged();
}

  3.2、文档管理

  3.2.1、添加文档

public void createDocument(){
    IndexRequest indexRequest1 = new IndexRequest("testindex").id(generateId());

    //==============================提供文档源========================================
    //方式1:以字符串形式提供
    String jsonString = "{\"testId\":\"json\",\"testName\":\"你猜不到的名字\",\"testDesc\":\"这是一条新闻描述\"}";
    indexRequest1.source(jsonString, XContentType.JSON);

    //方式2:以Map形式提供
    Map<String, Object> jsonMap = new HashMap<>();
    jsonMap.put("testId", "jsonMap");
    jsonMap.put("testName", "你猜不到的名字");
    jsonMap.put("testDesc", "这是一条新闻描述");
    //Map会自动转换为JSON格式的文档源
    IndexRequest indexRequest2 = new IndexRequest("testindex").source(jsonMap);

    // 方式3:文档源以XContentBuilder对象的形式提供,Elasticsearch内部会帮我们生成JSON内容
    XContentBuilder builder = XContentFactory.jsonBuilder();
    builder.startObject();
    builder.field("testId", "builder");
    builder.field("testName", "你猜不到的名字");
    builder.field("testDesc", "这是一条新闻描述");
    builder.endObject();
    IndexRequest indexRequest3 = new IndexRequest("testindex").id(generateId()).source(builder);

    //方式4:以Object key-pairs提供的文档源,它会被转换为JSON格式
    IndexRequest indexRequest4 = new IndexRequest("testindex")
            .id(UUID.randomUUID().toString().replaceAll("-", ""))
            .source("testId", "Object key-pairs",
                    "testName", "你猜不到的名字",
                    "testDesc", "这是一条新闻描述");

    //===============================可选参数start====================================
    //设置路由值
    // indexRequest1.routing("routing");

    //设置超时:等待主分片变得可用的时间:TimeValue方式
    indexRequest1.timeout(TimeValue.timeValueSeconds(1));
    // indexRequest1.timeout("1s"); //字符串方式

    //刷新策略:WriteRequest.RefreshPolicy实例方式
    indexRequest1.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
    // indexRequest1.setRefreshPolicy("wait_for");//字符串方式

    // indexRequest1.version(2);//设置版本

    // indexRequest1.versionType(VersionType.INTERNAL);//设置版本类型

    //操作类型:DocWriteRequest.OpType方式
    indexRequest1.opType(DocWriteRequest.OpType.CREATE);
    // indexRequest1.opType("create");//字符串方式, 可以是 create 或 update (默认)

    // The name of the ingest pipeline to be executed before indexing the document
    // indexRequest1.setPipeline("pipeline");

    //===============================执行====================================
    //同步执行
    IndexResponse indexResponse = client.index(indexRequest1, RequestOptions.DEFAULT);

    //异步执行:异步方法不会阻塞并立即返回,IndexResponse 的典型监听器如下所示:
    ActionListener<IndexResponse> listener = new ActionListener<IndexResponse>() {
        @Override
        public void onResponse(IndexResponse indexResponse) {
            //执行成功时调用。 Response以参数方式提供
        }

        @Override
        public void onFailure(Exception e) {
            //在失败的情况下调用。 引发的异常以参数方式提供
        }
    };
    //异步执行索引请求需要将IndexRequest实例和ActionListener实例传递给异步方法:
    client.indexAsync(indexRequest2, RequestOptions.DEFAULT, listener);

    //Index Response:返回的IndexResponse允许检索有关执行操作的信息,如下所示:
    String index = indexResponse.getIndex();
    String type = indexResponse.getType();
    String id = indexResponse.getId();
    long version = indexResponse.getVersion();
    if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
        //处理(如果需要)第一次创建文档的情况
    } else if (indexResponse.getResult() == DocWriteResponse.Result.UPDATED) {
        //处理(如果需要)文档被重写的情况
    }
    ReplicationResponse.ShardInfo shardInfo = indexResponse.getShardInfo();
    if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
        //处理成功分片数量少于总分片数量的情况
    }
    if (shardInfo.getFailed() > 0) {
        for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
            String reason = failure.reason();//处理潜在的失败
        }
    }

    //如果存在版本冲突,则会抛出ElasticsearchException:
    IndexRequest request = new IndexRequest("posts", "doc", "1")
            .source("field", "value")
            .version(1);
    try {
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
    } catch(ElasticsearchException e) {
        if (e.status() == RestStatus.CONFLICT) {
            //引发的异常表示返回了版本冲突错误
        }
    }

    //如果opType设置为创建但是具有相同索引,类型和ID的文档已存在,则也会发生同样的情况:
    request = new IndexRequest("posts", "doc", "1")
            .source("field", "value")
            .opType(DocWriteRequest.OpType.CREATE);
    try {
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
    } catch(ElasticsearchException e) {
        if (e.status() == RestStatus.CONFLICT) {
            //引发的异常表示返回了版本冲突错误
        }
    }
}

  插入测试结果如下:

  

  由于所有文档的异步操作

  3.2.2、文档是否存在

public void exists(){
    GetRequest getRequest = new GetRequest("testindex").id("e749eada74ca4ded8232bf1fcf65585e");
    // 禁止获取_source
    getRequest.fetchSourceContext(new FetchSourceContext(false));
    // 禁止获取存储字段
    getRequest.storedFields("_none_");
    boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
    System.out.println(getRequest.index() + "---" + getRequest.id() + "---文档是否存在:" + exists);
}
//异步执行获取索引请求需要将GetRequest  实例和ActionListener实例传递给异步方法:
client.existsAsync(request, listener);

  3.2.3、删除文档

public void deleteDocument() {
    DeleteRequest deleteRequest = new DeleteRequest("testindex").id("51dfb91a9d5c405f979");
    client.delete(deleteRequest, RequestOptions.DEFAULT);
    System.out.println(deleteRequest.index() + "---" + deleteRequest.id() + ": 文档已删除");
}
//异步执行获取索引请求需要将DeleteRequest  实例和ActionListener实例传递给异步方法:
client.deleteAsync(request, listener);

  3.2.4、更新文档

  3.2.4.1、局部更新

public void updateDocumentPart(){
    // 方式1:使用Map形式,会被自动转为json格式
    Map<String, Object> jsonMap = new HashMap<>();
    jsonMap.put("testId", "jsonMap2(新的类型)");
    jsonMap.put("testDesc", "这是一条新闻描述2(新的描述)");
    UpdateRequest request = new UpdateRequest("testindex", "Q0su_nUB4hs2I-RuESpC").doc(jsonMap);
    UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");

    // 方式2:使用字符串形式
    String jsonString = "{\"testId\":\"testIdNew\",\"testName\":\"testNameNew\"}";
    request = new UpdateRequest("testindex", "Q0su_nUB4hs2I-RuESpC").doc(jsonString, XContentType.JSON);
    response = client.update(request, RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");

    // 方式3:使用XContentBuilder形式
    XContentBuilder builder = XContentFactory.jsonBuilder();
    builder.startObject();
    {
        builder.field("testId", "使用XContentBuilder形式");
        builder.field("testName", "使用XContentBuilder形式 update");
    }
    builder.endObject();
    request = new UpdateRequest("testindex", "Q0su_nUB4hs2I-RuESpC").doc(builder);
    response = client.update(request, RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");

    //方式4:使用Object key-pairs形式
    request = new UpdateRequest("testindex","Q0su_nUB4hs2I-RuESpC")
            .doc("testId", "Object key-pairs",
                    "testDesc", "Object key-pairs update");
    response = client.update(request, RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");
}

  3.2.4.1、全部更新

    //为内联脚本提供参数
    Map<String, Object> parameters = singletonMap("testDesc", "内联脚本");

    //方式1:使用painless语言和上面的参数创建一个内联脚本
    Script inline = new Script(ScriptType.INLINE, "painless", "ctx._source.field += params.count", parameters);
    UpdateRequest request = new UpdateRequest("testindex", "REsu_nUB4hs2I-RuESpD").script(inline);
    UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");


    //方式2:引用名称为increment-field的脚本,改脚本定义的位置还没搞清楚。
    Script stored =
            new Script(ScriptType.STORED, null, "increment-field", parameters);
    request = new UpdateRequest("testindex", "RUsu_nUB4hs2I-RuESpD").script(stored);
    response = client.update(request, RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");
}

  ES的全部更新和局部更新,底层有什么区别?

  答:全部更新,是直接把之前的老数据,标记为删除状态,然后,再添加一条更新的;局域更新,只是修改某个字段。

  3.2.4.3、更新不存在则插入upsert

public void updateDocumentInsert(){
    //如果文档尚不存在,则可以使用upsert方法定义一些将作为新文档插入的内容:
    //与部分文档更新类似,可以使用接受String,Map,XContentBuilder或Object key-pairs的方式来定义upsert文档的内容。
    Map<String, Object> jsonMap = new HashMap<>();
    jsonMap.put("testId", "jsonMap2(新的类型)");
    jsonMap.put("testDesc", "这是一条新闻描述2(新的描述)");
    UpdateRequest request = new UpdateRequest("testindex", "updateDocumentInsert").docAsUpsert(true).doc(jsonMap);
    UpdateResponse response = client.update(request,RequestOptions.DEFAULT);
    System.out.println(response.getIndex() + "---" + response.getId() + "完成更新");
}
//异步执行获取索引请求需要将UpdateRequest  实例和ActionListener实例传递给异步方法:
client.updateAsync(request, listener);

  3.2.5、批量更新文档

public void bulk() {
    BulkRequest request = new BulkRequest();
    request.add(new IndexRequest("testindex")
            .source(XContentType.JSON, "testId", "foo", "testName", "lucky", "testDesc", "qwer"));
    request.add(new IndexRequest("testindex")
            .source(XContentType.JSON, "testId", "bar", "testName", "Jon", "testDesc", "sadasd"));
    request.add(new IndexRequest("testindex")
            .source(XContentType.JSON, "testId", "baz", "testName", "Lucy", "testDesc", "zxczx"));
    // id为10的不存在
    request.add(new DeleteRequest("testindex", "4eb9eaeb9522495e954"));
    request.add(new UpdateRequest("testindex", "e749eada74ca4ded8232bf1fcf65585e")
            .doc(XContentType.JSON, "testId", "12312313", "testName", "1221312", "testDesc", "435345353"));
    BulkResponse bulkResponse = null;
    bulkResponse = client.bulk(request, RequestOptions.DEFAULT);
    // 获取执行状态
    System.out.println("批量更新结果状态:" + bulkResponse.status());
}
public final Cancellable bulkAsync(BulkRequest bulkRequest, RequestOptions options, ActionListener<BulkResponse> listener) {
    return this.performRequestAsyncAndParseEntity((ActionRequest)bulkRequest, RequestConverters::bulk, options, 
          BulkResponse::fromXContent, listener, Collections.emptySet()); }

  3.3、文档搜索

  3.3.1、获取一个文档

public void getDocument(){
    GetRequest getRequest = new GetRequest("testindex", "e749eada74ca4ded8232bf1fcf65585e");
    GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
    String index = getResponse.getIndex();
    String id = getResponse.getId();
    if (getResponse.isExists()) {
        long version = getResponse.getVersion();
        String sourceAsString = getResponse.getSourceAsString();
        Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
        byte[] sourceAsBytes = getResponse.getSourceAsBytes();

        System.out.println("索引:" + index + ",ID:" + id + "版本:" + version);
        System.out.println(sourceAsString);
        System.out.println(sourceAsMap);
        System.out.println(sourceAsBytes.toString());
    } else {
        System.out.println("未查到结果");
    }
}
//异步执行获取索引请求需要将GetRequest 实例和ActionListener实例传递给异步方法:
client.getAsync(getRequest, listener);

  3.3.2、批量查询

public void getBulk(){
    MultiGetRequest request = new MultiGetRequest();
    request.add(new MultiGetRequest.Item("testindex", "e749eada74ca4ded8232bf1fcf65585e"));
    request.add(new MultiGetRequest.Item("testindex", "RUsu_nUB4hs2I-RuESpD"));
    request.add(new MultiGetRequest.Item("testindex", "Q0su_nUB4hs2I"));

    MultiGetResponse responses = null;
    try {
        responses = client.mget(request, RequestOptions.DEFAULT);
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 打印查詢結果
    System.out.println("MultiGetResponse:");
    responses.forEach(item -> System.out.println(item.getResponse().getSourceAsString()));
}
//异步执行获取索引请求需要将GetRequest 实例和ActionListener实例传递给异步方法:
client.mgetAsync(getRequest, listener);

  3.3.3、高亮查询

public void highLightSearch(){
    //条件搜索
    SearchRequest searchRequest = new SearchRequest("testindex");
    SearchSourceBuilder builder = new SearchSourceBuilder();
    //分页
    builder.from(1);
    builder.size(5);

    TermQueryBuilder title = QueryBuilders.termQuery("testDesc", "新闻");
    builder.query(title);
    builder.timeout(new TimeValue(60, TimeUnit.SECONDS));

    HighlightBuilder highlightBuilder = new HighlightBuilder();
    //高亮的字段
    highlightBuilder.field("testDesc");
    //是否多个字段都高亮
    highlightBuilder.requireFieldMatch(false);
    //前缀后缀
    highlightBuilder.preTags("<span style='color:red'>");
    highlightBuilder.postTags("</span>");
    builder.highlighter(highlightBuilder);

    //执行搜索
    searchRequest.source(builder);
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    //解析结果
    ArrayList<Map<String,Object>> list = new ArrayList<>();
    for (SearchHit hit : searchResponse.getHits().getHits()) {
        //解析高亮的字段
        //获取高亮字段
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        System.out.println("highlightFields=========="+"\n"+highlightFields);
        HighlightField testDesc = highlightFields.get("testDesc");
        System.out.println("testDesc=========="+"\n"+testDesc);
        //原来的结果
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        //将原来的字段替换为高亮字段即可
        if (testDesc!=null){
            Text[] fragments = testDesc.fragments();
            String newTitle = "";
            for (Text text : fragments) {
                newTitle +=text;
            }
            //替换掉原来的内容
            sourceAsMap.put("testDesc",newTitle);
        }
        list.add(sourceAsMap);
    }
    System.out.println("搜索结果:总共"+list.size()+"条,分别是:"+list);
}
//异步执行获取索引请求需要将GetRequest 实例和ActionListener实例传递给异步方法:
client.searchAsync(getRequest, listener);

  3.3.4、复合查询

  待补充

posted on 2020-11-27 03:22  kosamino  阅读(454)  评论(0编辑  收藏  举报