RestHighLevelClient详细使用手册

RestHighLevelClient 7.10.0

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

一、客户端初始化及参数

参数名 含义 默认值 生产建议值 注意事项
connectTimeout 连接 ES 节点的超时时间(TCP 握手阶段) 1000ms 3000ms 过小易因网络抖动失败,过大导致连接等待时间过长
socketTimeout 数据传输超时时间(请求发送后等待响应的时间) 30000ms 60000ms 复杂查询 / 大批量数据需调大(如 Bulk 批量写入、深度聚合)
connectionRequestTimeout 从连接池获取连接的超时时间 500ms 5000ms 连接池满时,超过该时间会抛连接超时异常
maxConnTotal 客户端最大连接数(所有 ES 节点共享) 20 100-200 按 QPS 调整,QPS 1000+ 建议 200
maxConnPerRoute 单个 ES 节点的最大连接数 10 50-100 避免单个节点连接数过多导致服务端限流
《初始化 示例Demo》
java 复制代码
@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
java 复制代码
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 默认分词器,按空格 / 标点拆分,英文小写化,中文单字拆分 默认值
analyzer 索引时分词器 text 字段 ik_max_word:IK 分词器 - 细粒度拆分(如 "华为 Mate60" 拆为 "华为、Mate60、Mate、60")
analyzer 索引时分词器 text 字段 ik_smart:IK 分词器 - 粗粒度拆分(如 "华为 Mate60" 拆为 "华为、Mate60")
analyzer 索引时分词器 text 字段 whitespace :仅按空格拆分,不小写化,不拆分标点
analyzer 索引时分词器 text 字段 keyword :不分词(整个字段作为一个词条)
analyzer 索引时分词器 text 字段 pattern :按正则表达式拆分
search_analyzer 搜索时分词器 analyzer 取值相同
format 日期格式 date 字段 yyyy-MM-dd HH:mm:ss/epoch_millis 等 epoch_millis
ignore_above 超过长度不索引 keyword 字段 1-32766 2147483647
dynamic 是否开启动态映射 根对象 /properties true/false/strict true
fields 多字段配置(如 text+keyword) text/keyword 字段 - -
null_value 空值替代值 keyword 字段 任意字符串 null
enabled 是否启用字段(禁用后不索引 / 存储) 所有字段 true/false true
《创建索引示例Demo》
java 复制代码
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》
java 复制代码
/**
 * 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》
java 复制代码
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》
java 复制代码
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) 是否返回文档版本号 乐观锁场景需开启
java 复制代码
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》
java 复制代码
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() 文档 ID ORDER20260212001
getScore() 相关性评分 1.0
getSourceAsMap() 文档内容(Map 格式) {order_id: "ORDER20260212001", ...}
getSortValues() 排序字段值(searchAfter 用) [1740000000000, "ORDER20260212001"]

作者:筱白爱学习!!

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

相关推荐
若谷老师2 小时前
21.WSL中部署gnina分子对接程序ds
linux·人工智能·ubuntu·卷积神经网络·gnina·smina
石油人单挑所有2 小时前
ProtoBuf编写网络版本通讯录时遇到问题及解决方案
运维·服务器
Andy3 小时前
分流设备的测试报告
运维·服务器
枷锁—sha3 小时前
【CTFshow-pwn系列】03_栈溢出【pwn 045】详解:Ret2Libc 之 32位动态泄露(补充本地 Libc 手动加载指南)
服务器·网络·网络安全·系统安全
liann1194 小时前
4.3.2_WEB——WEB后端语言——PHP
开发语言·前端·网络·安全·web安全·网络安全·php
啊辉的科研4 小时前
植物单细胞RNA-seq分析教程3-2025年版
linux·r语言
xdpcxq10294 小时前
EF Core实体追踪Entry中记录的数据
服务器·数据库·oracle
Norach4 小时前
ubuntu22.04安装ssh-server与realvnc-server
linux·服务器·经验分享·ubuntu·ssh·vnc
UP_Continue5 小时前
Linux--进程间通信
linux·运维·服务器