準(zhǔn)備工作
-
了解es基本概念:elasticsearch(es)背景故事與基本概念
-
安裝es:Linux安裝Elasticsearch詳細(xì)教程
-
安裝kibana:Linux安裝Kibana詳細(xì)教程
-
熟悉Json
-
熟悉REST接口
檢查 es 及 Kibana 是否運行正常
GET /
創(chuàng)建索引及文檔
創(chuàng)建一個名為 twitter 的索引(index),并插入一個文檔(document)
PUT twitter/_doc/1
{
"user": "GB",
"uid": 1,
"city": "Beijing",
"province": "Beijing",
"country": "China"
}
在關(guān)系型數(shù)據(jù)庫中,需要使用DDL語句來創(chuàng)建數(shù)據(jù)庫和表,然后才可以插入數(shù)據(jù), es 不是必須的。
我們可以看到在 Kibana 右邊的窗口中有下面的輸出:
創(chuàng)建文檔相關(guān)知識點
-
在關(guān)系型數(shù)據(jù)庫中,創(chuàng)建表(對應(yīng)es的文檔)我們必須指定數(shù)據(jù)類型和長度,而es可以動態(tài)創(chuàng)建索引 mapping(mapping 指數(shù)據(jù)類型) 。
-
當(dāng)我們創(chuàng)建文檔時,如果沒有創(chuàng)建對應(yīng)的mapping,那么 es會根據(jù)所輸入字段的數(shù)據(jù)猜測數(shù)據(jù)類型,例如上面的 user 被被認(rèn)為是 text 類型,而 uid 將被猜測為整數(shù)類型。
-
在插入文檔時,如果該文檔的 ID 已經(jīng)存在,那么就更新現(xiàn)有的文檔;如果該文檔從來沒有存在過,那么就創(chuàng)建新的文檔。
-
如果更新時該文檔有新的字段并且這個字段在現(xiàn)有的 mapping 中沒有出現(xiàn),那么 es會根據(jù) schem on write 的策略來推測該字段的類型,并更新當(dāng)前的 mapping 到最新的狀態(tài)。
動態(tài) mapping 可能會導(dǎo)致某些字段不是我們想要的數(shù)據(jù)類型,從而導(dǎo)致索引請求失敗
解決方案(顯式 mapping)
明確定義索引映射
首先我們查看索引的數(shù)據(jù)類型(相當(dāng)于關(guān)系型數(shù)據(jù)庫的表結(jié)構(gòu))
GET twitter/_mapping
返回結(jié)果
{
"twitter" : {
"mappings" : {
"properties" : {
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"country" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"province" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"uid" : {
"type" : "long"
},
"user" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
我們拿city字段來分析
"city" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
mulit-field 字段
關(guān)于兩個type的解釋
為一個字段的不同目的創(chuàng)建不同方式索引,我們定義字段 city 為 text 類型, 但是text 類型的數(shù)據(jù)在攝入的時候會分詞,這樣它可以實現(xiàn)搜索的功能。 同時,這個字段又被定義為 keyword 類型,keyword 類型可以讓我們針對它進行精確匹配(比如區(qū)分大小寫,空格等符號),聚合和排序。
關(guān)于兩個keyword的解釋
第一個 keyword 可以是隨便定義,第二個 keyword 才是它的類型
mulit-field應(yīng)用場景
一個字段需要同時進行搜索和聚合
如果我們僅需要搜索或者聚合,那么我們只需要定義一種類型,可以提高數(shù)據(jù)攝入的速度,同時它也可以減少磁盤的使用。
es的數(shù)據(jù)類型:
- text:全文搜索字符串
- keyword:用于精確字符串匹配和聚合
- date 及 date_nanos:格式化為日期或數(shù)字日期的字符串
- byte,short,integer,long:整數(shù)類型 boolean:布爾類型
- float,double,half_float:浮點數(shù)類型 分級的類型:object 及 nested
數(shù)據(jù)類型相關(guān)知識
-
一般情況下,es可以很好的理解文檔的結(jié)構(gòu)并自動創(chuàng)建映射(mapping)定義。
-
自動創(chuàng)建映射使用無模式(schemaless)方法快速攝取數(shù)據(jù),無需擔(dān)心字段類型。
-
為了在索引中獲得更好搜索的結(jié)果和更好性能,我們有時需要需要手動定義映射。
微調(diào)映射帶來了一些優(yōu)勢
- 減少磁盤上的索引大?。ń米远x字段的功能) 僅索引感興趣的字段(一般加速) 用于快速搜索或?qū)崟r分析(例如聚合)
- 正確定義字段是否必須分詞為多個 token 或單個 token 定義映射類型,例如地理點、suggester、向量等
假如,我們想創(chuàng)建一個索引 test,并且含有 id 及 message 字段。id 字段為 keyword 類型,而 message 字段為 text 類型,那么我們可以使用如下的方法來創(chuàng)建:
PUT test
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"message": {
"type": "text"
}
}
}
}
我們甚至可以使用如下的 API 來追加一個新的字段 age,并且它的類型為 long 類型:
PUT test/_mapping
{
"properties": {
"age": {
"type": "long"
}
}
}
我們可以使用如下的命令來查看索引 test 的最終 mapping:
GET test/_mapping
上面的命令顯示的結(jié)果為:
{
"test" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "long"
},
"id" : {
"type" : "keyword"
},
"message" : {
"type" : "text"
}
}
}
}
}
在上面,我們可以看出來我們已經(jīng)成功地創(chuàng)建了一個叫做 twitter 的 index。通過這樣的方法,我們可以自動創(chuàng)建一個 index。如果大家不喜歡自動創(chuàng)建一個 index,我們可以修改如下的一個設(shè)置:
PUT _cluster/settings
{
"persistent": {
"action.auto_create_index": "false"
}
}
在絕大多數(shù)情況下,我們并不需要這么做,除非你知道你要做什么。如果你想開啟自動創(chuàng)建索引,你必須配置 action.auto_create_index 以允許這些創(chuàng)建以下索引的組件:
PUT _cluster/settings
{
"persistent": {
"action.auto_create_index": ".monitoring*,.watches,.triggered_watches,.watcher-history*,.ml*"
}
}
如果我們向索引中插入一條文檔這個文檔并不馬上可以進行搜索。而是要過1s
以為有一個 refresh timer 來定時完成refresh操作。這個周期為1秒。這就是為什么 es可以實現(xiàn)秒級的搜索。當(dāng)然這個 timer 的周期也可以在索引的設(shè)置中進行配置。如果我們想讓我們的結(jié)果馬上可以對搜索可見,我們可以用如下的方法:
PUT twitter/_doc/1?refresh=true
{
"user": "GB",
"uid": 1,
"city": "Beijing",
"province": "Beijing",
"country": "China"
}
上面的方式可以強制使 es進行 refresh 的操作,當(dāng)然這個是有代價的。頻繁的進行這種操作,會使es 變慢。所以我們一般設(shè)置refresh=wait_for。這樣相當(dāng)于一個同步的操作,它等待下一個 refresh 周期發(fā)生完后,才返回。
PUT twitter/_doc/1?refresh=wait_for
{
"user": "GB",
"uid": 1,
"city": "Beijing",
"province": "Beijing",
"country": "China"
}
es為我們創(chuàng)建了一個被叫做 _doc 的 type。自從 es 6.0 以后,一個 index 只能有一個 type。如果我們創(chuàng)建另外一個 type 的話,會報錯。這里發(fā)現(xiàn)有一個版本(_version)信息,document 第一次創(chuàng)建 _id 為1它會顯示為 1之后如果我們更改這個 document,它的版本會每次自動增加1。
POST twitter/_doc/1
{
"user": "GB",
"uid": 1,
"city": "Shenzhen",
"province": "Guangdong",
"country": "China"
}
創(chuàng)建文檔
PUT twitter/_create/1
{
"user": "GB",
"uid": 1,
"city": "Shenzhen",
"province": "Guangdong",
"country": "China"
}
如果文檔已經(jīng)存在的話,會報錯
另一種寫法:在請求時帶上 op_type。它可以有兩種值:index 及 create。
PUT twitter/_doc/1?op_type=create
{
"user": "雙榆樹-張三",
"message": "今兒天氣不錯啊,出去轉(zhuǎn)轉(zhuǎn)去",
"uid": 2,
"age": 20,
"city": "北京",
"province": "北京",
"country": "中國",
"address": "中國北京市海淀區(qū)",
"location": {
"lat": "39.970718",
"lon": "116.325747"
}
}
curl寫法
curl -XPUT 'http://localhost:9200/twitter/_doc/1?pretty' -H 'Content-Type: application/json' -d '
{
"user": "GB",
"uid": 1,
"city": "Shenzhen",
"province": "Guangdong",
"country": "China"
}'
我們可以通過如下的命令來查看被修改的文檔:
GET twitter/_doc/1
我們可以看到在右邊顯示了我們被修改的文檔的結(jié)果。
如果我們只想得到這個文檔的 _source 部分,我們可以使用如下的命令格式:
GET twitter/_doc/1/_source
在 es7.0 之后,在 type 最終要被廢除的情況下,建議使用如下的方法來獲得 _source:
GET twitter/_source/1
自動 ID 生成
如果我們不指定文檔的 ID,創(chuàng)建一個新的文檔,轉(zhuǎn)而讓 es自動幫我們生成一個 ID,這樣的速度更快。在這種情況下,我們必須使用 POST,而不是 PUT,例如:
POST my_index/_doc
{
"content": "this is really cool"
}
返回的結(jié)果:
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "egiY4nEBQTokU_uEEGZz",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
在正常的情況下,當(dāng)前復(fù)制組的所有分片都執(zhí)行了索引操作時,es 從索引操作返回。
設(shè)置異步復(fù)制允許我們在主分片上同步執(zhí)行索引操作,在副本分片上異步執(zhí)行。這樣,API 調(diào)用會更快地返回響應(yīng)操作。我們可以這樣來進行調(diào)用:
POST my_index/_doc?replication=async
{
"content": "this is really cool"
}
如果我們只對 source 的內(nèi)容感興趣的話,我們可以使用:
GET twitter/_doc/1/_source
這樣我們可以直接得到 source 的信息:
{
"user" : "雙榆樹-張三",
"message" : "今兒天氣不錯啊,出去轉(zhuǎn)轉(zhuǎn)去",
"uid" : 2,
"age" : 20,
"city" : "北京",
"province" : "北京",
"country" : "中國",
"address" : "中國北京市海淀區(qū)",
"location" : {
"lat" : "39.970718",
"lon" : "116.325747"
}
}
我們也可以只獲取 source 的部分字段:
GET twitter/_doc/1?_source=city,age,province
如果你想一次請求查找多個文檔,我們可以使用 _mget 接口:
GET _mget
{
"docs": [
{
"_index": "twitter",
"_id": 1
},
{
"_index": "twitter",
"_id": 2
}
]
}
我們也可以只獲得部分字段:
GET _mget
{
"docs": [
{
"_index": "twitter",
"_id": 1,
"_source":["age", "city"]
},
{
"_index": "twitter",
"_id": 2,
"_source":["province", "address"]
}
]
}
在這里,我們同時請求 id 為 1 和 2 的兩個文檔。
我們也可以簡單地寫為:
GET twitter/_doc/_mget
{
"ids": ["1", "2"]
}
它和上面的做一個是一樣的。使用一個命令同時獲取 id 為 1 及 2 的文檔。
在上面當(dāng)我們寫入數(shù)據(jù)時,我們有意識地把文檔的 id 在命令中寫了出來。如果我們不寫這個 id 的話,ES 會幫我們自動生產(chǎn)一個 id:
POST twitter/_doc/
我可以看到右邊的一個 id 像是一個隨機的數(shù)值,同時我們可以看到它的一個版本信息為1。在實際的需要有大量導(dǎo)入數(shù)據(jù)的情況下,我們建議讓系統(tǒng)自動幫我們生成一個 id,這樣可以提高導(dǎo)入的速度。假如我們指定一個 id,通常 ES 會先查詢這個 id 是否存在,然后在覺得是更新之前的文檔還是創(chuàng)建一個新的文檔。這里是分兩步走。顯然它比直接創(chuàng)建一個文檔要慢!
我們也可以看出來系統(tǒng)所給出來的字段都是以下劃線的形式給出來的,比如:_id, _shards, _index, _typed 等
更新文檔
我們接下來看一下如何修改一個文檔。在上面我們看到了可以使用 POST 的命令來修改改一個文檔。通常我們使用 POST 來創(chuàng)建一個新的文檔。在使用 POST 的時候,我們甚至不用去指定特定的 id,系統(tǒng)會幫我們自動生成。但是我們修改一個文檔時,我們通常會使用 PUT 來進行操作,并且,我們需要指定一個特定的 id 來進行修改:
PUT twitter/_doc/1
{
"user": "GB",
"uid": 1,
"city": "北京",
"province": "北京",
"country": "中國",
"location":{
"lat":"29.084661",
"lon":"111.335210"
}
}
如上面所示,我們使用 PUT 命令來對我們的 id 為1的文檔進行修改。我們也可以使用我們上面學(xué)過的 GET 來進行查詢:
GET twitter/_doc/1
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "1",
"_version" : 8,
"_seq_no" : 13,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "GB",
"uid" : 1,
"city" : "北京",
"province" : "北京",
"country" : "中國",
"location" : {
"lat" : "29.084661",
"lon" : "111.335210"
}
}
}
顯然,我們的這個文檔已經(jīng)被成功修改了。
我們使用 PUT 的這個方法,每次修改一個文檔時,我們需要把文檔的每一項都要寫出來。這對于有些情況來說,并不方便,我們可以使用如下的方法來進行修改:
POST twitter/_update/1
{
"doc": {
"city": "成都",
"province": "四川"
}
}
我們可以使用如上的命令來修改我們的部分?jǐn)?shù)據(jù)。同樣我們可以使用 GET 來查詢我們的修改是否成功:
從上面的顯示中,我們可以看出來,我們的修改是成功的,雖然在我們修改時,我們只提供了部分的數(shù)據(jù)。
在關(guān)系數(shù)據(jù)庫中,我們通常是對數(shù)據(jù)庫進行搜索,讓后才進行修改。在這種情況下,我們事先通常并不知道文檔的 id。我們需要通過查詢的方式來進行查詢,讓后進行修改。ES 也提供了相應(yīng)的 REST 接口。
POST twitter/_update_by_query
{
"query": {
"match": {
"user": "GB"
}
},
"script": {
"source": "ctx._source.city = params.city;ctx._source.province = params.province;ctx._source.country = params.country",
"lang": "painless",
"params": {
"city": "上海",
"province": "上海",
"country": "中國"
}
}
}
對于那些名字是中文字段的文檔來說,在 painless 語言中,直接打入中文字段名字,并不能被認(rèn)可。我們可以使用如下的方式來操作:
POST edd/_update_by_query
{
"query": {
"match": {
"姓名": "張彬"
}
},
"script": {
"source": "ctx._source[\"簽到狀態(tài)\"] = params[\"簽到狀態(tài)\"]",
"lang": "painless",
"params" : {
"簽到狀態(tài)":"已簽到"
}
}
}
在上面我們使用一個中括號并 escape 引號的方式來操作。有關(guān) Painless 的編程,你可以參閱文章 “Elasticsearch: Painless script 編程”。
我們可以通過上面的方法搜尋 user 為 GB 的用戶,并且把它的數(shù)據(jù)項修改為:
"city" : "上海",
"province": "上海",
"country": "中國"
我們也可以通過 update 接口,使用 script 的方法來進行修改。這個方法也是需要知道文檔的 id:
POST twitter/_update/1
{
"script" : {
"source": "ctx._source.city=params.city",
"lang": "painless",
"params": {
"city": "長沙"
}
}
}
在我們使用上面的方法更新文檔時,如果當(dāng)前的文檔 id 不存在,那么我們甚至可以使用 upsert 屬性來創(chuàng)建一個文檔:
POST twitter/_update/1
{
"script" : {
"source": "ctx._source.city=params.city",
"lang": "painless",
"params": {
"city": "長沙"
}
},
"upsert": {
"city": "長沙"
}
}
和前面的方法一下,我們可以使用 GET 來查詢,我們的結(jié)果是否已經(jīng)改變:
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "1",
"_version" : 18,
"_seq_no" : 39,
"_primary_term" : 1,
"found" : true,
"_source" : {
"uid" : 1,
"country" : "中國",
"province" : "上海",
"city" : "長沙",
"location" : {
"lon" : "111.335210",
"lat" : "29.084661"
},
"user" : "GB"
}
}
如果你涉及到多個客戶端同時更新一個索引的情況,你需要閱讀文章 “深刻理解文檔中的 verision 及 樂觀并發(fā)控制”。
我們甚至可以使用 _update 接口使用 ctx[‘_op’] 來達到刪除一個文檔的目的,比如:
POST twitter/_update/1
{
"script": {
"source": """
if(ctx._source.uid == 1) {
ctx.op = 'delete'
} else {
ctx.op = "none"
}
"""
}
}
當(dāng)檢測文檔的 uid 是否為 1,如果為 1 的話,那么該文檔將被刪除,否則將不做任何事情。
我還可以充分使用 script 的一些高級操作,比如我們可以通過如下的方法來添加一個嶄新的字段:
POST twitter/_update/1
{
"script" : {
"source": "ctx._source.newfield=4",
"lang": "painless"
}
}
通過上面的操作,我們可以發(fā)現(xiàn),我們新增加了一個叫做 newfield 的字段。當(dāng)然我們也可以使用如下的方法來刪除一個字段:
POST twitter/_update/1
{
"script" : {
"source": "ctx._source.remove(\"newfield\")",
"lang": "painless"
}
}
在上面的命令中,我們通過 remove 刪除了剛才被創(chuàng)建的 newfiled 字段。我們可以通過如下的命令來進行查看:
GET twitter/_doc/1
在這里請注意的是:一旦一個字段被創(chuàng)建,那么它就會存在于更新的 mapping 中。即便針對 id 為 1 的文檔刪除了 newfield,但是 newfield 還將繼續(xù)存在于 twitter 的 mapping 中。我們可以使用如下的命令來查看 twitter 的 mapping:
GET twitter/_mapping
這里值得注意是:對于多用戶,我們可以從各個客戶端同時更新,這里可能會造成更新數(shù)據(jù)的一致性問題。為了避免這種現(xiàn)象的出現(xiàn),請閱讀我的另外一篇文章 “Elasticsearch:深刻理解文檔中的 verision 及樂觀并發(fā)控制”。
UPSERT文檔
僅在文檔事先存在的情況下,我們在前面的代碼中看到的部分更新才有效。 如果具有給定 id 的文檔不存在,Elasticsearch 將返回一個錯誤,指出該文檔丟失。 讓我們了解如何使用更新 API 進行 upsert 操作。 術(shù)語 “upsert” 寬松地表示更新或插入,即更新文檔(如果存在),否則,插入新文檔。
doc_as_upsert 參數(shù)檢查具有給定ID的文檔是否已經(jīng)存在,并將提供的 doc 與現(xiàn)有文檔合并。 如果不存在具有給定 id 的文檔,則會插入具有給定文檔內(nèi)容的新文檔。
下面的示例使用 doc_as_upsert 合并到 id 為 3 的文檔中,或者如果不存在則插入一個新文檔:
POST /catalog/_update/3
{
"doc": {
"author": "Albert Paro",
"title": "Elasticsearch 5.0 Cookbook",
"description": "Elasticsearch 5.0 Cookbook Third Edition",
"price": "54.99"
},
"doc_as_upsert": true
}
檢查一個文檔是否存在
有時候我們想知道一個文檔是否存在,我們可以使用如下的方法:
HEAD twitter/_doc/1
這個 HEAD 接口可以很方便地告訴我們在 twitter 的索引里是否有一 id 為1的文檔:
上面的返回值表面 id 為1的文檔時存在的。
刪除文檔
根據(jù)ID刪除文檔
DELETE twitter/_doc/1
根據(jù)條件刪除
POST twitter/_delete_by_query
{
"query": {
"match": {
"city": "上海"
}
}
}
這樣我們就把所有的 city 是上海的文檔都刪除了。
檢查一個索引是否存在
我們可以使用如下的命令來檢查一個索引是否存在:
HEAD twitter
如果 twitter 索引存在,那么上面的命令會返回:
200 - OK
否則就會返回:
{"statusCode":404,"error":"Not Found","message":"404 - Not Found"}
刪除索引
刪除一個索引 是非常直接的。我們可以直接使用如下的命令來進行刪除:
DELETE twitter
當(dāng)我們執(zhí)行完這一條語句后,所有的在 twitter 中的所有的文檔都將被刪除。
批處理命令
上面我們已經(jīng)了解了如何使用 REST 接口來創(chuàng)建一個 index,并為之創(chuàng)建(Create),讀?。≧ead),修改(Update),刪除文檔(Delete)(CRUD)。因為每一次操作都是一個 REST 請求,對于大量的數(shù)據(jù)進行操作的話,這個顯得比較慢。ES 創(chuàng)建一個批量處理的命令給我們使用。這樣我們在一次的 REST 請求中,我們就可以完成很多的操作。這無疑是一個非常大的好處。下面,我們來介紹一下這個 _bulk 命令。
我們使用如下的命令來進行 bulk 操作:
POST _bulk
{ "index" : { "_index" : "twitter", "_id": 1} }
{"user":"雙榆樹-張三","message":"今兒天氣不錯啊,出去轉(zhuǎn)轉(zhuǎn)去","uid":2,"age":20,"city":"北京","province":"北京","country":"中國","address":"中國北京市海淀區(qū)","location":{"lat":"39.970718","lon":"116.325747"}}
{ "index" : { "_index" : "twitter", "_id": 2 }}
{"user":"東城區(qū)-老劉","message":"出發(fā),下一站云南!","uid":3,"age":30,"city":"北京","province":"北京","country":"中國","address":"中國北京市東城區(qū)臺基廠三條3號","location":{"lat":"39.904313","lon":"116.412754"}}
{ "index" : { "_index" : "twitter", "_id": 3} }
{"user":"東城區(qū)-李四","message":"happy birthday!","uid":4,"age":30,"city":"北京","province":"北京","country":"中國","address":"中國北京市東城區(qū)","location":{"lat":"39.893801","lon":"116.408986"}}
{ "index" : { "_index" : "twitter", "_id": 4} }
{"user":"朝陽區(qū)-老賈","message":"123,gogogo","uid":5,"age":35,"city":"北京","province":"北京","country":"中國","address":"中國北京市朝陽區(qū)建國門","location":{"lat":"39.718256","lon":"116.367910"}}
{ "index" : { "_index" : "twitter", "_id": 5} }
{"user":"朝陽區(qū)-老王","message":"Happy BirthDay My Friend!","uid":6,"age":50,"city":"北京","province":"北京","country":"中國","address":"中國北京市朝陽區(qū)國貿(mào)","location":{"lat":"39.918256","lon":"116.467910"}}
{ "index" : { "_index" : "twitter", "_id": 6} }
{"user":"虹橋-老吳","message":"好友來了都今天我生日,好友來了,什么 birthday happy 就成!","uid":7,"age":90,"city":"上海","province":"上海","country":"中國","address":"中國上海市閔行區(qū)","location":{"lat":"31.175927","lon":"121.383328"}}
在上面的命令中,我們使用了 bulk 指令來完成我們的操作。在輸入命令時,我們需要特別的注意:千萬不要添加除了換行以外的空格,否則會導(dǎo)致錯誤。在上面我們使用的 index 用來創(chuàng)建一個文檔。為了說明問題的方便,我們在每一個文檔里,特別指定了每個文檔的 id。當(dāng)執(zhí)行完我們的批處理 bulk 命令后,我們可以看到:
顯然,我們的創(chuàng)建時成功的。因為我運行了兩遍的原因,所以你看到的是 version 為 2 的返回結(jié)果。bulk 指令是高效的,因為一個請求就可以處理很多個操作。在實際的使用中,我們必須注意的是:一個好的起點是批量處理 1,000 到 5,000 個文檔,總有效負(fù)載在 5MB 到 15MB 之間。如果我們的 payload 過大,那么可能會造成請求的失敗。如果你想更進一步探討的話,你可以使用文件 accounts.json 來做實驗。更多是有數(shù)據(jù)可以在地址 加載示例數(shù)據(jù) | Kibana 用戶手冊 | Elastic 進行下載。
如果你想查詢到所有的輸入的文檔,我們可以使用如下的命令來進行查詢:
POST twitter/_search
這是一個查詢的命令,在以后的章節(jié)中,我們將再詳細(xì)介紹。通過上面的指令,我們可以看到所有的已經(jīng)輸入的文檔。
上面的結(jié)果顯示,我們已經(jīng)有6條生產(chǎn)的文檔記錄已經(jīng)生產(chǎn)了。
我們可以通過使用 _count 命令來查詢有多少條數(shù)據(jù):
GET twitter/_count
上面我們已經(jīng)使用了 index 來創(chuàng)建6條文檔記錄。我也可以嘗試其它的命令,比如 create:
POST _bulk
{ "create" : { "_index" : "twitter", "_id": 1} }
{"user":"雙榆樹-張三","message":"今兒天氣不錯啊,出去轉(zhuǎn)轉(zhuǎn)去","uid":2,"age":20,"city":"北京","province":"北京","country":"中國","address":"中國北京市海淀區(qū)","location":{"lat":"39.970718","lon":"116.325747"}}
{ "index" : { "_index" : "twitter", "_id": 2 }}
{"user":"東城區(qū)-老劉","message":"出發(fā),下一站云南!","uid":3,"age":30,"city":"北京","province":"北京","country":"中國","address":"中國北京市東城區(qū)臺基廠三條3號","location":{"lat":"39.904313","lon":"116.412754"}}
{ "index" : { "_index" : "twitter", "_id": 3} }
{"user":"東城區(qū)-李四","message":"happy birthday!","uid":4,"age":30,"city":"北京","province":"北京","country":"中國","address":"中國北京市東城區(qū)","location":{"lat":"39.893801","lon":"116.408986"}}
{ "index" : { "_index" : "twitter", "_id": 4} }
{"user":"朝陽區(qū)-老賈","message":"123,gogogo","uid":5,"age":35,"city":"北京","province":"北京","country":"中國","address":"中國北京市朝陽區(qū)建國門","location":{"lat":"39.718256","lon":"116.367910"}}
{ "index" : { "_index" : "twitter", "_id": 5} }
{"user":"朝陽區(qū)-老王","message":"Happy BirthDay My Friend!","uid":6,"age":50,"city":"北京","province":"北京","country":"中國","address":"中國北京市朝陽區(qū)國貿(mào)","location":{"lat":"39.918256","lon":"116.467910"}}
{ "index" : { "_index" : "twitter", "_id": 6} }
{"user":"虹橋-老吳","message":"好友來了都今天我生日,好友來了,什么 birthday happy 就成!","uid":7,"age":90,"city":"上海","province":"上海","country":"中國","address":"中國上海市閔行區(qū)","location":{"lat":"31.175927","lon":"121.383328"}}
在上面,我們的第一個記錄里,我們使用了 create 來創(chuàng)建第一個 id 為1的記錄。因為之前,我們已經(jīng)創(chuàng)建過了,所以我們可以看到如下的信息:
從上面的信息,我們可以看出來 index 和 create 的區(qū)別。index 總是可以成功,它可以覆蓋之前的已經(jīng)創(chuàng)建的文檔,但是 create 則不行,如果已經(jīng)有以那個 id 為名義的文檔,就不會成功。
我們可以使用 delete 來刪除一個已經(jīng)創(chuàng)建好的文檔:
POST _bulk
{ "delete" : { "_index" : "twitter", "_id": 1 }}
我們可以看到 id 為1的文檔已經(jīng)被刪除了。我可以通過如下的命令來查看一下:
顯然,我們已經(jīng)把 id 為1的文檔已經(jīng)成功刪除了。
我們也可以是使用 update 來進行更新一個文檔。
POST _bulk
{ "update" : { "_index" : "twitter", "_id": 2 }}
{"doc": { "city": "長沙"}}
運行的結(jié)果如下:
同樣,我們可以使用如下的方法來查看我們修改的結(jié)果:
我們可以清楚地看到我們已經(jīng)成功地把城市 city 修改為 “長沙”。
注意:通過 bulk API 為數(shù)據(jù)編制索引時,你不應(yīng)在集群上進行任何查詢/搜索。 這樣做可能會導(dǎo)致嚴(yán)重的性能問題。
如果你對腳本編程比較熟悉的話,你可能更希望通過腳本的方法來把大量的數(shù)據(jù)通過腳本的方式來導(dǎo)入:
$ curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary @request_example.json
這里的 request_example.json 就是我們的 JSON 數(shù)據(jù)文件。我們可以做如下的實驗:
下載測試數(shù)據(jù):
wget https://github.com/liu-xiao-guo/elasticsearch-bulk-api-data/blob/master/es.json
然后在命令行中打入如下的命令:
curl -u elastic:123456 -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary @es.json
這里的 “elastic:123456” 是我們的 Elasticsearch 的用戶名及密碼,如果我們沒有為我們的 Elasticsearch 設(shè)置安全,那么可以把 “-u elastic:123456” 整個去掉。正對配置有 https 的 Elasticsearch 服務(wù)器,我們可以使用如下格式的命令來進行操作:
curl --cacert /home/elastic/ca.crt -u elastic:123456 -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary @es.json
在上面, 我們使用 --cacert /home/elastic/ca.crt 來定義證書的地址。
等我們運行完上面的指令后,我們可以在 Kibana 中查看到我們的叫做 “bank_account” 的索引。
Open/close Index
Elasticsearch 支持索引的在線/離線模式。 使用脫機模式時,在群集上幾乎沒有任何開銷地維護數(shù)據(jù)。 關(guān)閉索引后,將阻止讀/寫操作。 當(dāng)你希望索引重新聯(lián)機時,只需打開它即可。 但是,關(guān)閉索引會占用大量磁盤空間。 你可以通過將 cluster.indices.close.enable 的默認(rèn)值從 true 更改為 false 來禁用關(guān)閉索引功能,以避免發(fā)生意外。
一旦 twitter 索引被關(guān)閉了,那么我們再訪問時會出現(xiàn)如下的錯誤:
我們可以通過 _open 接口來重新打開這個 index:
關(guān)于關(guān)閉索引有很多用例:
它可以禁用基于日期的索引(按日期存儲其記錄的索引)— 例如,當(dāng)你將索引保留一周、一個月或一天,并且你希望保留固定數(shù)量的舊索引(即 2 個月 舊)在線和一些離線(即從 2 個月到 6 個月)。
當(dāng)你搜索集群的所有 active 索引并且不想搜索某些索引時(在這種情況下,使用 alias 是最好的解決方案,但你可以使用具有關(guān)閉索引的 alias 來實現(xiàn)相同的效果)。
Freeze/unfreeze index
凍結(jié)索引(freeze index)在群集上幾乎沒有開銷(除了將其元數(shù)據(jù)保留在內(nèi)存中),并且是只讀的。 只讀索引被阻止進行寫操作,例如 docs-index 或 force merge。 請參閱凍結(jié)索引和取消凍結(jié)索引。
凍結(jié)索引受到限制,以限制每個節(jié)點的內(nèi)存消耗。 每個節(jié)點的并發(fā)加載的凍結(jié)索引數(shù)受 search_throttled 線程池中的線程數(shù)限制,默認(rèn)情況下為1。 默認(rèn)情況下,即使已明確命名凍結(jié)索引,也不會針對凍結(jié)索引執(zhí)行搜索請求。 這是為了防止由于誤將凍結(jié)的索引作為目標(biāo)而導(dǎo)致的意外減速。 如果要包含凍結(jié)索引做搜索,必須使用查詢參數(shù) ignore_throttled = false 來執(zhí)行搜索請求。
我們可以使用如下的命令來對 twitter 索引來凍結(jié):
POST twitter/_freeze
在執(zhí)行上面的命令后,我們再對 twitter 進行搜索:
我們搜索不到任何的結(jié)果。按照我們上面所說的,我們必須加上 ignore_throttled=false 參數(shù)來進行搜索:
顯然對于一個 frozen 的索引來說,我們是可以對它進行搜索的。我們可以通過如下的命令來對這個已經(jīng)凍結(jié)的索引來進行解凍:
POST twitter/_unfreeze
一旦我們的索引被成功解凍,那么它就可以像我們正常的索引來進行操作了,而不用添加參數(shù) ignore_throttled=false 來進行訪問。文章來源:http://www.zghlxwxcb.cn/news/detail-405131.html
下期更精彩
在這篇文章中,我們詳細(xì)地介紹了如果在 es 中創(chuàng)建索引,文檔,并對他們進行更改,刪除,查詢的操作。在接下來的文章里,我們將重點介紹如何對 Elasticsearch 里的 index 進行搜索和分析。文章來源地址http://www.zghlxwxcb.cn/news/detail-405131.html
到了這里,關(guān)于Elasticsearch如何創(chuàng)建索引,添加,刪除,更新文檔的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!