1. 程式人生 > >為elasticSearch開發c++接口

為elasticSearch開發c++接口

upd 內存 重復 sea 第四部分 head 插件 權限 彈性

一、 ElasticSearch是什麽

ElasticSearch是目前開源全文搜索引擎的首選,可以快速存儲,搜索和分析海量數據。Stack Overflow,Github等都在使用。

Elasticsearch 是使用 Java 編寫的,它的內部使用 Lucene 做索引與搜索,但是它使全文檢索變得簡單, 通過隱藏 Lucene 的復雜性,取而代之的提供一套簡單一致的 RESTful API。

ES提供的Client API:https://www.elastic.co/guide/en/elasticsearch/client/index.html

包含多種語言:

技術分享圖片

技術分享圖片

註意:沒有C++接口,而我們需要基於c++操作ES

二、 安裝部署

1. 服務器選擇

設備IP:10.3.246.224

系統:linux-64

磁盤空間:無 (df –h 發現磁盤沒容量了)

2. 解決磁盤占滿

du -sh /* | sort –nr :找出系統中占容量最大的文件夾,系統中15scpp這個文件夾占41G

du -sh /15scpp/* | sort -nr :找出15scpp中占容量最大文件夾15scpp_testbin,占31G

確認這個文件夾已無用,rm刪除

PS:在Linux中,當我們使用rm在linux上刪除了大文件,但是如果有進程打開了這個大文件,卻沒有關閉這個文件的句柄,那麽linux內核還是不會釋放這個文件的磁盤空間。找出文件使用進程,kill掉,即可

3. JDK8安裝

Elastic 需要 Java 8 環境

Java –version查看java是否安裝或現在版本

官網下載jdk-8u181-linux-x64.tar.gz,解壓,安裝,設置環境變量,這裏就不贅述。

1. 下載ES

下載https://www.elastic.co/downloads/elasticsearch :

elasticsearch-6.3.2.tar.gz

tar解壓

2. 創建新用戶

因為安全問題elasticsearch 不讓用root用戶直接運行,所以要創建新用戶:

adduser pwrd-es

passwd pwrd-es pwrd-es

3. 修改安裝文件權限

chown -R pwrd-es:pwrd-es /home/elasticSearch/elasticsearch-6.3.2

//因為安全問題,不讓root用戶執行安裝,但是其他用戶又沒有文件操作權限,故而改之

4. 修改ES配置

Vim config/elasticSearch.yml

cluster.name: pwrd-es //Elasticsearch會自動發現在同一網段下的Elasticsearch 節點,用這個屬性來區分不同的集群,cluster.name相同則自動組建成一個集群

node.name: node-1 //節點名,默認隨機指定一個name列表中名字,不能重復

node.master: true //指定該節點是否有資格被選舉成為node,默認是true,es是默認集群中的第一臺機器為master,如果這臺機掛了就會重新選舉master

node.data: true //指定該節點是否存儲索引數據,默認為true

path.data: /home/elasticSearch/log_export/data //存儲數據

path.logs: /home/elasticSearch/log_export/logs //存儲日誌

network.host: 10.3.246.224 //設置成0.0.0.0 在curl中可以用localhost

http.port: 9200 //監聽端口

index.number_of_shards: 5 // 設置默認索引分片個數,默認為5片

index.number_of_replicas: 1 //設置默認索引副本個數,默認為1個副本

5. 修改系統最大虛擬內存

vim /etc/sysctl.conf

vm.max_map_count = 655360

sysctl -p

6. 切換用戶執行程序

切換用戶: su pwrd-es

./elasticsearch

7. 驗證安裝效果

瀏覽器中輸入10.3.246.224:9200

或者

curl ‘http://localhost:9200/?pretty‘

可以看到一個json數據,即為安裝成功

PS:pretty是為了json格式化,以至於返回的結果好看一些

一、 基本概念

1. Node 與 Cluster

Elastic 本質上是一個分布式數據庫,允許多臺服務器協同工作,每臺服務器可以運行多個 Elastic 實例。

單個 Elastic 實例稱為一個節點(node)。一組節點構成一個集群(cluster)

通過cluster.name 屬性配置集群的名字,用於唯一標識一個集群,不同的集群,其cluster.name 不同,集群名字相同的所有節點自動組成一個集群。當啟動一個結點時,該結點會在當前局域網內自動尋找相同集群名字的主結點;如果找到主結點,該結點加入集群中;如果未找到主結點,該結點成為主結點

2. Index

ES基本結構是 : index/type/id -> document (一般以json樣式存儲數據)

所以Index(索引)是Elastic 數據管理的頂層單位,它是單個數據庫的同義詞。

ES會索引所有字段,經過處理後寫入一個反向索引(Inverted Index)。查找數據的時候,直接查找該索引。

PS:每個 Index (即數據庫)的名字必須是小寫。

可以用如下命令,查看當前節點索引:

curl -X GET ‘http://localhost:9200/_cat/indices?v‘

3. Document

Index裏面單條的記錄稱為 Document(文檔)。許多條 Document 構成了一個 Index。

Document 使用 JSON 格式表示,如下:

{

“name”:”張三”,

“age”:18,

“sex”:”male”

}

PS:對於json的編寫與格式是否正確,可以借助在線json工具:http://www.bejson.com/

4. Type

Type可以用來分類document,比如,china/Beijing/id-i ->doc-n

china/shanghai/id-j ->doc-m

同一個Index下不同的 Type 應該有相似的結構。

但是,Elastic 6.x 版只允許每個 Index 包含一個 Type,7.x 版將會徹底移除 Type。

我們部署的是當前最新6.3.2版本

5. Shared分片

當一個索引下的數據太多,超過單一節點所能提供的磁盤空間,ES提供分片功能,可以將海量數據分片存儲到集群中不同的節點中。當你查詢的索引分布在多個分片上時,ES會把查詢發送給每個相關的分片,並將結果組合在一起,而應用程序並不知道分片的存在。即:這個過程對用戶來說是透明的。

6. Replicas副本

為提高查詢吞吐量或實現高可用性,可以使用分片副本。

副本是一個分片的精確復制,每個分片可以有零個或多個副本。ES中可以有許多相同的分片,其中之一被選擇更改索引操作,這種特殊的分片稱為主分片。

當主分片丟失時,如:該分片所在的數據不可用時,集群將副本提升為新的主分片。

7. ES數據架構概念與Mysql對比

技術分享圖片

但是目前type即將作廢。

四、 CRUD簡介

1. 創建索引

curl -XPUT "http://10.3.246.224:9200/tests/"

返回數據

{

"acknowledged": true,

"shards_acknowledged": true,

"index": "testes"

}

2. 添加數據

curl -XPUT "http://10.3.246.224:9200/tests/songs/1" -d ‘{"name":"deck the halls","year":"2018","month":"8"}‘ 會報錯,如下指定header就可以了

curl -H "Content-Type: application/json" -XPUT "http://10.3.246.224:9200/tests/songs/1" -d ‘{"name":"deck the halls","year":"2018","month":"8"}‘

返回結果:

{

"_index": "testes",

"_type": "songs",

"_id": "1", //id 也可以不知道,由系統自主生成

"_version": 1,

"result": "created",//代表添加成功

"_shards": {

"total": 2,

"successful": 1,

"failed": 0

},

"_seq_no": 0,

"_primary_term": 1

}

3. 讀取數據

curl -XGET http://localhost:9200/music/songs/1?pretty

返回數據:

{

"_index" : "testes",

"_type" : "songs",

"_id" : "1",

"_version" : 1,

"found" : true, //查找成功

"_source" : { //目的數據

"name" : "deck the halls",

"year" : "2018",

"month" : "8"

}

}

4. 更新數據

a) 查找更新某個key:

curl -H "Content-Type: application/json" -XPOST "http://10.3.246.224:9200/testes/songs/1/_update?pretty" -d ‘{"doc":{"query":{"match":{"name":"qqqddd"}}}}‘

返回數據:

{

"_index" : "testes",

"_type" : "songs",

"_id" : "1",

"_version" : 2,

"result" : "updated",//更新成功

"_shards" : {

"total" : 2,

"successful" : 1,

"failed" : 0

},

"_seq_no" : 1,

"_primary_term" : 1

}

b) 更新整條數據:

curl -H "Content-Type: application/json" -XPOST "http://10.3.246.224:9200/testes/songs/1/_update?pretty" -d ‘{"doc":{"name":"qddd","year":"2018","month":"8"}}‘

返回數據同上

c) 還有就是用添加數據的命令:只是將數據改了

curl -H "Content-Type: application/json" -XPUT "http://10.3.246.224:9200/tests/songs/1" -d ‘{"name":"deck the halls","year":"2020","month":"8"}‘

5. 刪除數據

curl -XDELETE "http://localhost:9200/music/songs/1"

返回數據:

{

"_index": "tests",

"_type": "songs",

"_id": "1",

"_version": 2,

"result": "deleted",//刪除成功

"_shards": {

"total": 2,

"successful": 1,

"failed": 0

},

"_seq_no": 1,

"_primary_term": 1

}

註意:刪除一個文檔不會立即生效,它只是被標記成已刪除。es將會在你之後添加更多索引的時候才會在後臺進行刪除內容的清理

五、 ES的C++ API開發

1. ES沒有C++的接口,而我們需要基於c++操作ES

有兩個辦法

一是嵌入其他語言的開發,利用ES已提供的接口,比如,在C++中嵌入python API,這在編譯上可能引入新的問題

二是需要自己構造如第四部分的http請求來獲得數據,可以基於libcurl庫,也可以基於系統中已有的httpproxy

為了不破壞已有系統的一致性,基於httpproxy,來構造http請求,對外封裝提供C++接口

2. 基於業務需求設計思想

/*es是面向文檔,基於索引的彈性搜索引擎,故而

*es中的數據結構:index/type/id ->對應一條數據,所以

*es中帖子的數據結構設計:

uid/tiezi/tid -> json{uid,tid,content,timestamp}

*雖然存在uid和tid的冗余,但是這樣設計的好處是:可以很方便處理某個人某條數據,因為uid就是索引,這樣還利用了,索引的高處理性能

*/

3. C++ API

1) 添加

/*功能:向es中添加protobuf數據,但是在es中是以json樣式存在

*uid:用戶id

*tid:帖子id

*msg:帖子結構,即(uid,tid,content,timestamp)

*/

bool addDocument(const std::string &uid, const std::string &tid,const google::protobuf::Message *msg);

封裝後形成的http請求:

curl -H "Content-Type: application/json" -XPUT "http://10.3.246.224:9200/ uid /tiezi/tid " -d ‘ msg .json_str()‘

2) 刪除

/*功能:向es中刪除某個人uid的所有數據

*uid:用戶id

*/

bool deleteAllByUid(const std::string &uid);

封裝後形成的http請求:

curl -XDELETE http://localhost:9200/uid -d ‘{“query”:{“match_all”:{}}}’

/*功能:向es中刪除某個人具體的某個數據

*uid:用戶id

*tid:帖子id

*/

bool deleteDocumentByUidTid(const std::string &uid, const std::string &tid);

封裝後形成的http請求:

curl -XDELETE "http://localhost:9200/ uid / tiezi / tid "

/*功能:向es中刪除某個用戶某個時間點以前的所有帖子,也就是 小於 某個時間的所有帖子

*uid:用戶id

*beforeTimes:時刻以前的數據將全部會刪除

*/

bool deleteDocumentByUidBeforeTimes(const std::string &uid, const std::string &beforeTimes);

封裝後形成的http請求:

curl -XPOST "http://localhost:9200/ uid /tiezi/_delete_by_query

-d‘{"query":{"range":{"timestamp.keyword":{"gte":"2016-07-09 11:18:21","lte":"2018-08-17 11:18:21","format":"yyyy-MM-dd HH:mm:ss"}}}}’

PS: timestamp是數據中一個字段,在時間段匹配中,要註意空格

3) 查詢

/*功能:以或的邏輯關系操作查詢帖子中是否存在包含詞,並過濾返回結果,只返回並得到UID,tid

*註:比如查詢詞是詞組:"running swimming",查詢之後的結果是,只要帖子content中至少包含一個詞匯就可以,即帖子content中包含"running","swimming","running ... swimming ..."都返回

*containsWords:查詢詞 或詞組 ,比如 "sport","running swimming"

*uid_tid:查詢成功返回的N條uid和tid數據

*/

int searchAllByContainWords_OR(const std::string &containsWords,vector<struct Uid_Tid> &uid_tid);

封裝後形成的http請求:

curl -H "Content-Type: application/json" -XPOST "http://localhost:9200/_search

-d ‘{"query":{"match": {"content":{"query":"swimming running"","operator":"or"}}},"_source":["uid","tid"]}’

PS: operator 是or,表示是或邏輯操作,query中填寫多個字段,匹配數據字段content中存在swimming或running,_source 中有數據字段uid和tid,用來控制返回結果的,當數據量很大的時候對結果裁剪,減少無用的數據傳輸

/*功能:以與的邏輯關系操作查詢帖子中是否存在包含詞,並過濾返回結果,只返回並得到UID,tid

*註:比如查詢詞是詞組:"running swimming",查詢之後的結果是,帖子content中包含每個詞匯,即帖子content中包含running和 swimming才返回

*containsWords:查詢詞 或詞組 ,比如 "sport","running swimming"

*uid_tid:查詢成功返回的N條uid和tid數據

*/

Int searchAllByContainWords_AND(const std::string &containsWords,vector<struct Uid_Tid> &uid_tid);

封裝後形成的http請求:

curl -H "Content-Type: application/json" -XPOST "http://localhost:9200/_search

-d ‘{"query":{"match": {"content":{"query":"swimming running"","operator":"and"}}},"_source":["uid","tid"]}’

PS:同上,區別是operator是and,表示是與邏輯操作

類似c++ API接口參考:https://github.com/QHedgeTech/cpp-elasticsearch

六、 資料

1. ES參考手冊

https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html

2. 《ElasticSearch權威指南》

https://www.elastic.co/guide/cn/elasticsearch/guide/current/intro.html

3. 中文社區

https://elasticsearch.cn/

4. 英文社區

https://discuss.elastic.co/c/elasticsearch/

七、 插件

1. Head插件

在chrome中直接安裝的插件,要比在linux下命令安裝簡單

2. Ik分詞插件

八、 其他

ES也提供對數據的分析,功能非常強大,還有很多像ik這樣分詞插件,我們在瀏覽器中訪問es服務,在web界面中也可以很方便的操作數據。了解的非常淺顯,暫記於此,以待有機會深入了解。對於json格式以及json中數據空格也需要非常註意。

為elasticSearch開發c++接口