ES8常用接口

ES 8.x 常用 Postman/ApiFox POST/GET 接口清单(HTTPS+Basic 认证)

前置统一配置

  1. 请求地址前缀:https://11.53.102.203:9200
  2. Auth 选择 Basic Auth,填 elastic 账号密码
  3. 关闭 SSL 证书校验(内网自签 CA 必开,否则 PKIX 报错)
  4. 请求头固定:Content-Type: application/json

一、索引管理接口(对应你业务表 T_las_eleasticsearch_index)

1. 判断索引是否存在(GET)

plaintext
 
 
GET /{indexName}
 
示例:GET https://11.53.102.203:9200/todo-log
  • 返回 200 存在;404 不存在
     
    代码对应:indices.exists()

2. 创建索引(PUT)

plaintext
 
 
PUT /todo-log
{
  "mappings": {
    "properties": {
      "id": {"type": "keyword"},
      "title": {"type": "text", "analyzer": "ik_max_word"},
      "createTime": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"}
    }
  },
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  }
}
 

3. 删除索引(谨慎使用,DELETE)

plaintext
 
 
DELETE /todo-log
 

4. 获取索引 Mapping 结构(GET)

plaintext
 
 
GET /todo-log/_mapping
 

5. 更新索引 Mapping 字段(PUT)

plaintext
 
 
PUT /todo-log/_mapping
{
  "properties": {
    "attachContent": {"type": "text", "analyzer": "ik_max_word"}
  }
}
 

6. 获取索引配置 Settings

plaintext
 
 
GET /todo-log/_settings
 

二、文档 CRUD 接口(业务数据增删改查)

1. 全文检索查询(POST 最常用)

plaintext
 
 
POST /todo-log/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "must": [
        {"match": {"title": "项目待办"}},
        {"term": {"userId.keyword": "admin"}}
      ],
      "filter": [
        {"range": {"createTime": {"gte": "2026-01-01"}}}
      ]
    }
  },
  "sort": [{"createTime": {"order": "desc"}}]
}
 

2. 根据 ID 查询单条文档(GET)

plaintext
 
 
GET /todo-log/_doc/文档ID
 

3. 新增 / 覆盖文档(PUT)

plaintext
 
 
PUT /todo-log/_doc/1001
{
  "id":"1001",
  "title":"周报待办任务",
  "userId":"admin",
  "createTime":"2026-07-21 15:30:00"
}
 

4. 新增文档(自动生成 ID,POST)

plaintext
 
 
POST /todo-log/_doc
{
  "title":"新流程待办"
}
 

5. 局部更新文档(POST _update)

plaintext
 
 
POST /todo-log/_doc/1001/_update
{
  "doc": {
    "title":"修改后的待办标题"
  }
}
 

6. 根据 ID 删除文档(DELETE)

plaintext
 
 
DELETE /todo-log/_doc/1001
 

7. 条件批量删除(POST _delete_by_query)

plaintext
 
 
POST /todo-log/_delete_by_query
{
  "query": {
    "term": {"userId.keyword": "test"}
  }
}
 

三、批量操作接口(同步大量业务数据)

批量插入 / 更新 / 删除 _bulk

plaintext
 
 
POST /todo-log/_bulk
{"index":{"_id":"1002"}}
{"title":"第一条批量数据"}
{"update":{"_id":"1001"}}
{"doc":{"title":"更新批量数据"}}
{"delete":{"_id":"999"}}
 

四、集群、健康、权限运维接口

  1. 集群健康状态
plaintext
 
 
GET /_cluster/health
 
  1. 查看所有索引列表
plaintext
 
 
GET /_cat/indices?v
 
  1. 节点信息
plaintext
 
 
GET /_nodes
 
  1. 账号权限校验(测试连通性)
plaintext
 
 
GET /_security/user/elastic/_has_privileges
{
  "index": [{"names":["*"], "privileges":["read","write"]}]
}
 

五、附件 / 高亮、聚合常用扩展接口

  1. 检索高亮展示
json
 
 
POST /todo-log/_search
{
  "query":{"match":{"title":"项目"}},
  "highlight": {
    "fields": {"title": {}}
  }
}
 
  1. 聚合统计(分组计数)
json
 
 
POST /todo-log/_search
{
  "size":0,
  "aggs": {
    "userGroup": {"terms": {"field":"userId.keyword"}}
  }
}
 

六、你业务系统配套封装接口(后端 Controller)

你之前写的业务接口,不属于 ES 原生,是项目封装:
  1. GET /lasEleasticsearchIndex/indexCheck/{indexName} 校验索引是否存在
  2. 新增 / 编辑索引配置:POST /lasEleasticsearchIndex/save
  3. 索引分页列表:GET /lasEleasticsearchIndex/list
  4. 索引字段保存:POST /lasEleasticsearchIndexField/save
  5. 根据索引 ID 查询字段列表:GET /lasEleasticsearchIndexField/list/{indexId}

关键踩坑提示

  1. ES8 默认强制 HTTPS + Basic 认证,缺一不可;
  2. 自签证书必须关闭 Postman/ApiFox SSL 校验,否则报 PKIX 证书链错误;
  3. _search 必须 POST,GET 传请求体部分低版本 ES 不兼容;
  4. keyword 字段用 term 精确匹配,text 字段用 match 分词检索;
  5. 生产禁止直接调用 DELETE /索引名,需后台做逻辑删除同步 ES。

---------------------------------------------------------

方案:案件 - 多文书 ES 全文检索(SpringBoot + MyBatis-Plus + Elasticsearch 8.x)

业务模型:1 条案件主表 → 关联多条文书附件(Word/PDF/PPT)
 
目标:支持输入关键词,同时检索【案件基础信息 + 所有文书附件文本内容】,命中案件返回。

一、两种架构选型对比

方案 A:宽表单索引(推荐,优先选用)

索引名:case_document_index
 
一条案件对应一条 ES 文档;
 
案件基础字段平铺 + 数组存储多条文书文本。
 
✅ 优点:查询简单、分页友好、聚合方便;一次查询直接返回案件。
 
❌ 缺点:案件更新时,要重新合并所有文书内容写入 ES。

方案 B:父子文档(Join 类型)

  • 父文档:案件信息
  • 子文档:单条文书
     
    ✅ 优点:文书新增 / 修改可单独更新子文档,不用刷新整条案件
     
    ❌ 缺点:DSL 复杂、分页性能一般,ES Join 性能有限,不推荐业务系统首选
结论:使用【方案 A 宽表模式】下文完整落地实现。

二、数据库表设计(MyBatis 实体基础)

1)案件主表 t_case_info

sql
 
 
CREATE TABLE t_case_info (
    id NVARCHAR(36) PRIMARY KEY,
    case_code NVARCHAR(100),    -- 案件编号
    case_name NVARCHAR(200),    -- 案件名称
    case_type NVARCHAR(50),     -- 案件类型
    litigant NVARCHAR(200),     -- 当事人
    create_time DATETIME,
    creator_name NVARCHAR(50),
    is_deleted BIT
);
 

2)案件文书附件表 t_case_file

sql
 
 
CREATE TABLE t_case_file (
    id NVARCHAR(36) PRIMARY KEY,
    case_id NVARCHAR(36),       -- 关联案件ID
    file_name NVARCHAR(200),    -- 文件名称
    file_suffix NVARCHAR(20),   -- 后缀 word/pdf/ppt
    file_path NVARCHAR(500),    -- 文件存储路径
    file_size BIGINT,
    content_text NTEXT,         -- 【可选】提前解析文本存入数据库
    create_time DATETIME,
    is_deleted BIT
);
 

三、依赖引入(pom.xml)

xml
 
 
<!-- Elasticsearch 8.x client -->
<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

<!-- Tika 文档解析:提取word/pdf/ppt文本 -->
<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-core</artifactId>
    <version>2.9.1</version>
</dependency>
 

四、ES 索引 Mapping 设计(宽表模型)

http
 
 
PUT /case_document_index
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1,
    "analysis": {
      "analyzer": {
        "ik_analyzer": {
          "type": "custom",
          "tokenizer": "ik_max_word"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "caseId": {"type":"keyword"},
      "caseCode": {"type":"keyword"},
      "caseName": {"type":"text","analyzer":"ik_analyzer","fields":{"keyword":{"type":"keyword"}}},
      "caseType": {"type":"keyword"},
      "litigant": {"type":"text","analyzer":"ik_analyzer"},
      "creatorName": {"type":"keyword"},
      "createTime": {"type":"date","format":"yyyy-MM-dd HH:mm:ss"},
      // 文书数组
      "fileList": {
        "type": "nested",
        "properties": {
          "fileId": {"type":"keyword"},
          "fileName": {"type":"text","analyzer":"ik_analyzer"},
          "fileSuffix": {"type":"keyword"},
          "fileContent": {"type":"text","analyzer":"ik_analyzer"}
        }
      },
      // 【关键】把所有文书内容合并成一个大文本,用于全局一键检索
      "allFileContent": {"type":"text","analyzer":"ik_analyzer"}
    }
  }
}
 
重点说明:
  1. nested fileList:保留每条文书独立信息,前端展示文件名;
  2. allFileContent:所有文书文本拼接汇总;用户输入关键词直接检索该字段,最简单高效;
  3. 使用 IK 分词 ik_max_word 支持中文全文检索。

五、ES 文档实体 Java

java
 
运行
 
 
import co.elastic.clients.elasticsearch._types.mapping.Type;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;

@Data
public class CaseDocumentEs {
    private String caseId;
    private String caseCode;
    private String caseName;
    private String caseType;
    private String litigant;
    private String creatorName;
    private LocalDateTime createTime;

    // 文书嵌套数组
    private List<CaseFileNested> fileList;
    // 全部文书合并文本,用于统一检索
    private String allFileContent;

    @Data
    public static class CaseFileNested {
        private String fileId;
        private String fileName;
        private String fileSuffix;
        private String fileContent;
    }
}
 

六、核心能力 1:Apache Tika 解析文档文本

java
 
运行
 
 
import org.apache.tika.Tika;
import java.io.File;
import java.io.InputStream;

@Component
public class DocumentParseUtil {
    private static final Tika tika = new Tika();

    /**
     * 提取word/pdf/ppt文本
     */
    public String extractText(InputStream inputStream) throws Exception {
        // 限制文本大小,防止超大文件
        return tika.parseToString(inputStream);
    }
}
 
支持格式:doc,docx,pdf,ppt,pptx;
 
注意:超大文件建议异步解析,不要阻塞 http 请求。

七、同步逻辑(两种触发时机)

方式 1:新增 / 修改案件、新增文书 → 主动同步 ES(实时)

流程:
  1. 案件保存 / 上传文书成功
  2. 根据 caseId 查询【案件信息 + 全部关联文书】
  3. 循环每个文书,调用 Tika 提取文本
  4. 组装 CaseDocumentEs,拼接 allFileContent
  5. ES upsert:存在则更新,不存在新增

方式 2:定时全量 / 增量同步(兜底补偿)

定时任务查询变更案件,重新构建文档写入 ES,防止消息丢失。

同步伪代码 Service

java
 
运行
 
 
@Service
public class CaseEsSyncService {

    private final ElasticsearchClient esClient;
    private final CaseInfoMapper caseInfoMapper;
    private final CaseFileMapper caseFileMapper;
    private final DocumentParseUtil parseUtil;

    /**
     * 根据案件ID同步ES
     */
    public void syncCaseToEs(String caseId) {
        // 1. 查询案件主信息
        CaseInfo caseInfo = caseInfoMapper.selectById(caseId);
        if (caseInfo == null || caseInfo.getIsDeleted()) {
            // 案件已删除 → 删除ES文档
            deleteEsDoc(caseId);
            return;
        }
        // 2. 查询该案件所有文书
        List<CaseFile> fileListDb = caseFileMapper.listByCaseId(caseId);

        // 3. 组装ES实体,解析文本
        CaseDocumentEs esDoc = new CaseDocumentEs();
        esDoc.setCaseId(caseInfo.getId());
        esDoc.setCaseCode(caseInfo.getCaseCode());
        esDoc.setCaseName(caseInfo.getCaseName());
        esDoc.setLitigant(caseInfo.getLitigant());
        esDoc.setCreatorName(caseInfo.getCreatorName());
        esDoc.setCreateTime(caseInfo.getCreateTime());

        List<CaseDocumentEs.CaseFileNested> nestedList = new ArrayList<>();
        StringBuilder allContentSb = new StringBuilder();

        for (CaseFile file : fileListDb) {
            CaseDocumentEs.CaseFileNested nested = new CaseDocumentEs.CaseFileNested();
            nested.setFileId(file.getId());
            nested.setFileName(file.getFileName());
            nested.setFileSuffix(file.getFileSuffix());

            String text;
            if (StringUtils.hasText(file.getContentText())) {
                // 数据库已预存解析文本,优先使用
                text = file.getContentText();
            } else {
                // 读取文件流解析
                try(InputStream is = getFileStream(file.getFilePath())){
                    text = parseUtil.extractText(is);
                }catch (Exception e){
                    text = "";
                }
            }
            nested.setFileContent(text);
            nestedList.add(nested);
            allContentSb.append(text).append(" ");
        }
        esDoc.setFileList(nestedList);
        esDoc.setAllFileContent(allContentSb.toString());

        // 4. upsert写入ES
        upsertEs(esDoc);
    }
}
 

八、全文检索 DSL 示例(用户查询入口)

需求:输入关键词,同时检索案件名称、当事人、所有文书内容
json
 
 
POST /case_document_index/_search
{
  "from": 0,
  "size": 10,
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "caseName": {
              "query": "施工合同纠纷"
            }
          }
        },
        {
          "match": {
            "litigant": {
              "query": "施工合同纠纷"
            }
          }
        },
        {
          "match": {
            "allFileContent": {
              "query": "施工合同纠纷"
            }
          }
        }
      ],
      "minimum_should_match": 1
    }
  },
  "sort": [
    {"createTime":"desc"}
  ],
  "highlight": {
    "fields": {
      "caseName": {},
      "allFileContent": {}
    }
  }
}
 

九、常见问题 & 优化方案

1)文件解析慢、接口超时

✅ 方案:异步线程池解析文本,上传文件只落库,通过 MQ / 线程后台解析 + 同步 ES。

2)大 PDF 内容太大,ES 文档过大

✅ 限制提取文本长度;或者只解析前 N 页;
 
✅ 超大附件考虑只检索文件名,不提取全文。

3)新增单个文书,不想重新加载全部文书

两种选择:
  1. 依然使用宽表:每次新增文书触发一次全量查询刷新(中小体量项目完全够用)
  2. 切换父子文档模型(大数据量、文书频繁独立新增场景)

4)权限控制

ES 只做全文检索;数据权限必须在业务代码过滤:
 
查询 ES 拿到 caseId 列表 → 再 MyBatis 根据当前用户权限过滤案件 ID。

十、扩展:结合你前面【索引配置管理模块】

你之前开发的 T_las_eleasticsearch_index / T_las_eleasticsearch_index_field 配置表:
 
可以把 case_document_index 作为一条索引配置记录,
 
6 个 / 多个检索字段(案件名称、当事人、文书名称、文书内容等)配置在明细表,
 
做到页面可视化配置检索字段,动态构建 ES 查询 DSL,不用硬编码字段。
如果你需要,我可以继续输出:
  1. Controller 检索接口代码 + QueryDTO
  2. ElasticsearchClient 完整工具类(upsert、delete、search 封装)
  3. MQ 异步同步文书完整代码模板

 

    ------------------------------------------------------------------------------------------------------
posted @ 2026-07-21 23:11  hanease  阅读(3)  评论(0)    收藏  举报