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。