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,验证高亮效果。
相关推荐
long31643 分钟前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
独断万古他化1 小时前
【SSM开发实战:博客系统】(三)核心业务功能开发与安全加密实现
spring boot·spring·mybatis·博客系统·加密
rannn_1111 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
qq_12498707531 小时前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
倒流时光三十年2 小时前
SpringBoot 数据库同步 Elasticsearch 性能优化
数据库·spring boot·elasticsearch
码农小卡拉2 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot
Dragon Wu2 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
人间打气筒(Ada)3 小时前
jenkins基于Pipeline发布项目
java·pipeline·jenkins·流水线·ci·cd·cicd
星辰_mya3 小时前
Elasticsearch更新了分词器之后
大数据·elasticsearch·搜索引擎
Elastic 中国社区官方博客4 小时前
Elasticsearch:Workflows 介绍 - 9.3
大数据·数据库·人工智能·elasticsearch·ai·全文检索