02-Elasticsearch API - 文檔操作

ES中文檔的概念

ES中一個文檔即為一個json格式的文本,隸屬于某個index的某個type下。當索引進ES后,一個文檔不僅包含原始文檔信息,還包含一下元數據:
_index 文檔存放在那個索引
_type 文檔屬于什么對象類別
_id 文檔的唯一標識

索引一個文檔(新建一個文檔)

自己根據業(yè)務指定自定義id

PUT /{index}/{type}/{id}
{
  "field": "value",
  ...
}

實例:

PUT /website/blog/123
{
  "title": "My first blog entry",
  "text":  "Just trying this out...",
  "date":  "2014/01/01"
}

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}

讓ES為我們自動生成ID

POST /{index}/{type}
{
  "field": "value",
  ...
}

實例

POST /website/blog/
{
  "title": "My second blog entry",
  "text":  "Still trying this out...",
  "date":  "2014/01/01"
}

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "AV1e6wxyr-eh0mA78TXL",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": true
}

取回一個文檔

GET /{index}/{type}/{id}

實例:

//在請求的查詢串參數中加上 pretty 參數, 正如前面的例子中看到的,這將會調用 Elasticsearch 的 pretty-print 功能,該功能 使得 JSON 響應體更加可讀。但是, _source 字段不能被格式化打印出來。相反,我們得到的 _source 字段中的 JSON 串,剛好是和我們傳給它的一樣。
GET /website/blog/123?pretty

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 1,
  "found": true,
  "_source": {
    "title": "My first blog entry",
    "text": "Just trying this out...",
    "date": "2014/01/01"
  }
}

返回文檔的一部分

GET /{index}/{type}/{id}?_source=field1,field2...

實例:

GET /website/blog/123?_source=title,text

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 1,
  "found": true,
  "_source": {
    "text": "Just trying this out...",
    "title": "My first blog entry"
  }
}

只想得到source字段

GET /{index}/{type}/{id}/_source

實例:

GET /website/blog/123/_source

//result
{
  "title": "My first blog entry",
  "text": "Just trying this out...",
  "date": "2014/01/01"
}

檢測文檔是否存在

將獲取文檔的GET請求改為HEAD請求即可,返回體只會返回一個HTTP請求報頭

HEAD /{index}/{type}/{id}

返回的頭信息:

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 0

更新整個文檔

在 ES 中文檔是 不可改變 的,不能修改它們。 相反,如果想要更新現有的文檔,需要 重建索引 或者進行替換, 我們可以使用相同的 index API 進行實現
實例:

PUT /website/blog/123
{
  "title": "My first blog entry",
  "text":  "I am starting to get the hang of this...",
  "date":  "2014/01/02"
}

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 2, //版本號增加了
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": false //是否創(chuàng)建為false
}

在內部,Elasticsearch 已將舊文檔標記為已刪除,并增加一個全新的文檔。 盡管你不能再對舊版本的文檔進行訪問,但它并不會立即消失。當繼續(xù)索引更多的數據,Elasticsearch 會在后臺清理這些已刪除文檔。

控制只是創(chuàng)建文檔不會更新文檔

當使用POST不指定id時,ES始終都是新建文檔,當指定id時可以使用一下兩種方式控制新建,當id存在時,則返回失敗

PUT /{index}/{type}/{id}?op_type=create
{...}

PUT /{index}/{type}/{id}/_create
{...}

刪除文檔

DELETE /{index}/{type}/{id}

實例:

DELETE /website/blog/123

//result
{
  "found": true,
  "_index": "website",
  "_type": "blog",
  "_id": "123",
  "_version": 3,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}

文檔的部分更新

我們也介紹過文檔是不可變的:他們不能被修改,只能被替換。 update API 必須遵循同樣的規(guī)則。 從外部來看,我們在一個文檔的某個位置進行部分更新。然而在內部, update API 簡單使用與之前描述相同的 檢索-修改-重建索引 的處理過程。 區(qū)別在于這個過程發(fā)生在分片內部,這樣就避免了多次請求的網絡開銷。通過減少檢索和重建索引步驟之間的時間,我們也減少了其他進程的變更帶來沖突的可能性。

POST /{index}/{type}/{id}/_update
{
  "doc": {
    "field": value,
    ...
  }
}

實例:

POST /website/blog/1/_update
{
   "doc" : {
      "tags" : [ "testing" ],
      "views": 0
   }
}

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "1",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}

使用Groovy腳本更新文檔

//將views字段值加1
POST /website/blog/1/_update
{
   "script" : "ctx._source.views+=1"
}

//result
{
  "_index": "website",
  "_type": "blog",
  "_id": "1",
  "_version": 3,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}

取回多個文檔

跨index與type取回文檔

GET /_mget
GET /_mget
{
   "docs" : [
      {
         "_index" : {index},
         "_type" : {type},
         "_id" : {id}
      },
      ...
   ]
}

實例:

GET /_mget
{
   "docs" : [
      {
         "_index" : "website",
         "_type" :  "blog",
         "_id" :    1
      },
      {
         "_index" : "website",
         "_type" :  "pageviews",
         "_id" :    1,
         "_source": "views"
      }
   ]
}

//result
{
  "docs": [
    {
      "_index": "website",
      "_type": "blog",
      "_id": "1",
      "_version": 3,
      "found": true,
      "_source": {
        "title": "My first blog entry",
        "text": "I am starting to get the hang of this...",
        "date": "2014/01/02",
        "views": 1,
        "tags": [
          "testing"
        ]
      }
    },
    {
      "_index": "website",
      "_type": "pageviews",
      "_id": "1",
      "found": false
    }
  ]
}

如果想檢索的數據都在相同的 _index 中(甚至相同的 _type 中),則可以在 URL 中指定默認的 /_index 或者默認的 /_index/_type
實例:

GET /website/blog/_mget
{
   "docs" : [
      { "_id" : 2 },
      { "_type" : "pageviews", "_id" :   1 }
   ]
}

如果所有文檔的 _index 和 _type 都是相同的,你可以只傳一個 ids 數組
實例:

GET /website/blog/_mget
{
   "ids" : [ "2", "1" ]
}

代價較小的批量操作

與 mget 可以使我們一次取回多個文檔同樣的方式, bulk API 允許在單個步驟中進行多次 create 、 index 、 update 或 delete 請求。

POST /_bulk
{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...

這種格式類似一個有效的單行 JSON 文檔 流 ,它通過換行符(\n)連接到一起。注意兩個要點:
每行一定要以換行符(\n)結尾, 包括最后一行 。這些換行符被用作一個標記,可以有效分隔行。
這些行不能包含未轉義的換行符,因為他們將會對解析造成干擾。這意味著這個 JSON 不 能使用 pretty 參數打印。

action/metadata 行指定 哪一個文檔 做 什么操作 。
action 必須是以下選項之一:
create
如果文檔不存在,那么就創(chuàng)建它。詳情請見 創(chuàng)建新文檔。
index
創(chuàng)建一個新文檔或者替換一個現有的文檔。詳情請見 索引文檔 和 更新整個文檔。
update
部分更新一個文檔。詳情請見 文檔的部分更新。
delete
刪除一個文檔。詳情請見 刪除文檔。
metadata 應該 指定被索引、創(chuàng)建、更新或者刪除的文檔的 _index 、 _type 和 _id 。

實例:

POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} 
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "title":    "My first blog post" }
{ "index":  { "_index": "website", "_type": "blog" }}
{ "title":    "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3} }
{ "doc" : {"title" : "My updated blog post"} } 

多大是太大了?
整個批量請求都需要由接收到請求的節(jié)點加載到內存中,因此該請求越大,其他請求所能獲得的內存就越少。 批量請求的大小有一個最佳值,大于這個值,性能將不再提升,甚至會下降。 但是最佳值不是一個固定的值。它完全取決于硬件、文檔的大小和復雜度、索引和搜索的負載的整體情況。

幸運的是,很容易找到這個 最佳點 :通過批量索引典型文檔,并不斷增加批量大小進行嘗試。 當性能開始下降,那么你的批量大小就太大了。一個好的辦法是開始時將 1,000 到 5,000 個文檔作為一個批次, 如果你的文檔非常大,那么就減少批量的文檔個數。

密切關注你的批量請求的物理大小往往非常有用,一千個 1KB 的文檔是完全不同于一千個 1MB 文檔所占的物理大小。 一個好的批量大小在開始處理后所占用的物理大小約為 5-15 MB。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容