es的封装

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

文章目录


前言

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


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

一、类和接口介绍

0.封装思想

ES客户端API二次封装:
封装四个操作 :索引创建,数据新增,数据查询,数据删除
封装最主要要完成的是请求正文的构造过程: Json::Value 对象的数据新增过程

索引创建:

1.能够动态设定索引名称,索引类型

2.能够动态的添加字段,并设置字段类型, 设置分词器类型,是否构造索引

构造思想:根据固定的ison格式构造Value对象即可

数据新增:

1.提供用户一个新增字段及数据的接口即可

2.提供一个发起请求的接口

1.es的操作分类

对于ES的操作请求分类:

1.创建索引

2.新增数据

  1. 查询数据

4.删除数据

下面是我们需要使用到的接口,search是用于查询数据,第二个index是用户索引创建和新增数据两个功能,第三个接口是用于删除数据的。最后一个接口时创建一个客户端,用于和es服务器进行通信。前面的三个接口都是这个client提供的。

上面的三个接口的返回值都是一个response对象,这里是这个对象的定义,有一个响应码,和一个响应码描述。

二、创建索引

1.成员变量

这个类中有五个成员变量

name就是索引名,type就是一个类型我们这里的类型都填一个_doc.

第三个变量就是一个Json对象,这个proerties就是我们要创建索引有哪些字段,我们这里是以用户索引为例,项目中,用户的信息有用户昵称,电话,用户id,个性签名,头像Id。所以在我们的这个proerties中就要有这几个字段。这也是我们创建索引中最核心的部分。

第四个变量_index就是我们创建索引的总的一个json正文,我们给服务器发送请求,就是发送的这个json串。

第五个参数就是一个client,我们需要通过这个对象给服务器发送请求。

cpp 复制代码
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操作的请求体进行分析。 后面复习看到这里记得看图!!!

cpp 复制代码
 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。

cpp 复制代码
 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内部如果失败会抛出异常。为了防止程序异常崩溃,我们捕获一下。

cpp 复制代码
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.创建索引总体代码

cpp 复制代码
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:"小明"。

cpp 复制代码
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。

cpp 复制代码
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。分别代表必须不满足的条件,可选满足条件,必须满足条件。

cpp 复制代码
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;
};
}
相关推荐
StarRocks_labs7 小时前
从InfluxDB到StarRocks:Grab实现Spark监控平台10倍性能提升
大数据·数据库·starrocks·分布式·spark·iris·物化视图
若兰幽竹8 小时前
【Spark分析HBase数据】Spark读取并分析HBase数据
大数据·spark·hbase
R²AIN SUITE8 小时前
金融合规革命:R²AIN SUITE 如何重塑银行业务智能
大数据·人工智能
绿算技术9 小时前
“强强联手,智启未来”凯创未来与绿算技术共筑高端智能家居及智能照明领域新生态
大数据·人工智能·智能家居
只因只因爆10 小时前
spark的缓存
大数据·缓存·spark
Leo.yuan11 小时前
3D 数据可视化系统是什么?具体应用在哪方面?
大数据·数据库·3d·信息可视化·数据分析
只因只因爆12 小时前
spark小任务
大数据·分布式·spark
cainiao08060512 小时前
Java 大视界——Java 大数据在智慧交通智能停车诱导系统中的数据融合与实时更新
java·大数据·开发语言
End92815 小时前
Spark之搭建Yarn模式
大数据·分布式·spark
我爱写代码?15 小时前
Spark 集群配置、启动与监控指南
大数据·开发语言·jvm·spark·mapreduce