这个示例使用了 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;
}
```
编译和运行说明
- **依赖库**:
-
libcurl: HTTP 客户端库
-
nlohmann/json: 单头文件 JSON 库
- **安装依赖** (Ubuntu):
```bash
sudo apt-get install libcurl4-openssl-dev
```
- **编译命令**:
```bash
g++ -std=c++11 -o elasticsearch_example elasticsearch_example.cpp -lcurl
```
- **运行前准备**:
-
确保 Elasticsearch 在 `http://localhost:9200` 运行
-
安装 nlohmann/json 头文件(或直接包含单文件版本)
示例功能说明
- **创建索引**:
- 创建一个名为 "cplusplus_test" 的索引
- **索引文档**:
-
添加两个包含 C++ 相关内容的文档
-
自动生成文档 ID
- **执行搜索**:
-
搜索包含 "C++" 的文档
-
显示搜索结果(ID、得分、标题、内容、年份和标签)
扩展建议
- **错误处理增强**:
-
添加更详细的错误日志
-
处理 HTTP 状态码(如 404、500 等)
- **连接池管理**:
-
实现连接复用
-
添加超时设置
- **认证支持**:
```cpp
curl_easy_setopt(curl, CURLOPT_USERPWD, "username:password");
```
- **批量操作**:
-
实现批量索引文档
-
使用 `_bulk` API
- **异步操作**:
-
使用 libcurl 的多接口实现异步请求
-
或使用线程池
- **映射管理**:
- 添加创建映射的功能
```cpp
json mapping = {
{"mappings", {
{"properties", {
{"title", {{"type", "text"}}},
{"year", {{"type", "integer"}}}
}}
}}
};
performRequest("PUT", "/" + indexName, mapping);
```
- **SSL/TLS 支持**:
```cpp
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 禁用证书验证(仅测试用)
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
```
这个示例展示了如何用 C++ 与 Elasticsearch 交互的基本操作。在实际项目中,你可能需要根据具体需求扩展这个基础实现。