这个示例使用了 libcurl 库进行 HTTP 请求和 nlohmann/json 库处理 JSON 数据:
```cpp
#include <iostream>
#include <string>
#include <curl/curl.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// libcurl 的回调函数,用于收集响应数据
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
// Elasticsearch 客户端类
class ElasticsearchClient {
private:
std::string host;
CURL* curl;
public:
ElasticsearchClient(const std::string& host = "http://localhost:9200") : host(host) {
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (!curl) {
throw std::runtime_error("Failed to initialize cURL");
}
}
~ElasticsearchClient() {
if (curl) curl_easy_cleanup(curl);
curl_global_cleanup();
}
// 执行 HTTP 请求
json performRequest(const std::string& method,
const std::string& endpoint,
const json& body = json()) {
std::string responseString;
std::string url = host + endpoint;
// 设置 cURL 选项
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &responseString);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method.c_str());
// 设置请求体(如果有)
std::string bodyString = body.dump();
if (!bodyString.empty() && bodyString != "null") {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyString.c_str());
struct curl_slist* headers = nullptr;
headers = curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
}
// 执行请求
CURLcode res = curl_easy_perform(curl);
// 检查错误
if (res != CURLE_OK) {
throw std::runtime_error("cURL failed: " + std::string(curl_easy_strerror(res)));
}
// 解析 JSON 响应
if (!responseString.empty()) {
return json::parse(responseString);
}
return json();
}
// 创建索引
bool createIndex(const std::string& indexName) {
try {
auto response = performRequest("PUT", "/" + indexName);
return response.value("acknowledged", false);
} catch (...) {
return false;
}
}
// 索引文档
std::string indexDocument(const std::string& indexName, const json& document) {
try {
auto response = performRequest("POST", "/" + indexName + "/_doc", document);
return response.value("_id", "");
} catch (...) {
return "";
}
}
// 搜索文档
json searchDocuments(const std::string& indexName, const json& query) {
try {
return performRequest("GET", "/" + indexName + "/_search", query);
} catch (...) {
return json();
}
}
};
int main() {
try {
ElasticsearchClient es;
// 1. 创建索引
std::string indexName = "cplusplus_test";
if (es.createIndex(indexName)) {
std::cout << "索引创建成功: " << indexName << std::endl;
} else {
std::cout << "索引创建失败" << std::endl;
return 1;
}
// 2. 索引文档
json doc1 = {
{"title", "C++ Programming"},
{"content", "Guide to modern C++ features"},
{"year", 2023},
{"tags", json::array({"c++", "programming", "guide"})}
};
json doc2 = {
{"title", "Elasticsearch with C++"},
{"content", "How to use Elasticsearch in C++ applications"},
{"year", 2024},
{"tags", json::array({"c++", "elasticsearch", "api"})}
};
std::string id1 = es.indexDocument(indexName, doc1);
std::string id2 = es.indexDocument(indexName, doc2);
std::cout << "文档1 ID: " << id1 << "\n文档2 ID: " << id2 << std::endl;
// 等待索引刷新(生产环境中应使用更可靠的方式)
sleep(1);
// 3. 执行搜索
json searchQuery = {
{"query", {
{"match", {
{"content", "C++"}
}}
}},
{"size", 10}
};
auto searchResults = es.searchDocuments(indexName, searchQuery);
// 处理搜索结果
if (!searchResults.empty()) {
std::cout << "\n搜索结果 (" << searchResults["hits"]["total"]["value"] << " 个匹配):" << std::endl;
for (const auto& hit : searchResults["hits"]["hits"]) {
std::cout << "\nID: " << hit["_id"]
<< "\n得分: " << hit["_score"]
<< "\n标题: " << hit["_source"]["title"]
<< "\n内容: " << hit["_source"]["content"]
<< "\n年份: " << hit["_source"]["year"]
<< "\n标签: ";
for (const auto& tag : hit["_source"]["tags"]) {
std::cout << tag << " ";
}
std::cout << "\n------------------------------------" << std::endl;
}
} else {
std::cout << "未找到结果" << std::endl;
}
} catch (const std::exception& e) {
std::cerr << "错误: " << e.what() << std::endl;
return 1;
}
return 0;
}
```
### 编译和运行说明
1. **依赖库**:
- libcurl: HTTP 客户端库
- nlohmann/json: 单头文件 JSON 库
2. **安装依赖** (Ubuntu):
```bash
sudo apt-get install libcurl4-openssl-dev
```
3. **编译命令**:
```bash
g++ -std=c++11 -o elasticsearch_example elasticsearch_example.cpp -lcurl
```
4. **运行前准备**:
- 确保 Elasticsearch 在 `http://localhost:9200` 运行
- 安装 nlohmann/json 头文件(或直接包含单文件版本)
### 示例功能说明
1. **创建索引**:
- 创建一个名为 "cplusplus_test" 的索引
2. **索引文档**:
- 添加两个包含 C++ 相关内容的文档
- 自动生成文档 ID
3. **执行搜索**:
- 搜索包含 "C++" 的文档
- 显示搜索结果(ID、得分、标题、内容、年份和标签)
### 扩展建议
1. **错误处理增强**:
- 添加更详细的错误日志
- 处理 HTTP 状态码(如 404、500 等)
2. **连接池管理**:
- 实现连接复用
- 添加超时设置
3. **认证支持**:
```cpp
curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");
```
4. **批量操作**:
- 实现批量索引文档
- 使用 `_bulk` API
5. **异步操作**:
- 使用 libcurl 的多接口实现异步请求
- 或使用线程池
6. **映射管理**:
- 添加创建映射的功能
```cpp
json mapping = {
{"mappings", {
{"properties", {
{"title", {{"type", "text"}}},
{"year", {{"type", "integer"}}}
}}
}}
};
performRequest("PUT", "/" + indexName, mapping);
```
7. **SSL/TLS 支持**:
```cpp
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 禁用证书验证(仅测试用)
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
```
这个示例展示了如何用 C++ 与 Elasticsearch 交互的基本操作。在实际项目中,你可能需要根据具体需求扩展这个基础实现。