用elasticlient封装Elasticsearch C++ 客户端封装库
文章目录
- Elasticsearch C++ 客户端封装库详解
- 概述
- 核心组件
- 1. 工具函数
- JSON 序列化与反序列化
- 索引存在性检查
- 2. 索引管理类 (ESIndex)
- 构造函数与初始化
- 索引配置方法
- 使用示例
- 3. 文档插入类 (ESInsert)
- 核心方法
- 使用示例
- 4. 搜索查询类 (ESSearch)
- 查询条件构建
- 查询执行
- 使用示例
- 5. 删除操作类 (ESDelete)
- 功能方法
- 使用示例
- 完整封装
Elasticsearch C++ 客户端封装库详解
概述
这是一个基于 C++ 的 Elasticsearch 客户端封装库,通过封装elasticlient库
提供了简洁易用的 API 来操作 Elasticsearch 索引、文档的增删查等核心功能。库采用模块化设计,包含索引管理、文档插入、搜索查询和删除操作等组件。
核心组件
1. 工具函数
JSON 序列化与反序列化
namespace ESTool {// JSON对象转字符串inline bool JsonToString(const Json::Value& root, std::string& out);// 字符串转JSON对象inline bool StringToJson(const std::string& root, Json::Value& out);
}
索引存在性检查
inline bool indexExists(std::shared_ptr<elasticlient::Client> es_client, const std::string& indexname);
2. 索引管理类 (ESIndex)
构造函数与初始化
ESIndex(std::vector<std::string> hosturls = {"http://127.0.0.1:9200/"}, int timeout_ms = 5000);
特性:
- 自动初始化日志系统
- 支持多节点连接
- 内置连接超时设置
- 异常安全的设计
索引配置方法
// 设置分片和副本配置
void setIndexSettings(int shards = 1, int replicas = 0);// 添加字段映射(支持链式调用)
ESIndex& addFieldMapping(const std::string& field_name, const std::string& field_type,const std::string& format = "");// 创建索引
bool createIndex(const std::string& indexname, const Json::Value& custom_mappings = Json::nullValue);
字段类型支持:
keyword
:精确匹配字段text
:全文检索字段(自动启用IK分词器)integer
:整型字段date
:日期字段(支持自定义格式)
使用示例
// 创建索引管理器
ESTool::ESIndex es_index;// 配置索引
es_index.setIndexSettings(3, 1) // 3个分片,1个副本.addFieldMapping("student_id", "keyword").addFieldMapping("name", "text").addFieldMapping("age", "integer").addFieldMapping("birthday", "date", "yyyy-MM-dd");// 创建索引
if (es_index.createIndex("student_info")) {std::cout << "索引创建成功" << std::endl;
}
3. 文档插入类 (ESInsert)
核心方法
// 设置目标索引
void SetIndexName(const std::string& index_name);// 添加文档字段(支持链式调用)
ESInsert& append(const std::string& key, const std::string& val);
ESInsert& append(const std::string& key, const int& val);// 插入文档
bool insert(const std::string& id);
使用示例
ESTool::ESInsert es_insert;
es_insert.SetIndexName("student_info");// 构建并插入文档
es_insert.append("student_id", "2024001").append("name", "张三").append("age", 20).append("birthday", "2004-05-15").insert("doc_001"); // 指定文档ID
4. 搜索查询类 (ESSearch)
查询条件构建
// 设置查询索引
void SetIndexName(const std::string& index_name);// 必须匹配条件
ESSearch& append_must(const std::string& key, const std::string& val,const std::string& precision = "term");// 必须不匹配条件
ESSearch& append_must_not(const std::string& key, const std::string& val,const std::string& precision = "term");// 应该匹配条件
ESSearch& append_should(const std::string& key, const std::string& val,const std::string& precision = "term");// 范围查询
ESSearch& append_must_range(const std::string& key, const std::map<std::string, std::string>& range_conditions);
查询执行
// 查询所有文档
Json::Value queryAll();// 执行构建的查询
Json::Value query();
使用示例
ESTool::ESSearch es_search;
es_search.SetIndexName("student_info");// 精确查询
auto result1 = es_search.append_must("name", "张三").append_must("age", "20").query();// 范围查询
std::map<std::string, std::string> age_range{{"gte", "18"}, {"lt", "25"}};
auto result2 = es_search.append_must_range("age", age_range).query();// 查询所有文档
auto all_docs = es_search.queryAll();
5. 删除操作类 (ESDelete)
功能方法
// 删除指定文档
bool DeleteId(const std::string& id);// 删除整个索引
bool DeleteIndex();
使用示例
ESTool::ESDelete es_delete;
es_delete.SetIndexName("student_info");// 删除文档
es_delete.DeleteId("doc_001");// 删除索引
es_delete.DeleteIndex();
完整封装
#pragma once
#include <cpr/body.h>
#include <cpr/response.h>
#include <elasticlient/client.h>
#include <cpr/cpr.h>
#include <json/reader.h>
#include <json/value.h>
#include <json/writer.h> // 新增:用于JSON转字符串
#include <memory>
#include <fmt/format.h>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "LogTool.hpp"namespace ESTool
{inline bool JsonToString(const Json::Value& root, std::string& out){try{Json::StreamWriterBuilder swb;std::unique_ptr<Json::StreamWriter> swriter(swb.newStreamWriter());std::ostringstream oss;swriter->write(root, &oss);out = oss.str();return true;}catch (const std::exception& e){// 可以选择记录错误信息LOG_ERROR("JsonToString Error:{}", e.what());}return false;}inline bool StringToJson(const std::string& root, Json::Value& out){try{Json::CharReaderBuilder crb;std::unique_ptr<Json::CharReader> creader(crb.newCharReader());std::string errs; // 用于保存错误信息bool ok = creader->parse(root.c_str(), root.c_str() + root.size(), &out, &errs);if (!ok) {LOG_ERROR("StringToJson 解析失败:{}", errs);return false;}return true;}catch (const std::exception& e){LOG_ERROR("StringToJson 异常:{}", e.what());}return false;}/*** @brief 检查索引是否存在* @param indexname 要检查的索引名(如"student_info")* @return 存在返回true,不存在返回false(出错也返回false,日志记录错误)*/inline bool indexExists(std::shared_ptr<elasticlient::Client> es_client, const std::string& indexname){std::string last_error_;try{// ES 7.x 已移除_type,第二个参数传空字符串(原代码"_doc"是6.x写法,7.x无效)Json::Value body;body["query"]["match_all"] = Json::Value(Json::objectValue);std::string out;JsonToString(body, out);cpr::Response rep = es_client->performRequest(elasticlient::Client::HTTPMethod::GET, indexname+"/_search", out);//cpr::Response rep = es_client_->get(indexname, "_doc", "1","");// 状态码解析:200=索引存在,404=索引不存在if (rep.status_code == 200){//LOG_INFO("索引 [{}] 已存在", indexname);return true;}else if (rep.status_code == 404){//LOG_INFO("索引 [{}] 不存在", indexname);return false;}// 其他状态码(如503服务不可用):抛异常并记录错误std::string err_msg = fmt::format("检查索引 [{}] 失败:HTTP状态码={}, 错误信息={}, 返回:{}, boyd:{}",indexname, rep.status_code, rep.error.message, rep.text, out);last_error_ = err_msg;throw std::runtime_error(err_msg);}catch(const elasticlient::ConnectionException& ce){last_error_ = fmt::format("ES连接失败:{}", ce.what());LOG_ERROR("{}", last_error_);}catch (const std::exception& e){last_error_ = fmt::format("检查索引异常:{}", e.what());LOG_ERROR("{}", last_error_);}return false;}class ESIndex{public:/*** @brief 构造函数:初始化ES客户端连接* @param hosturls ES节点列表(默认本地节点:http://127.0.0.1:9200)* @param timeout_ms 超时时间(默认5000毫秒)*/ESIndex(std::vector<std::string> hosturls = {"http://127.0.0.1:9200/"}, // 注意:ES客户端要求URL以"/"结尾int timeout_ms = 5000){try {//初始化日志系统LogModule::Log::Init();// 初始化ES客户端(使用shared_ptr管理,自动释放)es_client_ = std::make_shared<elasticlient::Client>(hosturls,elasticlient::Client::TimeoutOption(timeout_ms));//初始化issettings_ = false;//默认配置DefaultSettings();LOG_INFO("ESIndex客户端初始化成功");} catch (const elasticlient::ConnectionException& ce) {LOG_ERROR("ESIndex客户端初始化失败(连接异常): {}", ce.what());throw std::runtime_error("ESIndex客户端初始化失败:" + std::string(ce.what()));} catch (const std::exception& e) {LOG_ERROR("ESIndex客户端初始化失败(标准异常): {}", e.what());throw std::runtime_error("ESIndex客户端初始化失败:" + std::string(e.what()));}}/*** @brief 设置索引的分片和副本配置(创建索引前调用)* @param shards 分片数量(创建后不可修改,测试环境建议1)* @param replicas 副本数量(可动态修改,测试环境建议0)*/void setIndexSettings(int shards = 1, int replicas = 0){if (shards <= 0) {LOG_WARN("分片数量非法({}),自动修正为1", shards);shards = 1;}if (replicas < 0) {LOG_WARN("副本数量非法({}),自动修正为0", replicas);replicas = 0;}// 填充settings_成员变量(ES标准配置格式)settings_["number_of_shards"] = shards; // 主分片数settings_["number_of_replicas"] = replicas; // 副本数issettings_ = true;LOG_INFO("索引配置已设置:分片={}, 副本={}", shards, replicas);}/*** @brief 添加字段映射(创建索引前调用,可多次调用添加多个字段)* @param field_name 字段名(如"student_id")* @param field_type 字段类型(如"keyword"、"text"、"integer"、"date")* @param format 可选:日期字段的格式(如"yyyy-MM-dd",非日期字段无需传)*/ESIndex& addFieldMapping(const std::string& field_name, const std::string& field_type,const std::string& format = ""){if (field_name.empty() || field_type.empty()) {LOG_ERROR("字段名或字段类型不能为空");return *this;}// 填充mappings_成员变量(ES 7.x 格式:直接在properties下定义字段)Json::Value& field = mappings_["properties"][field_name];field["type"] = field_type;if(field_type == "text")field["analyzer"] = "ik_max_word";// 若为日期类型且指定了格式:添加format配置if (field_type == "date" && !format.empty()) {field["format"] = format;LOG_INFO("添加字段映射:{}(类型={},格式={})", field_name, field_type, format);} else {LOG_INFO("添加字段映射:{}(类型={})", field_name, field_type);}return *this;}/*** @brief 创建索引(需先调用setIndexSettings和addFieldMapping配置,或直接传自定义映射)* @param indexname 要创建的索引名* @param custom_mappings 可选:自定义完整映射(优先级高于addFieldMapping的配置)* @return 创建成功返回true,失败返回false*/bool createIndex(const std::string& indexname, const Json::Value& custom_mappings = Json::nullValue){// 第一步:检查索引是否已存在if (indexExists(es_client_,indexname)) {last_error_ = fmt::format("索引 [{}] 已存在,无需重复创建", indexname);LOG_WARN("{}", last_error_);return false;}// 第二步:组装索引创建请求体(index_成员变量)try {// 1. 填充settings(若未调用setIndexSettings,使用默认配置)if (!issettings_) {LOG_WARN("未设置索引配置,使用默认值:分片=1,副本=0");settings_["number_of_shards"] = 1;settings_["number_of_replicas"] = 0;}index_["settings"] = settings_;// 2. 填充mappings(优先使用自定义映射,其次使用addFieldMapping的配置)if (!custom_mappings.isNull()) {index_["mappings"] = custom_mappings;LOG_INFO("使用自定义映射创建索引");} else {if (mappings_["properties"].empty()) {LOG_WARN("未添加任何字段映射,将创建空结构索引");}index_["mappings"] = mappings_;}// 3. 将JSON请求体转为字符串(ES要求传入字符串格式)std::string out;JsonToString(index_, out);std::string request_body = out;//LOG_DEBUG("创建索引请求体:{}", request_body);// 第三步:发送创建索引请求(ES用PUT方法创建索引)cpr::Response rep = es_client_->performRequest(elasticlient::Client::HTTPMethod::PUT, // HTTP方法:PUTindexname, // URL路径:/索引名request_body // 请求体);// 第四步:解析响应结果if (rep.status_code == 200 || rep.status_code == 201) {LOG_INFO("索引 [{}] 创建成功,HTTP状态码={}", indexname, rep.status_code);// 重置成员变量(避免下次创建索引复用旧配置)resetIndexConfig();return true;} else {last_error_ = fmt::format("创建索引 [{}] 失败:HTTP状态码={}, 响应内容={}",indexname, rep.status_code, rep.text);throw std::runtime_error(last_error_);}}catch(const elasticlient::ConnectionException& ce){last_error_ = fmt::format("ES连接失败:{}", ce.what());LOG_ERROR("{}", last_error_);}catch (const std::exception& e){last_error_ = fmt::format("创建索引异常:{}", e.what());LOG_ERROR("{}", last_error_);}// 失败时重置配置,避免影响下次使用resetIndexConfig();return false;}/*** @brief 获取最后一次错误信息* @return 错误信息字符串*/std::string getLastError() const{return last_error_;}/*** @brief 重置索引配置(清空settings_、mappings_、index_,用于重新配置新索引)*/void resetIndexConfig(){settings_.clear();mappings_.clear();index_.clear();last_error_.clear();issettings_ = false;//默认配置DefaultSettings();LOG_DEBUG("索引配置已重置");}~ESIndex(){LOG_INFO("ESIndex 实例已销毁");}private:void DefaultSettings(){try{//settingsJson::Value tokenizer;Json::Value ik;Json::Value analyzer;tokenizer["tokenizer"] = "ik_max_word";ik["ik"] = tokenizer;analyzer["analyzer"] = ik;settings_["analysis"] = analyzer;//mappingsmappings_["dynamic"] = true;}catch (const Json::Exception& e){LOG_ERROR("AddikSettings fail:{}", e.what());}}private:std::shared_ptr<elasticlient::Client> es_client_; // ES客户端(智能指针管理)Json::Value index_; // 完整索引创建请求体Json::Value settings_; // 索引配置(分片、副本)Json::Value mappings_; // 字段映射配置std::string last_error_; // 最后一次错误信息bool issettings_; //是否设置配置};class ESInsert{public:ESInsert(std::vector<std::string> hosturls = {"http://127.0.0.1:9200/"}, // 注意:ES客户端要求URL以"/"结尾int timeout_ms = 5000){try {//初始化日志系统LogModule::Log::Init();// 初始化ES客户端(使用shared_ptr管理,自动释放)es_client_ = std::make_shared<elasticlient::Client>(hosturls,elasticlient::Client::TimeoutOption(timeout_ms));LOG_INFO("ESInsert客户端初始化成功");} catch (const elasticlient::ConnectionException& ce) {LOG_ERROR("ESInsert客户端初始化失败(连接异常): {}", ce.what());throw std::runtime_error("ESInsert客户端初始化失败:" + std::string(ce.what()));} catch (const std::exception& e) {LOG_ERROR("ESInsert客户端初始化失败(标准异常): {}", e.what());throw std::runtime_error("ESInsert客户端初始化失败:" + std::string(e.what()));}}void SetIndexName(const std::string& index_name){index_name_ = index_name;}ESInsert& append(const std::string& key, const std::string& val){try{if(key.empty()){LOG_WARN("append key cannot empty");return *this;}root_[key] = val;}catch (const std::exception& e){LOG_ERROR("append error:{}", e.what());}return *this;}ESInsert& append(const std::string& key, const int& val){try{if(key.empty()){LOG_WARN("append key cannot empty");return *this;}root_[key] = val;}catch (const std::exception& e){LOG_ERROR("append error:{}", e.what());}return *this;}bool insert(const std::string& id){try{if(id.empty()){LOG_WARN("id为空!");return false;}if(root_.empty() || index_name_.empty()){LOG_WARN("要插入的json为空或索引名为空!");return false;}if(!indexExists(es_client_, index_name_)){LOG_WARN("索引-{}不存在,插入数据失败!", index_name_);return false;}std::string body;JsonToString(root_, body);auto rep = es_client_->performRequest(elasticlient::Client::HTTPMethod::PUT, index_name_ + std::string("/_doc/") + id, body);if (rep.status_code < 200 || rep.status_code >= 300){LOG_ERROR("insert error:{}, reponse text: {}", rep.error.message, rep.text);return false;}LOG_ERROR("插入成功,返回码:{}", rep.status_code);reset();return true;}catch (const std::exception& e){LOG_ERROR("insert error:{}", e.what());}return false;}void reset(){root_.clear();last_error_.clear();LOG_INFO("ESInsert数据重置成功!");}~ESInsert(){LOG_INFO("ESInsert 实例已销毁");}private:std::shared_ptr<elasticlient::Client> es_client_; // ES客户端(智能指针管理)std::string last_error_; // 最后一次错误信息Json::Value root_;std::string index_name_;};class ESSearch{public:ESSearch(std::vector<std::string> hosturls = {"http://127.0.0.1:9200/"}, // 注意:ES客户端要求URL以"/"结尾int timeout_ms = 5000){try {//初始化日志系统LogModule::Log::Init();// 初始化ES客户端(使用shared_ptr管理,自动释放)es_client_ = std::make_shared<elasticlient::Client>(hosturls,elasticlient::Client::TimeoutOption(timeout_ms));LOG_INFO("ESSearch客户端初始化成功");} catch (const elasticlient::ConnectionException& ce) {LOG_ERROR("ESSearch客户端初始化失败(连接异常): {}", ce.what());throw std::runtime_error("ESSearch客户端初始化失败:" + std::string(ce.what()));} catch (const std::exception& e) {LOG_ERROR("ESSearch客户端初始化失败(标准异常): {}", e.what());throw std::runtime_error("ESSearch客户端初始化失败:" + std::string(e.what()));}}void SetIndexName(const std::string& index_name){index_name_ = index_name;}Json::Value queryAll(){try{Json::Value queryall;queryall["query"]["match_all"] = Json::Value(Json::objectValue);return _query(queryall);}catch (const std::exception& e){LOG_ERROR("queryAll error:{}", e.what());}return Json::Value();}ESSearch& append_must(const std::string& key,const std::string& val,const std::string& precision = "match"){return _append(key, val, "must", precision);}ESSearch& append_must_not(const std::string& key,const std::string& val,const std::string& precision = "match"){return _append(key, val, "must_not", precision);}ESSearch& append_should(const std::string& key,const std::string& val,const std::string& precision = "match"){return _append(key, val, "should", precision);}// 向 must 中添加范围查询(如 age > 20 且 <= 30)ESSearch& append_must_range(const std::string& key, const std::map<std::string, std::string>& range_conditions){return _append_range(key, range_conditions, "must");}// 向 must_not 中添加范围查询ESSearch& append_must_not_range(const std::string& key, const std::map<std::string, std::string>& range_conditions){return _append_range(key, range_conditions, "must_not");}// 向 should 中添加范围查询ESSearch& append_should_range(const std::string& key, const std::map<std::string, std::string>& range_conditions){return _append_range(key, range_conditions, "should");}Json::Value query(){return _query(queryjson_);}void reset(){queryjson_.clear();LOG_INFO("清空查询数据!");}~ESSearch(){LOG_INFO("ESSearch 实例已销毁!");}private:ESSearch& _append(const std::string& key,const std::string& val,const std::string& demand,const std::string& precision){try{Json::Value& must = queryjson_["query"]["bool"][demand];Json::Value item;item[precision][key] = val;must.append(item);LOG_TRACE("append_{} sucess!-key-val:{}-{}", demand, key, val);}catch (const std::exception& e){LOG_ERROR("append_must error:{}", e.what());last_error_ = e.what();}return *this;}Json::Value _query(const Json::Value& root){try{if (index_name_.empty()){LOG_WARN("索引名未设置!");return false;}if(!indexExists(es_client_, index_name_)){LOG_WARN("索引-{}不存在,插入数据失败!", index_name_);return false;}if (root.empty()){LOG_WARN("查询条件不允许为空!");return false;}std::string body;JsonToString(root, body);auto rep = es_client_->performRequest(elasticlient::Client::HTTPMethod::GET, index_name_ + "/_search", body);//LOG_TRACE("查询语句:{}", body);//LOG_TRACE("查询结果:{}", rep.text);if (rep.status_code < 200 || rep.status_code >= 300){LOG_ERROR("query error:{}, reponse text: {}", rep.error.message, rep.text);return Json::Value();}Json::Value result;StringToJson(rep.text, result);LOG_INFO("query sucess!, status code:{}", rep.status_code);reset();return result["hits"]["hits"];}catch (const std::exception& e){LOG_ERROR("query error:{}", e.what());last_error_ = e.what();}return Json::Value();}// 私有方法:构建范围查询并添加到指定的 bool 条件中(must/must_not/should)ESSearch& _append_range(const std::string& key, const std::map<std::string, std::string>& range_conditions, const std::string& demand){try{// 1. 获取 bool 中对应的条件数组(如 query.bool.must)Json::Value& condition_array = queryjson_["query"]["bool"][demand];// 2. 构建 range 查询对象(如 { "range": { "age": { "gt": 20, "lte": 30 } } })Json::Value range_item;Json::Value range_params; // 存储 gt/gte/lt/lte 等条件// 遍历传入的范围条件(如 {{"gt", "20"}, {"lte", "30"}})for (const auto& [range_type, value] : range_conditions){// 支持的范围类型:gt(>)、gte(>=)、lt(<)、lte(<=)if (range_type == "gt" || range_type == "gte" || range_type == "lt" || range_type == "lte"){// 尝试将值转换为数字(如果是数字类型),否则按字符串处理if (isdigit(value[0])) {range_params[range_type] = Json::Value(std::stoi(value)); // 整数// 若需要支持浮点数,可改为 std::stod 并使用 asDouble()} else {range_params[range_type] = Json::Value(value); // 字符串(如日期)}} else {LOG_WARN("不支持的范围类型: {}", range_type);}}// 3. 将范围条件添加到 range 中range_item["range"][key] = range_params;// 4. 将整个 range 条件添加到 bool 条件数组中condition_array.append(range_item);LOG_TRACE("append_{}_range success! - key:{}", demand, key);}catch (const std::exception& e){LOG_ERROR("append_range error: {}", e.what());last_error_ = e.what();}return *this;}private:std::shared_ptr<elasticlient::Client> es_client_; // ES客户端(智能指针管理)std::string last_error_; // 最后一次错误信息Json::Value queryjson_;std::string index_name_;};class ESDelete{public:ESDelete(std::vector<std::string> hosturls = {"http://127.0.0.1:9200/"}, // 注意:ES客户端要求URL以"/"结尾int timeout_ms = 5000){try {//初始化日志系统LogModule::Log::Init();// 初始化ES客户端(使用shared_ptr管理,自动释放)es_client_ = std::make_shared<elasticlient::Client>(hosturls,elasticlient::Client::TimeoutOption(timeout_ms));LOG_INFO("ESDelete客户端初始化成功");} catch (const elasticlient::ConnectionException& ce) {LOG_ERROR("ESDelete客户端初始化失败(连接异常): {}", ce.what());last_error_ = ce.what();throw std::runtime_error("ESDelete客户端初始化失败:" + std::string(ce.what()));} catch (const std::exception& e) {LOG_ERROR("ESDelete客户端初始化失败(标准异常): {}", e.what());last_error_ = e.what();throw std::runtime_error("ESDelete客户端初始化失败:" + std::string(e.what()));}}void SetIndexName(const std::string& index_name){index_name_ = index_name;}bool DeleteId(const std::string& id){try{if (index_name_.empty()){LOG_WARN("索引名未设置!");return false;}if(!indexExists(es_client_, index_name_)){LOG_WARN("索引-{}不存在,删除数据失败!", index_name_);return false;}auto rep = es_client_->remove(index_name_, "_doc", id);// auto rep = es_client_->performRequest(// elasticlient::Client::HTTPMethod::DELETE// , index_name_ + id// , "");if (rep.status_code < 200 || rep.status_code >= 300){LOG_ERROR("query error:{}, reponse text: {}", rep.error.message, rep.text);return false;}LOG_INFO("delete sucess!, status code:{}, removeid:/{}/_doc/{}", rep.status_code, index_name_, id);return true;}catch (const std::exception& e){LOG_ERROR("DeleteId error:{}", e.what());last_error_ = e.what();}return false;}bool DeleteIndex(){try{if (index_name_.empty()){LOG_WARN("索引名未设置!");return false;}if(!indexExists(es_client_, index_name_)){LOG_WARN("索引-{}不存在,删除索引失败!", index_name_);return false;}auto rep = es_client_->performRequest(elasticlient::Client::HTTPMethod::DELETE, index_name_, "");if (rep.status_code < 200 || rep.status_code >= 300){LOG_ERROR("query error:{}, reponse text: {}", rep.error.message, rep.text);return false;}LOG_INFO("delete sucess!, status code:{}, removeindex:/{}", rep.status_code, index_name_);return true;}catch (const std::exception& e){LOG_ERROR("DeleteIndex error:{}", e.what());last_error_ = e.what();}return false;}~ESDelete(){LOG_INFO("ESDlete 实例已销毁!");}private:std::shared_ptr<elasticlient::Client> es_client_; // ES客户端(智能指针管理)std::string last_error_; // 最后一次错误信息std::string index_name_;};
};