公司做網(wǎng)站花銷會計分錄發(fā)稿推廣
提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 前言
- 一、類和接口介紹
- 0.封裝思想
- 1.es的操作分類
- 二、創(chuàng)建索引
- 1.成員變量
- 2.構(gòu)造函數(shù)
- 2.添加字段
- 3.發(fā)送請求
- 4.創(chuàng)建索引總體代碼
- 三.插入數(shù)據(jù)
- 四.刪除數(shù)據(jù)
- 五.查詢數(shù)據(jù)
前言
es他使用的網(wǎng)絡(luò)協(xié)議時http,序列化協(xié)議用的json。而es客戶端給我們提供的三個接口中,我們需要填的就是一個請求正文,所以我們主要是針對這個正文json的一個組織。
這里貼一個連接,里面是一些請求格式:
es基本請求格式
提示:以下是本篇文章正文內(nèi)容,下面案例可供參考
一、類和接口介紹
0.封裝思想
ES客戶端API二次封裝:
封裝四個操作:索引創(chuàng)建,數(shù)據(jù)新增,數(shù)據(jù)查詢,數(shù)據(jù)刪除
封裝最主要要完成的是請求正文的構(gòu)造過程: Json::Value 對象的數(shù)據(jù)新增過程
索引創(chuàng)建:
1.能夠動態(tài)設(shè)定索引名稱,索引類型
2.能夠動態(tài)的添加字段,并設(shè)置字段類型, 設(shè)置分詞器類型,是否構(gòu)造索引
構(gòu)造思想:根據(jù)固定的ison格式構(gòu)造Value對象即可
數(shù)據(jù)新增:
1.提供用戶一個新增字段及數(shù)據(jù)的接口即可
2.提供一個發(fā)起請求的接口
1.es的操作分類
對于ES的操作請求分類:
1.創(chuàng)建索引
2.新增數(shù)據(jù)
3. 查詢數(shù)據(jù)
4.刪除數(shù)據(jù)
下面是我們需要使用到的接口,search是用于查詢數(shù)據(jù),第二個index是用戶索引創(chuàng)建和新增數(shù)據(jù)兩個功能,第三個接口是用于刪除數(shù)據(jù)的。最后一個接口時創(chuàng)建一個客戶端,用于和es服務(wù)器進行通信。前面的三個接口都是這個client提供的。
上面的三個接口的返回值都是一個response對象,這里是這個對象的定義,有一個響應(yīng)碼,和一個響應(yīng)碼描述。
二、創(chuàng)建索引
1.成員變量
這個類中有五個成員變量
name就是索引名,type就是一個類型我們這里的類型都填一個_doc.
第三個變量就是一個Json對象,這個proerties就是我們要創(chuàng)建索引有哪些字段,我們這里是以用戶索引為例,項目中,用戶的信息有用戶昵稱,電話,用戶id,個性簽名,頭像Id。所以在我們的這個proerties中就要有這幾個字段。這也是我們創(chuàng)建索引中最核心的部分。
第四個變量_index就是我們創(chuàng)建索引的總的一個json正文,我們給服務(wù)器發(fā)送請求,就是發(fā)送的這個json串。
第五個參數(shù)就是一個client,我們需要通過這個對象給服務(wù)器發(fā)送請求。
std::string _name;
std::string _type;
Json::Value _properties;
Json::Value _index;
std::shared_ptr<elasticlient::Client> _client;
2.構(gòu)造函數(shù)
在構(gòu)造函數(shù)中,用戶需要闖入兩個參數(shù),一個就是一個client,用戶需要自己定義一個client然后闖入進來,第二個就是你要創(chuàng)建的索引名。
在構(gòu)造函數(shù)的函數(shù)體中主要是組織了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.添加字段
我們要創(chuàng)建的索引,它里面有哪些字段,比如用戶索引,就有用戶id,昵稱,簽名,手機號等。如果是一個消息索引,就有消息id,消息時間,消息體等。
用戶需要指定key,也就是哪一個字段。其中type就是字段的類型,axalyzer就是分詞工具,enable是是否參與索引,這里我們默認是true,對于一些用戶索引,我們的用戶昵稱,用戶id,手機號是要參與索引的于是要設(shè)為true.
另外這個type,如果設(shè)置為text就代表進行分詞,就需要設(shè)置分詞工具,type類型為keyword就代表不進行分詞。另外這里我們這里對enable進行了一個判斷,如果他為false,我們才添加到j(luò)son中,原因是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.發(fā)送請求
這里需要一個索引Id,防止對于同一個索引類型創(chuàng)建出多個索引,這里我們有默認參數(shù),不許用戶提供了。這里面就會對總的Json進行一個組織,然后調(diào)用client的index進行一個請求發(fā)送。他會返回一個response對象,我們根據(jù)這個對象里的響應(yīng)碼判斷是否成功。需要對這個發(fā)送請求進行捕獲,在index內(nèi)部如果失敗會拋出異常。為了防止程序異常崩潰,我們捕獲一下。
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. 發(fā)起搜索請求try {auto rsp = _client->index(_name, _type, index_id, body);if (rsp.status_code < 200 || rsp.status_code >= 300) {LOG_ERROR("創(chuàng)建ES索引 {} 失敗,響應(yīng)狀態(tài)碼異常: {}", _name, rsp.status_code);return false;}} catch(std::exception &e) {LOG_ERROR("創(chuàng)建ES索引 {} 失敗: {}", _name, e.what());return false;}return true;}
4.創(chuàng)建索引總體代碼
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. 發(fā)起搜索請求try {auto rsp = _client->index(_name, _type, index_id, body);if (rsp.status_code < 200 || rsp.status_code >= 300) {LOG_ERROR("創(chuàng)建ES索引 {} 失敗,響應(yīng)狀態(tài)碼異常: {}", _name, rsp.status_code);return false;}} catch(std::exception &e) {LOG_ERROR("創(chuàng)建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;
};
三.插入數(shù)據(jù)
插入請求的請求正文比較簡單,就是對你插入數(shù)據(jù)的個字段進行一個組織就行。例如用戶信息索引,就有昵稱,用戶Id,簽名,電話等。我們把它組織到一個json中,在這里成員變量定義了一個item進行組織。通過append函數(shù)進行組織。用戶只需要填寫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. 發(fā)起搜索請求try {auto rsp = _client->index(_name, _type, id, body);if (rsp.status_code < 200 || rsp.status_code >= 300) {LOG_ERROR("新增數(shù)據(jù) {} 失敗,響應(yīng)狀態(tài)碼異常: {}", body, rsp.status_code);return false;}} catch(std::exception &e) {LOG_ERROR("新增數(shù)據(jù) {} 失敗: {}", body, e.what());return false;}return true;}private:std::string _name;std::string _type;Json::Value _item;std::shared_ptr<elasticlient::Client> _client;
};
四.刪除數(shù)據(jù)
刪除數(shù)據(jù)沒有正文體,只需要提供你要刪除的索引,類型,以及一個文檔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("刪除數(shù)據(jù) {} 失敗,響應(yīng)狀態(tài)碼異常: {}", id, rsp.status_code);return false;}} catch(std::exception &e) {LOG_ERROR("刪除數(shù)據(jù) {} 失敗: {}", id, e.what());return false;}return true;}
private:std::string _name;std::string _type;std::shared_ptr<elasticlient::Client> _client;
};
五.查詢數(shù)據(jù)
查詢這里,我們需要添加一些"過濾條件",在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. 發(fā)起搜索請求cpr::Response rsp;try {rsp = _client->search(_name, _type, body);if (rsp.status_code < 200 || rsp.status_code >= 300) {LOG_ERROR("檢索數(shù)據(jù) {} 失敗,響應(yīng)狀態(tài)碼異常: {}", body, rsp.status_code);return Json::Value();}} catch(std::exception &e) {LOG_ERROR("檢索數(shù)據(jù) {} 失敗: {}", body, e.what());return Json::Value();}//3. 需要對響應(yīng)正文進行反序列化LOG_DEBUG("檢索響應(yīng)正文: [{}]", rsp.text);Json::Value json_res;ret = UnSerialize(rsp.text, json_res);if (ret == false) {LOG_ERROR("檢索數(shù)據(jù) {} 結(jié)果反序列化失敗", 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;
};
}