自学内容网 自学内容网

es的封装

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

es他使用的网络协议时http,序列化协议用的json。而es客户端给我们提供的三个接口中,我们需要填的就是一个请求正文,所以我们主要是针对这个正文json的一个组织。
这里贴一个连接,里面是一些请求格式:
es基本请求格式


提示:以下是本篇文章正文内容,下面案例可供参考

一、类和接口介绍

0.封装思想

ES客户端API二次封装:
封装四个操作:索引创建,数据新增,数据查询,数据删除
封装最主要要完成的是请求正文的构造过程: Json::Value 对象的数据新增过程
索引创建:
1.能够动态设定索引名称,索引类型
2.能够动态的添加字段,并设置字段类型, 设置分词器类型,是否构造索引
构造思想:根据固定的ison格式构造Value对象即可
数据新增:
1.提供用户一个新增字段及数据的接口即可
2.提供一个发起请求的接口

1.es的操作分类

对于ES的操作请求分类:
1.创建索引
2.新增数据
3. 查询数据
4.删除数据
下面是我们需要使用到的接口,search是用于查询数据,第二个index是用户索引创建和新增数据两个功能,第三个接口是用于删除数据的。最后一个接口时创建一个客户端,用于和es服务器进行通信。前面的三个接口都是这个client提供的。
在这里插入图片描述
上面的三个接口的返回值都是一个response对象,这里是这个对象的定义,有一个响应码,和一个响应码描述。
在这里插入图片描述

二、创建索引

1.成员变量

这个类中有五个成员变量
name就是索引名,type就是一个类型我们这里的类型都填一个_doc.
第三个变量就是一个Json对象,这个proerties就是我们要创建索引有哪些字段,我们这里是以用户索引为例,项目中,用户的信息有用户昵称,电话,用户id,个性签名,头像Id。所以在我们的这个proerties中就要有这几个字段。这也是我们创建索引中最核心的部分。
第四个变量_index就是我们创建索引的总的一个json正文,我们给服务器发送请求,就是发送的这个json串。
第五个参数就是一个client,我们需要通过这个对象给服务器发送请求。

std::string _name;
std::string _type;
Json::Value _properties;
Json::Value _index;
std::shared_ptr<elasticlient::Client> _client;

2.构造函数

在构造函数中,用户需要闯入两个参数,一个就是一个client,用户需要自己定义一个client然后闯入进来,第二个就是你要创建的索引名。
在构造函数的函数体中主要是组织了settings部分的json。其中tokenizer是分词工具,我们填入的是ik_max_work它可以支持中文分词。这里具体要看es操作的请求体进行分析。 后面复习看到这里记得看图!!!

 ESIndex(std::shared_ptr<elasticlient::Client> &client, 
            const std::string &name, 
            const std::string &type = "_doc"):
            _name(name), _type(type), _client(client) {
            Json::Value analysis;
            Json::Value analyzer;
            Json::Value ik;
            Json::Value tokenizer;
            tokenizer["tokenizer"] = "ik_max_word";
            ik["ik"] = tokenizer;
            analyzer["analyzer"] = ik;
            analysis["analysis"] = analyzer;
            _index["settings"] = analysis;
        }

2.添加字段

我们要创建的索引,它里面有哪些字段,比如用户索引,就有用户id,昵称,签名,手机号等。如果是一个消息索引,就有消息id,消息时间,消息体等。
用户需要指定key,也就是哪一个字段。其中type就是字段的类型,axalyzer就是分词工具,enable是是否参与索引,这里我们默认是true,对于一些用户索引,我们的用户昵称,用户id,手机号是要参与索引的于是要设为true.
另外这个type,如果设置为text就代表进行分词,就需要设置分词工具,type类型为keyword就代表不进行分词。另外这里我们这里对enable进行了一个判断,如果他为false,我们才添加到json中,原因是es会默认添加enable:true。

 ESIndex& append(const std::string &key, 
            const std::string &type = "text", 
            const std::string &analyzer = "ik_max_word", 
            bool enabled = true) {
            Json::Value fields;
            fields["type"] = type;
            fields["analyzer"] = analyzer;
            if (enabled == false ) fields["enabled"] = enabled;
            _properties[key] = fields;
            return *this;
        }

3.发送请求

这里需要一个索引Id,防止对于同一个索引类型创建出多个索引,这里我们有默认参数,不许用户提供了。这里面就会对总的Json进行一个组织,然后调用client的index进行一个请求发送。他会返回一个response对象,我们根据这个对象里的响应码判断是否成功。需要对这个发送请求进行捕获,在index内部如果失败会抛出异常。为了防止程序异常崩溃,我们捕获一下。

bool create(const std::string &index_id = "default_index_id") {
   Json::Value mappings;
     mappings["dynamic"] = true;
     mappings["properties"] = _properties;
     _index["mappings"] = mappings;

     std::string body;
     bool ret = Serialize(_index, body);
     if (ret == false) {
         LOG_ERROR("索引序列化失败!");
         return false;
     }
     LOG_DEBUG("{}", body);
     //2. 发起搜索请求
     try {
         auto rsp = _client->index(_name, _type, index_id, body);
         if (rsp.status_code < 200 || rsp.status_code >= 300) {
             LOG_ERROR("创建ES索引 {} 失败,响应状态码异常: {}", _name, rsp.status_code);
             return false;
         }
     } catch(std::exception &e) {
         LOG_ERROR("创建ES索引 {} 失败: {}", _name, e.what());
         return false;
     }
     return true;
 }

4.创建索引总体代码

class ESIndex {
    public:
        ESIndex(std::shared_ptr<elasticlient::Client> &client, 
            const std::string &name, 
            const std::string &type = "_doc"):
            _name(name), _type(type), _client(client) {
            Json::Value analysis;
            Json::Value analyzer;
            Json::Value ik;
            Json::Value tokenizer;
            tokenizer["tokenizer"] = "ik_max_word";
            ik["ik"] = tokenizer;
            analyzer["analyzer"] = ik;
            analysis["analysis"] = analyzer;
            _index["settings"] = analysis;
        }
        ESIndex& append(const std::string &key, 
            const std::string &type = "text", 
            const std::string &analyzer = "ik_max_word", 
            bool enabled = true) {
            Json::Value fields;
            fields["type"] = type;
            fields["analyzer"] = analyzer;
            if (enabled == false ) fields["enabled"] = enabled;
            _properties[key] = fields;
            return *this;
        }
        bool create(const std::string &index_id = "default_index_id") {
            Json::Value mappings;
            mappings["dynamic"] = true;
            mappings["properties"] = _properties;
            _index["mappings"] = mappings;

            std::string body;
            bool ret = Serialize(_index, body);
            if (ret == false) {
                LOG_ERROR("索引序列化失败!");
                return false;
            }
            LOG_DEBUG("{}", body);
            //2. 发起搜索请求
            try {
                auto rsp = _client->index(_name, _type, index_id, body);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("创建ES索引 {} 失败,响应状态码异常: {}", _name, rsp.status_code);
                    return false;
                }
            } catch(std::exception &e) {
                LOG_ERROR("创建ES索引 {} 失败: {}", _name, e.what());
                return false;
            }
            return true;
        }
    private:
        std::string _name;
        std::string _type;
        Json::Value _properties;
        Json::Value _index;
        std::shared_ptr<elasticlient::Client> _client;
};

三.插入数据

插入请求的请求正文比较简单,就是对你插入数据的个字段进行一个组织就行。例如用户信息索引,就有昵称,用户Id,签名,电话等。我们把它组织到一个json中,在这里成员变量定义了一个item进行组织。通过append函数进行组织。用户只需要填写key和val.例如nickname:“小明”。

class ESInsert {
    public:
        ESInsert(std::shared_ptr<elasticlient::Client> &client, 
            const std::string &name, 
            const std::string &type = "_doc"):
            _name(name), _type(type), _client(client){}
        template<typename T>
        ESInsert &append(const std::string &key, const T &val){
            _item[key] = val;
            return *this;
        }
        bool insert(const std::string id = "") {
            std::string body;
            bool ret = Serialize(_item, body);
            if (ret == false) {
                LOG_ERROR("索引序列化失败!");
                return false;
            }
            LOG_DEBUG("{}", body);
            //2. 发起搜索请求
            try {
                auto rsp = _client->index(_name, _type, id, body);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("新增数据 {} 失败,响应状态码异常: {}", body, rsp.status_code);
                    return false;
                }
            } catch(std::exception &e) {
                LOG_ERROR("新增数据 {} 失败: {}", body, e.what());
                return false;
            }
            return true;
        }
    private:
        std::string _name;
        std::string _type;
        Json::Value _item;
        std::shared_ptr<elasticlient::Client> _client;
};

四.删除数据

删除数据没有正文体,只需要提供你要删除的索引,类型,以及一个文档id。

class ESRemove {
public:
    ESRemove(std::shared_ptr<elasticlient::Client> &client, 
        const std::string &name, 
        const std::string &type = "_doc"):
        _name(name), _type(type), _client(client){}
    bool remove(const std::string &id) {
        try {
            auto rsp = _client->remove(_name, _type, id);
            if (rsp.status_code < 200 || rsp.status_code >= 300) {
                LOG_ERROR("删除数据 {} 失败,响应状态码异常: {}", id, rsp.status_code);
                return false;
            }
        } catch(std::exception &e) {
            LOG_ERROR("删除数据 {} 失败: {}", id, e.what());
            return false;
        }
        return true;
    }
private:
    std::string _name;
    std::string _type;
    std::shared_ptr<elasticlient::Client> _client;
};

五.查询数据

查询这里,我们需要添加一些"过滤条件",在es中有must_not/should/must/三个Json。分别代表必须不满足的条件,可选满足条件,必须满足条件。

class ESSearch {
    public:
        ESSearch(std::shared_ptr<elasticlient::Client> &client, 
            const std::string &name, 
            const std::string &type = "_doc"):
            _name(name), _type(type), _client(client){}
        ESSearch& append_must_not_terms(const std::string &key, const std::vector<std::string> &vals) {
            Json::Value fields;
            for (const auto& val : vals){
                fields[key].append(val);
            }
            Json::Value terms;
            terms["terms"] = fields;
            _must_not.append(terms);
            return *this;
        }
        ESSearch& append_should_match(const std::string &key, const std::string &val) {
            Json::Value field;
            field[key] = val;
            Json::Value match;
            match["match"] = field;
            _should.append(match);
            return *this;
        }
        ESSearch& append_must_term(const std::string &key, const std::string &val) {
            Json::Value field;
            field[key] = val;
            Json::Value term;
            term["term"] = field;
            _must.append(term);
            return *this;
        }
        ESSearch& append_must_match(const std::string &key, const std::string &val){
            Json::Value field;
            field[key] = val;
            Json::Value match;
            match["match"] = field;
            _must.append(match);
            return *this;
        }
        Json::Value search(){
            Json::Value cond;
            if (_must_not.empty() == false) cond["must_not"] = _must_not;
            if (_should.empty() == false) cond["should"] = _should;
            if (_must.empty() == false) cond["must"] = _must;
            Json::Value query;
            query["bool"] = cond;
            Json::Value root;
            root["query"] = query;

            std::string body;
            bool ret = Serialize(root, body);
            if (ret == false) {
                LOG_ERROR("索引序列化失败!");
                return Json::Value();
            }
            LOG_DEBUG("{}", body);
            //2. 发起搜索请求
            cpr::Response rsp;
            try {
                rsp = _client->search(_name, _type, body);
                if (rsp.status_code < 200 || rsp.status_code >= 300) {
                    LOG_ERROR("检索数据 {} 失败,响应状态码异常: {}", body, rsp.status_code);
                    return Json::Value();
                }
            } catch(std::exception &e) {
                LOG_ERROR("检索数据 {} 失败: {}", body, e.what());
                return Json::Value();
            }
            //3. 需要对响应正文进行反序列化
            LOG_DEBUG("检索响应正文: [{}]", rsp.text);
            Json::Value json_res;
            ret = UnSerialize(rsp.text, json_res);
            if (ret == false) {
                LOG_ERROR("检索数据 {} 结果反序列化失败", rsp.text);
                return Json::Value();
            }
            return json_res["hits"]["hits"];
        }
    private:
        std::string _name;
        std::string _type;
        Json::Value _must_not;
        Json::Value _should;
        Json::Value _must;
        std::shared_ptr<elasticlient::Client> _client;
};
}

原文地址:https://blog.csdn.net/2301_77412625/article/details/142324009

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!