在前面幾節的內容中,我們學習索引、字段映射、分析器等,這些都是使用ES的基礎,就像在數據庫中創建表一樣,基礎工作做好以后,我們就要真正的使用它了,這一節我們要看看怎么向索引里寫入數據、修改數據、刪除數據,至於搜索嘛,因為ES的主要功能就是搜索,所以搜索的相關功能我們后面會展開講。
Document的創建與更新
索引中的數據叫做document,和數據中的一條記錄是一樣的,而索引就像數據庫中的一張表,我們向索引中添加數據,就像在數據庫表中添加一條記錄一樣。下面我們看看怎么向索引中添加數據,
PUT /<index>/_doc/<_id>
POST /<index>/_doc/
PUT /<index>/_create/<_id>
POST /<index>/_create/<_id>
在這個POST請求中,<index>
也就是索引的名字是必須的,這就好比我們向數據庫中插入記錄,要知道往哪張表里插是一樣的。<index>
后面可以是_doc
或者_create
,這兩個是什么意思呢?咱們慢慢看,除了這兩個區別以外,再有就是請求的方法了,分為POST
和PUT
兩種。一般情況下,POST
用於數據的插入,PUT
用戶數據的修改,是不是這樣呢?咱們把這4種方式都試一下,首先我們看一下POST /<index>/_doc/
這種方式的請求,
POST /ik_index/_doc
{
"id": 1,
"title": "蘋果",
"desc": "蘋果真好吃"
}
在這里,索引我們使用的是上一節創建的ik_index
,執行一下。然后我們再查詢一下這個索引,
GET /ik_index/_search
返回結果如下:
{
"took": 1000,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "ik_index",
"_type": "_doc",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"title": "大興龐各庄的西瓜",
"desc": "大興龐各庄的西瓜真是好吃,脆沙瓤,甜掉牙"
}
},
{
"_index": "ik_index",
"_type": "_doc",
"_id": "fEsN-HEBZl0Dh1ayKWZb",
"_score": 1,
"_source": {
"id": 1,
"title": "蘋果",
"desc": "蘋果真好吃"
}
}
]
}
}
我們重點看一下hits
,這是我們查詢出的結果,第一條是我們上一節存入的數據,不用管它。我們看一下第二條記錄,注意一下_id
這個字段,這個_id
是這條記錄在索引里的唯一標識,在插入數據的請求中,我們沒有指定這個id,ES給我們自動生成了fEsN-HEBZl0Dh1ayKWZb
。那么我們可不可以指定呢?試一下,
POST /ik_index/_doc/2
{
"id": 1,
"title": "香蕉",
"desc": "香蕉真好吃"
}
注意我們發送的請求,_doc
后面加了2
,這樣就指定了id,執行一下。然后再次查詢,返回的結果中,我們只截取hits
的部分,如下:
"hits": [
{
"_index": "ik_index",
"_type": "_doc",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"title": "大興龐各庄的西瓜",
"desc": "大興龐各庄的西瓜真是好吃,脆沙瓤,甜掉牙"
}
},
{
"_index": "ik_index",
"_type": "_doc",
"_id": "fEsN-HEBZl0Dh1ayKWZb",
"_score": 1,
"_source": {
"id": 1,
"title": "蘋果",
"desc": "蘋果真好吃"
}
},
{
"_index": "ik_index",
"_type": "_doc",
"_id": "2",
"_score": 1,
"_source": {
"id": 1,
"title": "香蕉",
"desc": "香蕉真好吃"
}
}
]
我們看到插入的香蕉
記錄,它的_id
是2
。那么POST
請求中指定的id在索引中存在,會是什么情況呢?我們再看一下,
POST /ik_index/_doc/1
{
"id": 1,
"title": "香蕉",
"desc": "香蕉真好吃"
}
還是香蕉
這條數據,我們指定id=1,id=1這條數據在索引中是存在的,我們執行一下,然后查詢,返回的結果如下:
"hits": [
{
"_index": "ik_index",
"_type": "_doc",
"_id": "fEsN-HEBZl0Dh1ayKWZb",
"_score": 1,
"_source": {
"id": 1,
"title": "蘋果",
"desc": "蘋果真好吃"
}
},
{
"_index": "ik_index",
"_type": "_doc",
"_id": "2",
"_score": 1,
"_source": {
"id": 1,
"title": "香蕉",
"desc": "香蕉真好吃"
}
},
{
"_index": "ik_index",
"_type": "_doc",
"_id": "1",
"_score": 1,
"_source": {
"id": 1,
"title": "香蕉",
"desc": "香蕉真好吃"
}
}
]
我們看到之前的那條數據被修改了,所以,關於POST /<index>/_doc/<_id>
,這種添加數據的方式,我們得出結論如下:
- <_id>不指定時,ES會為我們自動生成id;
- 指定<_id>時,且id在索引中不存在,ES將添加一條指定id的數據;
- 指定<_id>時,但id在索引中存在,ES將會更新這條數據;
接下來我們再看看_doc
方式的PUT
請求方式,我們先不指定id,看看會是什么情況,請求如下:
PUT /ik_index/_doc
{
"id": 1,
"title": "葡萄",
"desc": "葡萄真好吃"
}
執行一下,返回如下結果:
{
"error": "Incorrect HTTP method for uri [/ik_index/_doc] and method [PUT], allowed: [POST]",
"status": 405
}
錯誤信息說我們的請求不對,讓我們使用POST
請求,看來PUT
請求不指定id是不行的。我們再看看指定一個不存在的id,是什么情況,如下:
PUT /ik_index/_doc/3
{
"id": 1,
"title": "葡萄",
"desc": "葡萄真好吃"
}
執行成功,再查詢一下,
"hits": [
……
{
"_index": "ik_index",
"_type": "_doc",
"_id": "3",
"_score": 1,
"_source": {
"id": 1,
"title": "葡萄",
"desc": "葡萄真好吃"
}
}
]
數據添加成功。再看看指定一個存在的id是什么情況,那當然是修改了,我們再試一下,
PUT /ik_index/_doc/3
{
"id": 1,
"title": "橘子",
"desc": "橘子真好吃"
}
執行成功,再查詢一下,
"hits": [
……
{
"_index": "ik_index",
"_type": "_doc",
"_id": "3",
"_score": 1,
"_source": {
"id": 1,
"title": "橘子",
"desc": "橘子真好吃"
}
}
]
沒有問題,修改成功。POST /<index>/_doc/<_id>
這種方式的總結如下:
<_id>
必須指定,不指定會報錯;<_id>
在索引中不存在,為添加新數據;<_id>
在索引中存在,為修改數據;
_doc
這種請求的POST
和PUT
都嘗試過了,再看看_create
這種請求,先看看不指定id是什么情況,如下:
POST /ik_index/_create
{
"id": 1,
"title": "桃子",
"desc": "桃子真好吃"
}
返回錯誤信息如下:
{
"error": {
"root_cause": [
{
"type": "invalid_type_name_exception",
"reason": "mapping type name [_create] can't start with '_' unless it is called [_doc]"
}
],
"type": "invalid_type_name_exception",
"reason": "mapping type name [_create] can't start with '_' unless it is called [_doc]"
},
"status": 400
}
具體內容我們也不去解讀了,總之是不可以,然后加個索引中不存在id試一下,
POST /ik_index/_create/4
{
"id": 1,
"title": "桃子",
"desc": "桃子真好吃"
}
返回結果創建成功,查詢如下:
"hits": [
……
{
"_index": "ik_index",
"_type": "_doc",
"_id": "4",
"_score": 1,
"_source": {
"id": 1,
"title": "桃子",
"desc": "桃子真好吃"
}
}
]
如果id在索引中存在呢?再試,
POST /ik_index/_create/3
{
"id": 1,
"title": "桃子",
"desc": "桃子真好吃"
}
返回錯誤:
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[3]: version conflict, document already exists (current version [2])",
"index_uuid": "W2X_riHIT4u678p8HZwnEg",
"shard": "0",
"index": "ik_index"
}
],
"type": "version_conflict_engine_exception",
"reason": "[3]: version conflict, document already exists (current version [2])",
"index_uuid": "W2X_riHIT4u678p8HZwnEg",
"shard": "0",
"index": "ik_index"
},
"status": 409
}
大致的意思是,數據已經存在了,不能再添加新記錄,看來_create
這種方式還是比較嚴格的,總結如下:
- id必須指定;
- 指定的id如果在索引中存在,報錯,添加不成功;
- 指定的id在索引中不存在,添加成功,符合預期;
再看看_create
的PUT
,應該和POST
正好相反吧?我們試一下,先不指定id,試一下,
PUT /ik_index/_create
{
"id": 1,
"title": "火龍果",
"desc": "火龍果真好吃"
}
返回錯誤,不指定id肯定是不行的,錯誤信息就不給大家貼出來了,然后再指定一個不存在的id,
PUT /ik_index/_create/5
{
"id": 1,
"title": "火龍果",
"desc": "火龍果真好吃"
}
創建成功,查詢結果就不給大家展示了,然后再換一個存在的id,如下:
PUT /ik_index/_create/4
{
"id": 1,
"title": "火龍果",
"desc": "火龍果真好吃"
}
返回了錯誤的信息,如下,和POST
請求是一樣的,
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[4]: version conflict, document already exists (current version [1])",
"index_uuid": "W2X_riHIT4u678p8HZwnEg",
"shard": "0",
"index": "ik_index"
}
],
"type": "version_conflict_engine_exception",
"reason": "[4]: version conflict, document already exists (current version [1])",
"index_uuid": "W2X_riHIT4u678p8HZwnEg",
"shard": "0",
"index": "ik_index"
},
"status": 409
}
我們得出如下的結論:
_create
這種形式的POST
和PUT
是一樣的,沒有區別;- id必須指定;
- id必須在索引中不存在;
Document的刪除
有了添加,肯定會有刪除,刪除的方式很簡單,請求格式如下:
DELETE /<index>/_doc/<_id>
發送delete
請求,指定數據的id,就可以了,我們試一下,刪除剛剛添加的火龍果
數據,它的id是5
,我們發送請求如下:
DELETE /ik_index/_doc/5
執行成功,數據被成功的刪除。
根據id查詢Document
根據id查詢數據也很簡單,發送如下請求就可以完成查詢,
GET <index>/_doc/<_id>
我們需要指定索引的名稱,以及要查詢數據的id,如下:
GET ik_index/_doc/3
返回結果如下:
{
"_index": "ik_index",
"_type": "_doc",
"_id": "3",
"_version": 2,
"_seq_no": 5,
"_primary_term": 3,
"found": true,
"_source": {
"id": 1,
"title": "橘子",
"desc": "橘子真好吃"
}
}
根據id成功的查詢出來結果。
好了~ 到這里,ES數據的增刪改都介紹了,下節開始,我們看看ES的核心功能——搜索。