使用 C++ 调用 Elasticsearch API

发布于:2025-07-15 ⋅ 阅读:(21) ⋅ 点赞:(0)

这个示例使用了 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 交互的基本操作。在实际项目中,你可能需要根据具体需求扩展这个基础实现。

 


网站公告

今日签到

点亮在社区的每一天
去签到