SpringBoot集成Elasticsearch | Elasticsearch 7.x专属HLRC(High Level Rest Client)

SpringBoot集成Elasticsearch | Elasticsearch 7.x专属HLRC(High Level Rest Client)

  • 前言
    • [1. 版本说明与Maven依赖](#1. 版本说明与Maven依赖)
    • [2. 配置文件(application.yml)](#2. 配置文件(application.yml))
    • [3. 核心代码实现](#3. 核心代码实现)
      • [3.1 配置类(构建HLRC客户端)](#3.1 配置类(构建HLRC客户端))
      • [3.2 工具类(封装ES操作)](#3.2 工具类(封装ES操作))
      • [3.3 实体类(Employee7xHlrc)](#3.3 实体类(Employee7xHlrc))
      • [3.4 Controller层(测试接口)](#3.4 Controller层(测试接口))
    • [4. 测试步骤](#4. 测试步骤)

SpringBoot集成Elasticsearch的三种核心方式,
Spring官方场景启动器
Elasticsearch 7.x专属HLRC(High Level Rest Client)
Elasticsearch 8.x专属Java Client

前言

Elasticsearch 7.x专属HLRC(High Level Rest Client)

HLRC是ES 7.x官方唯一推荐的高级客户端,稳定性与兼容性最优,支持所有ES 7.x特性,且版本需与ES服务器完全一致

1. 版本说明与Maven依赖

xml 复制代码
<dependencies>
    <!-- Web依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <!-- FastJSON -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>

    <!-- 1. Elasticsearch核心依赖(版本与ES服务器一致) -->
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.15.2</version>
    </dependency>
    <!-- 2. HLRC底层依赖(低级REST客户端) -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-client</artifactId>
        <version>7.15.2</version>
    </dependency>
    <!-- 3. HLRC核心依赖(高级REST客户端) -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.15.2</version>
    </dependency>
</dependencies>

2. 配置文件(application.yml)

配置ES连接信息、超时时间、连接池参数(7.x默认未开启安全认证)。

yaml 复制代码
server:
  port: 8082 # 与方式一区分端口

# ES HLRC配置
elasticsearch:
  hlrc:
    cluster-name: es-cluster-7x # 集群名称(非必需,仅标识)
    hosts: 127.0.0.1:9200 # 服务器地址(集群用逗号分隔)
    scheme: http # 协议(7.x默认http,8.x默认https)
    # 安全认证(7.x默认关闭,开启需配置)
    # username: elastic
    # password: 你的ES密码
    # 超时配置(毫秒)
    connect-timeout: 1000
    socket-timeout: 30000
    connection-request-timeout: 500
    # 连接池配置
    max-connect-num: 100 # 总连接数
    max-connect-per-route: 50 # 单个节点最大连接数

3. 核心代码实现

3.1 配置类(构建HLRC客户端)

通过@ConfigurationProperties绑定配置,构建单例RestHighLevelClient(由Spring管理,避免重复创建连接)。

java 复制代码
package com.es.demo.config;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * ES 7.x HLRC客户端配置类
 */
@Slf4j
@Data
@Configuration
@ConfigurationProperties(prefix = "elasticsearch.hlrc")
public class Es7xHlrcConfig {
    // 配置参数(与application.yml对应)
    private String clusterName;
    private String hosts;
    private String scheme;
    private String username;
    private String password;
    private int connectTimeout;
    private int socketTimeout;
    private int connectionRequestTimeout;
    private int maxConnectNum;
    private int maxConnectPerRoute;

    /**
     * 构建RestHighLevelClient实例(单例,Spring自动注入)
     */
    @Bean(name = "es7xRestHighLevelClient")
    public RestHighLevelClient restHighLevelClient() {
        // 1. 解析ES服务器地址(host:port格式)
        List<HttpHost> httpHostList = new ArrayList<>();
        String[] hostArray = hosts.split(",");
        for (String host : hostArray) {
            String[] hostPort = host.split(":");
            if (hostPort.length != 2) {
                throw new RuntimeException("ES地址格式错误:" + host + "(正确格式:host:port)");
            }
            httpHostList.add(new HttpHost(hostPort[0], Integer.parseInt(hostPort[1]), scheme));
        }

        // 2. 构建RestClientBuilder
        RestClientBuilder builder = RestClient.builder(httpHostList.toArray(new HttpHost[0]));

        // 3. 配置安全认证(若开启)
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        if (username != null && password != null) {
            credentialsProvider.setCredentials(
                    AuthScope.ANY,
                    new UsernamePasswordCredentials(username, password)
            );
        }

        // 4. 配置超时时间(连接、Socket、请求排队)
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(connectTimeout);
            requestConfigBuilder.setSocketTimeout(socketTimeout);
            requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
            return requestConfigBuilder;
        });

        // 5. 配置连接池与认证
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(maxConnectNum); // 总连接数
            httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute); // 单节点连接数
            if (username != null && password != null) {
                httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
            return httpClientBuilder;
        });

        // 6. 构建并返回客户端
        RestHighLevelClient client = new RestHighLevelClient(builder);
        log.info("ES 7.x HLRC客户端初始化完成,集群名称:{},服务器地址:{}", clusterName, hosts);
        return client;
    }
}

3.2 工具类(封装ES操作)

封装索引CRUD、文档CRUD、高亮查询等核心操作,避免重复代码。

java 复制代码
package com.es.demo.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * ES 7.x HLRC工具类(封装核心操作)
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class Es7xHlrcUtil {
    // 注入HLRC客户端(与配置类中Bean名称一致)
    private final RestHighLevelClient es7xRestHighLevelClient;

    // 常量定义
    public static final String KEYWORD_SUFFIX = ".keyword"; // 精确匹配后缀(text类型字段用)
    public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueSeconds(3); // 默认超时时间

    /**
     * 1. 创建索引(若已存在则返回false)
     * @param indexName 索引名(需小写,无特殊字符)
     * @param mapping DSL(可选,如指定字段类型、分词器,null则用默认映射)
     */
    public boolean createIndex(String indexName, String mapping) throws IOException {
        if (isIndexExist(indexName)) {
            log.warn("索引[{}]已存在,无需重复创建", indexName);
            return false;
        }

        CreateIndexRequest request = new CreateIndexRequest(indexName);
        // 若传入mapping,则设置索引映射
        if (StringUtils.isNotBlank(mapping)) {
            request.mapping(mapping, XContentType.JSON);
        }

        CreateIndexResponse response = es7xRestHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
        log.info("索引[{}]创建成功,响应状态:{}", indexName, response.isAcknowledged());
        return response.isAcknowledged();
    }

    /**
     * 2. 判断索引是否存在
     */
    public boolean isIndexExist(String indexName) throws IOException {
        GetIndexRequest request = new GetIndexRequest(indexName);
        boolean exists = es7xRestHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        log.debug("索引[{}]存在状态:{}", indexName, exists);
        return exists;
    }

    /**
     * 3. 删除索引(若不存在则返回false)
     */
    public boolean deleteIndex(String indexName) throws IOException {
        if (!isIndexExist(indexName)) {
            log.warn("索引[{}]不存在,无需删除", indexName);
            return false;
        }

        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        AcknowledgedResponse response = es7xRestHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
        log.info("索引[{}]删除成功,响应状态:{}", indexName, response.isAcknowledged());
        return response.isAcknowledged();
    }

    /**
     * 4. 添加文档(自定义docId,不存在则新增,存在则覆盖)
     * @param indexName 索引名
     * @param docId 文档ID(null则让ES自动生成)
     * @param data 文档数据(POJO或Map)
     */
    public String addDoc(String indexName, String docId, Object data) throws IOException {
        // 转换数据为JSON字符串
        String jsonData = JSON.toJSONString(data);

        IndexRequest request = new IndexRequest(indexName);
        // 设置文档ID(null则自动生成)
        if (StringUtils.isNotBlank(docId)) {
            request.id(docId);
        }
        // 设置超时时间和数据
        request.timeout(DEFAULT_TIMEOUT);
        request.source(jsonData, XContentType.JSON);

        IndexResponse response = es7xRestHighLevelClient.index(request, RequestOptions.DEFAULT);
        log.info("文档添加成功:索引[{}],docId[{}],响应状态[{}]",
                indexName, response.getId(), response.status().getStatus());
        return response.getId(); // 返回实际的docId(自动生成或自定义)
    }

    /**
     * 4. 重载:添加文档(自动生成UUID作为docId)
     */
    public String addDoc(String indexName, Object data) throws IOException {
        String autoDocId = UUID.randomUUID().toString().replace("-", "").toUpperCase();
        return addDoc(indexName, autoDocId, data);
    }

    /**
     * 5. 根据docId删除文档
     */
    public boolean deleteDocByDocId(String indexName, String docId) throws IOException {
        if (!isDocExist(indexName, docId)) {
            log.warn("文档不存在:索引[{}],docId[{}]", indexName, docId);
            return false;
        }

        DeleteRequest request = new DeleteRequest(indexName, docId);
        request.timeout(DEFAULT_TIMEOUT);

        DeleteResponse response = es7xRestHighLevelClient.delete(request, RequestOptions.DEFAULT);
        log.info("文档删除成功:索引[{}],docId[{}],响应状态[{}]",
                indexName, docId, response.status().getStatus());
        return response.status().getStatus() == 200;
    }

    /**
     * 6. 根据docId更新文档(部分更新,仅修改传入字段)
     */
    public boolean updateDocByDocId(String indexName, String docId, Object updateData) throws IOException {
        if (!isDocExist(indexName, docId)) {
            log.warn("文档不存在:索引[{}],docId[{}],无法更新", indexName, docId);
            return false;
        }

        // 转换更新数据为JSON字符串
        String jsonData = JSON.toJSONString(updateData);

        UpdateRequest request = new UpdateRequest(indexName, docId);
        request.timeout(DEFAULT_TIMEOUT);
        request.doc(jsonData, XContentType.JSON);
        // 实时刷新(wait_for:等待刷新完成后返回,确保更新后可立即查询,性能略低)
        request.setRefreshPolicy("wait_for");

        UpdateResponse response = es7xRestHighLevelClient.update(request, RequestOptions.DEFAULT);
        log.info("文档更新成功:索引[{}],docId[{}],响应状态[{}]",
                indexName, docId, response.status().getStatus());
        return response.status().getStatus() == 200;
    }

    /**
     * 7. 根据docId查询文档
     * @param fields 需要返回的字段(逗号分隔,如"name,age",null则返回所有字段)
     */
    public Map<String, Object> getDocByDocId(String indexName, String docId, String fields) throws IOException {
        if (!isDocExist(indexName, docId)) {
            log.warn("文档不存在:索引[{}],docId[{}]", indexName, docId);
            return null;
        }

        GetRequest request = new GetRequest(indexName, docId);
        // 筛选返回字段
        if (StringUtils.isNotBlank(fields)) {
            request.fetchSourceContext(new FetchSourceContext(
                    true,
                    fields.split(","), // 需返回的字段
                    Strings.EMPTY_ARRAY // 需排除的字段(空数组表示不排除)
            ));
        }

        GetResponse response = es7xRestHighLevelClient.get(request, RequestOptions.DEFAULT);
        Map<String, Object> docData = response.getSource();
        // 补充docId到返回结果中(方便前端使用)
        if (docData != null) {
            docData.put("docId", response.getId());
        }
        return docData;
    }

    /**
     * 8. 判断文档是否存在(仅判断存在性,不返回数据,性能更高)
     */
    public boolean isDocExist(String indexName, String docId) throws IOException {
        GetRequest request = new GetRequest(indexName, docId);
        // 不获取文档内容,仅判断存在性
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");

        boolean exists = es7xRestHighLevelClient.exists(request, RequestOptions.DEFAULT);
        log.debug("文档存在状态:索引[{}],docId[{}],存在[{}]", indexName, docId, exists);
        return exists;
    }

    /**
     * 9. 高亮查询(支持分页、排序、字段筛选)
     * @param indexName 索引名
     * @param searchSourceBuilder 查询条件(需外部构建,如匹配、范围查询)
     * @param pageNum 页码(从1开始)
     * @param pageSize 每页条数
     * @param fields 返回字段(逗号分隔,null则返回所有)
     * @param sortField 排序字段(null则不排序,text类型需加.keyword)
     * @param highlightField 高亮字段(如"name")
     */
    public List<Map<String, Object>> searchHighlight(String indexName,
                                                     SearchSourceBuilder searchSourceBuilder,
                                                     Integer pageNum,
                                                     Integer pageSize,
                                                     String fields,
                                                     String sortField,
                                                     String highlightField) throws IOException {
        // 1. 配置分页(from = (页码-1)*每页条数)
        int from = (pageNum - 1) * pageSize;
        searchSourceBuilder.from(from).size(pageSize);

        // 2. 配置排序(text类型字段需加.keyword才能精确排序)
        if (StringUtils.isNotBlank(sortField)) {
            if (sortField.contains(".")) {
                searchSourceBuilder.sort(sortField, SortOrder.ASC);
            } else {
                searchSourceBuilder.sort(sortField + KEYWORD_SUFFIX, SortOrder.ASC);
            }
        }

        // 3. 配置返回字段筛选
        if (StringUtils.isNotBlank(fields)) {
            searchSourceBuilder.fetchSource(new FetchSourceContext(
                    true,
                    fields.split(","),
                    Strings.EMPTY_ARRAY
            ));
        }

        // 4. 配置高亮(红色span标签)
        if (StringUtils.isNotBlank(highlightField)) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            HighlightBuilder.Field field = new HighlightBuilder.Field(highlightField)
                    .preTags("<span style='color:red'>")
                    .postTags("</span>")
                    .requireFieldMatch(false); // 允许高亮多个字段
            highlightBuilder.field(field);
            searchSourceBuilder.highlighter(highlightBuilder);
        }

        // 5. 执行查询
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = es7xRestHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        // 6. 解析查询结果(处理高亮字段)
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            Map<String, Object> docData = hit.getSourceAsMap();
            // 补充docId
            docData.put("docId", hit.getId());

            // 替换高亮字段(将原始字段值替换为高亮后的内容)
            if (StringUtils.isNotBlank(highlightField)) {
                HighlightField highlight = hit.getHighlightFields().get(highlightField);
                if (highlight != null && highlight.getFragments() != null) {
                    // 拼接多片段(如字段内容过长,ES会拆分为多个片段)
                    StringBuilder highlightValue = new StringBuilder();
                    for (Text fragment : highlight.getFragments()) {
                        highlightValue.append(fragment.string());
                    }
                    docData.put(highlightField, highlightValue.toString());
                }
            }

            resultList.add(docData);
        }

        log.info("高亮查询完成:索引[{}],匹配总数[{}],分页[{}页/{}条]",
                indexName, response.getHits().getTotalHits().value, pageNum, pageSize);
        return resultList;
    }
}

3.3 实体类(Employee7xHlrc)

与方式一类似,仅用于数据传输,无需ES注解(HLRC不依赖Spring Data注解)。

java 复制代码
package com.es.demo.entity;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 员工实体(用于ES 7.x HLRC)
 */
@Data
public class Employee7xHlrc {
    private String docId; // 文档ID(可选,HLRC可自动生成)
    private String jobNo; // 工号
    private String name; // 姓名
    private String job; // 岗位
    private Integer age; // 年龄
    private BigDecimal salary; // 薪资
    private Date jobDay; // 入职时间
    private String remark; // 备注
}

3.4 Controller层(测试接口)

调用工具类实现业务接口,方便测试。

环境提示

  • 开发/测试环境:创建索引时可不传mapping参数,依赖ES动态映射快速验证接口功能;
  • 生产环境:必须传入自定义mapping(如当前代码中指定字段类型和IK分词器的配置),精准控制字段属性,同时建议关闭动态映射并提前预创建索引。
java 复制代码
package com.es.demo.controller;

import com.es.demo.entity.Employee7xHlrc;
import com.es.demo.util.Es7xHlrcUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/api/hlrc7x/employee")
@RequiredArgsConstructor
public class Employee7xHlrcController {
    private final Es7xHlrcUtil es7xHlrcUtil;
    // 索引名(与实体类对应)
    private static final String EMPLOYEE_INDEX = "employee_hlrc_7x";

    /**
     * 1. 创建员工索引(带自定义mapping,指定字段类型和分词器)
     */
    @GetMapping("/index/create")
    public String createIndex() {
        // 自定义mapping(指定字段类型、IK分词器)
        String mapping = "{\n" +
                "  \"properties\": {\n" +
                "    \"jobNo\": {\n" +
                "      \"type\": \"keyword\"\n" +
                "    },\n" +
                "    \"name\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"job\": {\n" +
                "      \"type\": \"keyword\"\n" +
                "    },\n" +
                "    \"age\": {\n" +
                "      \"type\": \"integer\"\n" +
                "    },\n" +
                "    \"salary\": {\n" +
                "      \"type\": \"double\"\n" +
                "    },\n" +
                "    \"jobDay\": {\n" +
                "      \"type\": \"date\",\n" +
                "      \"format\": \"yyyy-MM-dd\"\n" +
                "    },\n" +
                "    \"remark\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_smart\"\n" +
                "    }\n" +
                "  }\n" +
                "}";

        try {
            boolean result = es7xHlrcUtil.createIndex(EMPLOYEE_INDEX, mapping);
            return result ? "索引创建成功" : "索引已存在";
        } catch (IOException e) {
            log.error("创建索引失败", e);
            return "索引创建失败:" + e.getMessage();
        }
    }

    /**
     * 2. 删除员工索引
     */
    @GetMapping("/index/delete")
    public String deleteIndex() {
        try {
            boolean result = es7xHlrcUtil.deleteIndex(EMPLOYEE_INDEX);
            return result ? "索引删除成功" : "索引不存在";
        } catch (IOException e) {
            log.error("删除索引失败", e);
            return "索引删除失败:" + e.getMessage();
        }
    }

    /**
     * 3. 添加员工文档(自动生成docId)
     */
    @PostMapping("/save")
    public String save(@RequestBody Employee7xHlrc employee) {
        try {
            String docId = es7xHlrcUtil.addDoc(EMPLOYEE_INDEX, employee);
            return "员工添加成功,docId:" + docId;
        } catch (IOException e) {
            log.error("添加员工失败", e);
            return "添加员工失败:" + e.getMessage();
        }
    }

    /**
     * 4. 根据docId查询员工
     */
    @GetMapping("/get/{docId}")
    public Map<String, Object> get(@PathVariable String docId) {
        try {
            // 仅返回name、job、salary、jobDay字段
            return es7xHlrcUtil.getDocByDocId(EMPLOYEE_INDEX, docId, "name,job,salary,jobDay");
        } catch (IOException e) {
            log.error("查询员工失败(docId:{})", docId, e);
            return null;
        }
    }

    /**
     * 5. 高亮查询员工(姓名模糊匹配)
     */
    @GetMapping("/search-highlight")
    public List<Map<String, Object>> searchHighlight(
            @RequestParam String name,
            @RequestParam(defaultValue = "1") Integer pageNum,
            @RequestParam(defaultValue = "10") Integer pageSize) {
        try {
            // 构建查询条件:姓名模糊匹配(matchQuery支持分词)
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchQuery("name", name));

            // 调用工具类高亮查询(按jobNo升序排序,高亮name字段)
            return es7xHlrcUtil.searchHighlight(
                    EMPLOYEE_INDEX,
                    searchSourceBuilder,
                    pageNum,
                    pageSize,
                    "name,jobNo,job,age,salary", // 返回字段
                    "jobNo", // 排序字段(keyword类型,无需加后缀)
                    "name" // 高亮字段
            );
        } catch (IOException e) {
            log.error("高亮查询员工失败(姓名关键词:{})", name, e);
            return null;
        }
    }

    /**
     * 6. 测试示例:添加单个员工(手动传参)
     */
    @GetMapping("/test/save")
    public String testSave(
            @RequestParam String jobNo,
            @RequestParam String name,
            @RequestParam String job,
            @RequestParam Integer age,
            @RequestParam BigDecimal salary,
            @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date jobDay,
            @RequestParam(required = false) String remark) {
        Employee7xHlrc employee = new Employee7xHlrc();
        employee.setJobNo(jobNo);
        employee.setName(name);
        employee.setJob(job);
        employee.setAge(age);
        employee.setSalary(salary);
        employee.setJobDay(jobDay);
        employee.setRemark(remark);

        try {
            String docId = es7xHlrcUtil.addDoc(EMPLOYEE_INDEX, employee);
            return "测试添加成功,docId:" + docId;
        } catch (IOException e) {
            log.error("测试添加员工失败", e);
            return "测试添加失败:" + e.getMessage();
        }
    }
}

4. 测试步骤

  1. 启动ES 7.15.2服务器;
  2. 调用创建索引接口:http://localhost:8082/api/hlrc7x/employee/index/create
  3. 调用测试添加接口:http://localhost:8082/api/hlrc7x/employee/test/save?jobNo=2024002&name=李四&job=前端开发&age=26&salary=22000&jobDay=2023-03-20&remark=UI专家
  4. 调用高亮查询接口:http://localhost:8082/api/hlrc7x/employee/search-highlight?name=李&pageNum=1&pageSize=10,验证高亮效果。
相关推荐
Linux运维技术栈3 小时前
Jenkins从节点配置全攻略:从搭建到任务调度,参数详解与实战指南
运维·jenkins
Slow菜鸟3 小时前
SpringBoot教程(安装篇):Elasticsearch及可视化工具安装(Windows环境)
spring boot·elasticsearch
忧郁的橙子.3 小时前
IntelliJ IDEA 2023中为 Spring Boot 项目添加注释模板
java·spring boot·intellij-idea
sniper_fandc3 小时前
Elasticsearch从入门到进阶——搜索优化原理
elasticsearch·搜索引擎·lucene·1024程序员节
有谁看见我的剑了?3 小时前
Rocky 9 安装 Elasticsearch分布式集群
分布式·elasticsearch·jenkins
聆风吟º3 小时前
【Spring Boot 报错已解决】别让端口配置卡壳!Spring Boot “Binding to target failed” 报错解决思路
android·java·spring boot
Pastthewind13 小时前
docker-compose部署ES
elasticsearch
遥远_14 小时前
Spring Boot微服务健康检测:保障系统稳定性的关键实践
spring boot·微服务·1024程序员节·健康检测
苹果醋314 小时前
学习札记-Java8系列-1-Java8新特性简介&为什么要学习Java8
java·运维·spring boot·mysql·nginx