天天看點

ES7學習筆記(八)資料的增删改

在前面幾節的内容中,我們學習索引、字段映射、分析器等,這些都是使用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必須在索引中不存在;

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的核心功能——搜尋。