RestHighLevelClient 7.10.0

RestHighLevelClient 是全局单例类,核心参数决定连接稳定性和性能

一、客户端初始化及参数

参数名含义默认值生产建议值注意事项
connectTimeout连接 ES 节点的超时时间(TCP 握手阶段)1000ms3000ms过小易因网络抖动失败,过大导致连接等待时间过长
socketTimeout数据传输超时时间(请求发送后等待响应的时间)30000ms60000ms复杂查询 / 大批量数据需调大(如 Bulk 批量写入、深度聚合)
connectionRequestTimeout从连接池获取连接的超时时间500ms5000ms连接池满时,超过该时间会抛连接超时异常
maxConnTotal客户端最大连接数(所有 ES 节点共享)20100-200按 QPS 调整,QPS 1000+ 建议 200
maxConnPerRoute单个 ES 节点的最大连接数1050-100避免单个节点连接数过多导致服务端限流
《初始化示例Demo》
@Bean
    public RestHighLevelClient esRestClient(){
        //创建RestHighLevelClient客户端
        RestClientBuilder builder = RestClient.builder(new HttpHost(hostname, port, scheme));
​
        // 认证配置(无密码则跳过)
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(userName, password));  //es账号密码
​
        // 连接池配置
        builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                if (maxConnectNum != null && maxConnectNumPerRoute != null) {
                    httpClientBuilder.setMaxConnTotal(maxConnectNum); // 最大总连接数
                    httpClientBuilder.setMaxConnPerRoute(maxConnectNumPerRoute); // 单节点最大连接数
                }
                httpClientBuilder.disableAuthCaching();
                return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
        });
​
        // 请求配置(超时参数)
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            if (connectTimeout != null && socketTimeout != null && connectionRequestTimeout != null) {
                requestConfigBuilder.setConnectTimeout(connectTimeout); // 连接超时
                requestConfigBuilder.setSocketTimeout(socketTimeout); // 传输超时
                requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout); // 连接池获取超时
            }
            return requestConfigBuilder;
        });
        return new RestHighLevelClient(builder);
    }

二、索引操作核心类

1. CreateIndexRequest(创建索引)

核心作用

创建 ES 索引,支持配置分片、副本、Mapping、索引级参数(如刷新间隔)。

关键参数 / 方法
方法 / 参数含义默认值生产建议
settings(Settings)设置索引级别参数(分片、副本、刷新间隔)-必配:分片数 3-8,副本数 1-2
mapping(XContentBuilder)配置索引 Mapping(字段类型、分词器)动态映射禁用动态映射,手动配置所有字段
alias(String)为索引设置别名-按时间分索引时必用(如 order_info_202602 → alias: order_info)
settings的相关参数
  • number_of_shards :主分片数(生产 3-8)

  • number_of_replicas :副本数(生产 1-2)

  • refresh_interval :刷新间隔(写入密集调大)

  • index.query.bool.max_clause_count :布尔查询最大子句数

  • index.mapping.total_fields.limit :最大字段数限制

mapping的参数

XContentBuilder 是 Elasticsearch Java 客户端中构建结构化 JSON 数据的核心工具,主要用于:

  • 构建 ES 文档内容(新增 / 更新文档时的 JSON 数据);
  • 构建索引 Mapping 配置(定义字段类型、分词器、格式等);
  • 构建索引设置(分片、副本、刷新间隔等);
  • 替代手动拼接 JSON 字符串(避免语法错误、JSON 注入、格式不规范等问题)
XContentBuilder核心特性
  • 流式 API:支持链式调用,代码简洁且易维护;
  • 类型安全:自动处理 JSON 格式(如引号、逗号、花括号配对),避免手动拼接的语法错误;
  • 多格式支持:默认构建 JSON 格式,也支持 Smile(二进制 JSON)、YAML 等格式(生产仅用 JSON);
  • UTF-8 编码:默认采用 UTF-8 编码,兼容中文等多语言。
初始化方式
方法含义适用场景
XContentFactory.jsonBuilder()创建 JSON 格式的 XContentBuilder核心方法(推荐使用)
XContentFactory.smileBuilder()二进制 JSON 格式高性能二进制传输(极少用)
XContentFactory.yamlBuilder()YAML 格式配置文件解析(非 ES 交互)
XContentFactory.cborBuilder()CBOR 二进制格式小众场景
方法
方法含义参数说明使用场景
startObject()开启一个空的 JSON 对象({}根对象 / 嵌套对象的起始
startObject(String fieldName)开启指定字段名的嵌套 JSON 对象(如 "order_items": {}fieldName:嵌套对象字段名文档中的嵌套对象(如订单项)
endObject()关闭当前 JSON 对象startObject() 成对关闭
startArray(String fieldName)开启指定字段名的 JSON 数组(如 "order_items": []fieldName:数组字段名文档中的数组(如多订单项、多标签)
endArray()关闭当前 JSON 数组startArray() 成对关闭
XContentBuilder实例Demo
XContentBuilder builder = XContentFactory.jsonBuilder()
        .startObject() // 根对象开始
            .startObject("user_info") // 嵌套对象开始
                .field("name", "张三")
                .field("age", 25)
            .endObject() // 嵌套对象结束
            .startArray("tags") // 数组开始
                .value("VIP") // 数组元素
                .value("新用户")
            .endArray() // 数组结束
        .endObject(); // 根对象结束
field中常用的参数
参数名含义适用字段类型取值范围默认值
type字段类型所有字段keyword/text/date/double/nested 等-
analyzer索引时分词器text 字段standard:ES 默认分词器,按空格 / 标点拆分,英文小写化,中文单字拆分

默认值

ik_max_word:IK 分词器 - 细粒度拆分(如 “华为 Mate60” 拆为 “华为、Mate60、Mate、60”)
ik_smart:IK 分词器 - 粗粒度拆分(如 “华为 Mate60” 拆为 “华为、Mate60”)
whitespace :仅按空格拆分,不小写化,不拆分标点
keyword :不分词(整个字段作为一个词条)
pattern :按正则表达式拆分                
search_analyzer搜索时分词器analyzer 取值相同
format日期格式date 字段yyyy-MM-dd HH:mm:ss/epoch_millis 等epoch_millis
ignore_above超过长度不索引keyword 字段1-327662147483647
dynamic是否开启动态映射根对象 /propertiestrue/false/stricttrue
fields多字段配置(如 text+keyword)text/keyword 字段--
null_value空值替代值keyword 字段任意字符串null
enabled是否启用字段(禁用后不索引 / 存储)所有字段true/falsetrue
《创建索引示例Demo》
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.client.RestHighLevelClient;

import java.io.IOException;

/**
 * CreateIndexRequest 完整 Demo
 */
public class IndexOperationDemo {
    private final RestHighLevelClient client;
    // 索引名(按时间分索引)
    private static final String INDEX_NAME = "order_info_202602";
    // 索引别名
    private static final String INDEX_ALIAS = "order_info";

    public IndexOperationDemo(RestHighLevelClient client) {
        this.client = client;
    }

    public void createOrderIndex() throws IOException {
        // 1. 检查索引是否已存在
        if (client.indices().exists(new GetIndexRequest(INDEX_NAME), RequestOptions.DEFAULT)) {
            System.out.println("索引已存在:" + INDEX_NAME);
            return;
        }

        // 2. 构建创建索引请求
        CreateIndexRequest request = new CreateIndexRequest(INDEX_NAME);

        // 3. 设置索引级别参数(核心)
        request.settings(Settings.builder()
                .put("number_of_shards", 3)          // 主分片数(生产 3-8)
                .put("number_of_replicas", 1)        // 副本数(生产 1-2)
                .put("refresh_interval", "5s")       // 刷新间隔(写入密集调大)
                .put("index.query.bool.max_clause_count", 2048) // 布尔查询最大子句数
                .put("index.mapping.total_fields.limit", 1000)); // 最大字段数限制

        // 4. 配置 Mapping(禁用动态映射,手动配置所有字段)
        XContentBuilder mapping = XContentFactory.jsonBuilder()
                .startObject()
                    .field("dynamic", false) // 禁用动态映射(核心!避免字段类型混乱)
                    .startObject("properties")
                        // 订单号:精准匹配,不分词
                        .startObject("order_id")
                            .field("type", "keyword")
                        .endObject()
                        // 用户ID:精准匹配
                        .startObject("user_id")
                            .field("type", "keyword")
                        .endObject()
                        // 订单金额:数值类型(支持范围查询)
                        .startObject("amount")
                            .field("type", "double")
                        .endObject()
                        // 创建时间:日期类型(支持范围/排序)
                        .startObject("create_time")
                            .field("type", "date")
                            .field("format", "yyyy-MM-dd HH:mm:ss||epoch_millis")
                        .endObject()
                        // 订单备注:分词+精准双字段
                        .startObject("order_remark")
                            .field("type", "text")
                            .field("analyzer", "ik_max_word") // 中文分词
                            .startObject("fields")
                                .startObject("keyword") // 精准匹配子字段
                                    .field("type", "keyword")
                                    .field("ignore_above", 256) // 超过256字符不索引
                                .endObject()
                            .endObject()
                        .endObject()
                        // 订单项:嵌套类型(1:N 关联)
                        .startObject("order_items")
                            .field("type", "nested") // 嵌套类型(查询需用 nested 查询)
                            .startObject("properties")
                                .startObject("sku_id")
                                    .field("type", "keyword")
                                .endObject()
                                .startObject("sku_name")
                                    .field("type", "text")
                                    .field("analyzer", "ik_max_word")
                                .endObject()
                            .endObject()
                        .endObject()
                    .endObject()
                .endObject();
        request.mapping(mapping);

        // 5. 设置索引别名(屏蔽分索引细节)
        request.alias(INDEX_ALIAS);

        // 6. 执行创建
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        if (response.isAcknowledged()) {
            System.out.println("索引创建成功:" + INDEX_NAME + ",别名:" + INDEX_ALIAS);
        } else {
            System.out.println("索引创建失败:" + INDEX_NAME);
        }
    }
}

2. DeleteIndexRequest(删除索引)

核心作用

删除指定索引,支持批量删除(多个索引用逗号分隔)。

关键参数
方法含义注意事项
DeleteIndexRequest(String)指定要删除的索引名支持通配符(如 order_info_*),慎用!
《删除索引示例Demo》
/**
 * DeleteIndexRequest Demo
 */
public void deleteIndex(String indexName) throws IOException {
    // 1. 检查索引是否存在
    if (!client.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT)) {
        System.out.println("索引不存在:" + indexName);
        return;
    }
    // 2. 构建删除请求
    DeleteIndexRequest request = new DeleteIndexRequest(indexName);
    // 3. 执行删除
    client.indices().delete(request, RequestOptions.DEFAULT);
    System.out.println("索引删除成功:" + indexName);
}

三、文档操作核心类(Document)

1. IndexRequest(新增单条文档)

核心作用

新增 / 更新单条文档(指定 ID 时,存在则更新,不存在则新增)。

关键参数 / 方法
方法 / 参数含义默认值生产建议
id(String)文档 ID(业务唯一键,如订单号)自动生成必配!保证幂等性,避免重复数据
routing(String)路由键(将文档路由到指定分片)-按用户 ID / 商户 ID 路由,提升查询性能
refreshPolicy(String)刷新策略"wait_for"批量写入设为 "false",减少 IO
source(XContentBuilder)文档内容-仅传入查询所需字段,减少存储
刷新策略说明
策略值含义适用场景
"immediate"立即刷新(同步)实时性要求极高的场景(如秒杀)
"wait_for"等待下一次刷新(默认)常规场景
"false"不立即刷新,由索引 refresh_interval 控制批量写入、非实时场景
《新增文档示例Demo》
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;

/**
 * IndexRequest Demo(新增单条文档)
 */
public void addSingleDoc() throws IOException {
    String docId = "ORDER20260212001"; // 文档ID=订单号
    String userId = "10086";           // 路由键=用户ID

    // 1. 构建文档内容
    XContentBuilder doc = XContentFactory.jsonBuilder()
            .startObject()
                .field("order_id", docId)
                .field("user_id", userId)
                .field("amount", 199.99)
                .field("create_time", "2026-02-12 10:00:00")
                .field("order_remark", "加急发货")
                // 嵌套对象
                .startArray("order_items")
                    .startObject()
                        .field("sku_id", "SKU1001")
                        .field("sku_name", "华为Mate60")
                        .field("price", 199.99)
                        .field("quantity", 1)
                    .endObject()
                .endArray()
            .endObject();

    // 2. 构建新增请求
    IndexRequest request = new IndexRequest(INDEX_NAME)
            .id(docId)                          // 文档ID(业务唯一键)
            .routing(userId)                    // 路由到用户ID分片
            .refreshPolicy("false")             // 不立即刷新
            .source(doc);

    // 3. 执行新增
    IndexResponse response = client.index(request, RequestOptions.DEFAULT);
    // 结果枚举:CREATED(新增)、UPDATED(更新)
    System.out.println("文档新增结果:" + response.getResult());
    System.out.println("文档版本号:" + response.getVersion()); // ES 版本号(乐观锁)
}

2. BulkRequest(批量文档操作)

核心作用

批量执行新增 / 更新 / 删除文档操作,减少网络请求,提升写入性能。

方法 / 参数含义默认值生产建议
add(IndexRequest/UpdateRequest/DeleteRequest)添加单条操作请求-每批 500-1000 条(最优性能)
setRefreshPolicy(String)刷新策略"wait_for"设为 "false",减少 IO
timeout(TimeValue)批量操作超时时间1m大批量(>1000 条)设为 5m
setPipeline(String)指定数据处理管道(如脱敏、格式转换)-敏感数据写入前脱敏
《批量新增文档示例Demo》
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;

import java.util.ArrayList;
import java.util.List;

/**
 * BulkRequest Demo(批量新增)
 */
public void batchAddDocs() throws IOException {
    BulkRequest bulkRequest = new BulkRequest();
    // 批量大小建议:500-1000 条
    int batchSize = 500;

    // 模拟批量数据
    List<OrderDoc> orderList = new ArrayList<>();
    for (int i = 0; i < 100; i++) {
        orderList.add(new OrderDoc(
                "ORDER20260212" + String.format("%03d", i + 2),
                "10086" + i,
                99.99 + i,
                "2026-02-12 10:" + String.format("%02d", i) + ":00",
                "普通发货"
        ));
    }

    // 1. 组装批量请求
    for (OrderDoc order : orderList) {
        XContentBuilder doc = XContentFactory.jsonBuilder()
                .startObject()
                    .field("order_id", order.getOrderId())
                    .field("user_id", order.getUserId())
                    .field("amount", order.getAmount())
                    .field("create_time", order.getCreateTime())
                    .field("order_remark", order.getRemark())
                .endObject();

        // 添加单条新增请求
        bulkRequest.add(new IndexRequest(INDEX_NAME)
                .id(order.getOrderId())
                .routing(order.getUserId())
                .source(doc));
    }

    // 2. 批量配置
    bulkRequest.setRefreshPolicy("false") // 不立即刷新
               .timeout(TimeValue.timeValueMinutes(5)); // 超时时间 5 分钟

    // 3. 执行批量操作
    BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);

    // 4. 结果解析
    if (response.hasFailures()) {
        // 打印失败详情
        System.out.println("批量操作失败:" + response.buildFailureMessage());
        // 遍历失败项
        for (var item : response.getItems()) {
            if (item.isFailed()) {
                System.out.println("失败文档ID:" + item.getId() + ",原因:" + item.getFailureReason());
            }
        }
    } else {
        System.out.println("批量操作成功,条数:" + response.getItems().length);
        System.out.println("总耗时:" + response.getTook().getMillis() + "ms");
    }
}

// 订单文档实体
static class OrderDoc {
    private String orderId;
    private String userId;
    private Double amount;
    private String createTime;
    private String remark;

    // 构造器、getter/setter 省略
    public OrderDoc(String orderId, String userId, Double amount, String createTime, String remark) {
        this.orderId = orderId;
        this.userId = userId;
        this.amount = amount;
        this.createTime = createTime;
        this.remark = remark;
    }

    // getter/setter...
}

3. GetRequest(按 ID 查询文档)

核心作用

按文档 ID 精准查询单条文档。

关键参数 / 方法
方法 / 参数含义注意事项
fetchSourceContext(FetchSourceContext)指定返回字段 / 排除字段仅返回所需字段,减少网络传输
routing(String)指定路由键必须与写入时的路由键一致,否则查不到
version(boolean)是否返回文档版本号乐观锁场景需开启
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;

/**
 * GetRequest Demo(按ID查询)
 */
public void getDocById(String docId, String userId) throws IOException {
    // 1. 构建查询请求
    GetRequest request = new GetRequest(INDEX_NAME, docId)
            .routing(userId) // 必须与写入时的路由键一致
            // 指定返回字段(仅返回订单号、金额、创建时间)
            .fetchSourceContext(new FetchSourceContext(
                    true, // 开启字段过滤
                    new String[]{"order_id", "amount", "create_time"}, // 包含字段
                    null // 排除字段
            ));

    // 2. 执行查询
    GetResponse response = client.get(request, RequestOptions.DEFAULT);

    // 3. 结果解析
    if (response.isExists()) {
        System.out.println("文档版本号:" + response.getVersion());
        // 文档内容转为 Map
        var source = response.getSourceAsMap();
        System.out.println("订单ID:" + source.get("order_id"));
        System.out.println("金额:" + source.get("amount"));
        System.out.println("创建时间:" + source.get("create_time"));
    } else {
        System.out.println("文档不存在:" + docId);
    }
}

四、查询核心类(Search)

1. SearchRequest + SearchSourceBuilder(搜索请求)

核心作用

SearchRequest 封装搜索的索引范围、路由等元信息;SearchSourceBuilder 封装查询条件、分页、排序、返回字段等核心查询逻辑。

SearchRequest 关键参数
方法 / 参数含义注意事项
indices(String...)指定要查询的索引(支持通配符,如 order_info_2026*)按时间分索引时用通配符
routing(String)指定路由键(仅查询该分片)提升查询性能,减少分片遍历
preference(String)查询偏好(如优先查副本)"_replica":优先查副本,读写分离
source(SearchSourceBuilder)设置查询核心逻辑必配!所有查询条件都在这里
SearchSourceBuilder 关键参数 / 方法
方法 / 参数含义默认值生产建议
query(QueryBuilder)设置查询条件(BoolQuery/TermQuery 等)match_all必配!避免全量查询
from(int)分页起始位置0深度分页禁用(>10000 性能极差)
size(int)每页条数10最大 10000(ES 默认限制)
searchAfter(Object[])游标分页(替代 from+size)-深度分页必用
sort(String, SortOrder)排序字段 + 顺序-searchAfter 必须配唯一排序字段
fetchSource(String[], String[])指定返回字段 / 排除字段返回所有仅返回所需字段,减少传输
trackTotalHits(boolean)是否返回总命中数true无需总条数时设为 false,提升性能

2. BoolQueryBuilder(布尔查询核心)

核心作用

组合多个子查询条件,实现复杂的多条件过滤 / 匹配。

关键方法(子句类型)
方法含义评分 / 性能适用场景
must(QueryBuilder)必须满足的条件(参与相关性评分)参与评分核心查询条件(如关键词匹配)
filter(QueryBuilder)必须满足的条件(不参与评分,ES 缓存结果)不评分状态、时间、金额范围等过滤条件
should(QueryBuilder)或条件(满足其一即可)参与评分多关键词模糊匹配
mustNot(QueryBuilder)必须不满足的条件不评分排除指定数据(如已删除订单)
常见子查询 Builder
查询类型作用示例代码
TermQueryBuilder精准匹配(不分词)QueryBuilders.termQuery("user_id", "10086")
MatchQueryBuilder分词模糊匹配QueryBuilders.matchQuery("order_remark", "加急")
RangeQueryBuilder范围查询(时间 / 金额)QueryBuilders.rangeQuery("amount").gte(100).lte(1000)
WildcardQueryBuilder通配符查询(慎用)QueryBuilders.wildcardQuery("order_id", "ORDER2026*")
NestedQueryBuilder嵌套对象查询QueryBuilders.nestedQuery("order_items", QueryBuilders.termQuery("order_items.sku_id", "SKU1001"), ScoreMode.None)
《复杂布尔查询 + 游标分页示例Demo》
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

/**
 * 布尔查询 + 游标分页 Demo
 */
public void boolQueryWithSearchAfter() throws IOException {
    // 1. 构建布尔查询条件
    BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

    // 必须满足:用户ID=10086(精准匹配)
    boolQuery.must(QueryBuilders.termQuery("user_id", "10086"));

    // 必须满足:备注含"加急"(分词匹配)
    boolQuery.must(QueryBuilders.matchQuery("order_remark", "加急"));

    // 过滤:金额 100-1000 元(不评分,性能高)
    boolQuery.filter(QueryBuilders.rangeQuery("amount")
            .gte(100)
            .lte(1000)
            .format("yyyy-MM-dd HH:mm:ss"));

    // 过滤:创建时间在 2026-02-01 至 2026-02-12
    boolQuery.filter(QueryBuilders.rangeQuery("create_time")
            .gte("2026-02-01 00:00:00")
            .lte("2026-02-12 23:59:59"));

    // 必须不满足:订单状态=已取消(2)
    boolQuery.mustNot(QueryBuilders.termQuery("order_status", 2));

    // 2. 构建 SearchSourceBuilder(查询核心)
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
            .query(boolQuery)
            .size(20) // 每页 20 条
            // 排序:创建时间降序 + 订单号降序(保证唯一性)
            .sort("create_time", SortOrder.DESC)
            .sort("order_id", SortOrder.DESC)
            // 仅返回指定字段
            .fetchSource(
                    new String[]{"order_id", "amount", "create_time", "order_remark"},
                    null
            )
            .trackTotalHits(true); // 返回总命中数

    // 3. 构建 SearchRequest
    SearchRequest searchRequest = new SearchRequest(INDEX_ALIAS) // 查询别名(屏蔽分索引)
            .source(sourceBuilder)
            .routing("10086") // 仅查询该用户分片
            .preference("_replica"); // 优先查副本(读写分离)

    // 4. 执行首次查询(第一页)
    SearchResponse firstPageResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    parseSearchResponse(firstPageResponse);

    // 5. 游标分页(第二页)
    SearchHit[] hits = firstPageResponse.getHits().getHits();
    if (hits.length > 0) {
        // 获取最后一条文档的排序值(游标)
        Object[] searchAfterValues = hits[hits.length - 1].getSortValues();
        // 构建第二页查询
        SearchSourceBuilder secondPageBuilder = new SearchSourceBuilder()
                .query(boolQuery)
                .size(20)
                .sort("create_time", SortOrder.DESC)
                .sort("order_id", SortOrder.DESC)
                .searchAfter(searchAfterValues) // 游标分页
                .from(0); // 必须设为 0
        // 执行第二页查询
        SearchResponse secondPageResponse = client.search(
                new SearchRequest(INDEX_ALIAS).source(secondPageBuilder),
                RequestOptions.DEFAULT
        );
        System.out.println("===== 第二页结果 =====");
        parseSearchResponse(secondPageResponse);
    }
}

/**
 * 通用 SearchResponse 解析方法
 */
private void parseSearchResponse(SearchResponse response) {
    SearchHits hits = response.getHits();
    // 总命中数
    long total = hits.getTotalHits().value;
    // 最大相关性评分
    float maxScore = hits.getMaxScore();

    System.out.println("总命中数:" + total + ",最大评分:" + maxScore);
    System.out.println("查询耗时:" + response.getTook().getMillis() + "ms");

    // 遍历命中文档
    for (SearchHit hit : hits) {
        String docId = hit.getId(); // 文档ID
        float score = hit.getScore(); // 相关性评分(filter 子句为 0)
        var source = hit.getSourceAsMap(); // 文档内容

        System.out.println(String.format(
                "文档ID:%s,评分:%.2f,订单ID:%s,金额:%s,创建时间:%s",
                docId, score,
                source.get("order_id"),
                source.get("amount"),
                source.get("create_time")
        ));
    }
}

五、核心响应类解析(Response)

1. SearchResponse(搜索响应)

核心字段 / 方法
方法 / 字段含义示例值
getHits()获取查询结果集SearchHits 对象
getTook()查询耗时50ms
isTimedOut()是否超时false
getShards()分片执行情况(成功 / 失败数)SuccessfulShards=3, FailedShards=0

2. SearchHits(结果集)

方法 / 字段含义示例值
getTotalHits().value总命中数1000
getMaxScore()最大相关性评分1.23
getHits()命中文档数组SearchHit[]

3. SearchHit(单条文档)

方法 / 字段含义示例值
getId()文档 IDORDER20260212001
getScore()相关性评分1.0
getSourceAsMap()文档内容(Map 格式){order_id: "ORDER20260212001", ...}
getSortValues()排序字段值(searchAfter 用)[1740000000000, "ORDER20260212001"]

作者:筱白爱学习!!

欢迎关注转发评论点赞沟通,您的支持是筱白的动力!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐