02-Elasticsearch API - 文档操作

2017-07-20  本文已影响0人  M醉逍遥

ES中文档的概念

ES中一个文档即为一个json格式的文本,隶属于某个index的某个type下。当索引进ES后,一个文档不仅包含原始文档信息,还包含一下元数据:
_index 文档存放在那个索引
_type 文档属于什么对象类别
_id 文档的唯一标识

索引一个文档(新建一个文档)

自己根据业务指定自定义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 //是否创建为false
}

在内部,Elasticsearch 已将旧文档标记为已删除,并增加一个全新的文档。 尽管你不能再对旧版本的文档进行访问,但它并不会立即消失。当继续索引更多的数据,Elasticsearch 会在后台清理这些已删除文档。

控制只是创建文档不会更新文档

当使用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 必须遵循同样的规则。 从外部来看,我们在一个文档的某个位置进行部分更新。然而在内部, update API 简单使用与之前描述相同的 检索-修改-重建索引 的处理过程。 区别在于这个过程发生在分片内部,这样就避免了多次请求的网络开销。通过减少检索和重建索引步骤之间的时间,我们也减少了其他进程的变更带来冲突的可能性。

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
如果文档不存在,那么就创建它。详情请见 创建新文档。
index
创建一个新文档或者替换一个现有的文档。详情请见 索引文档 和 更新整个文档。
update
部分更新一个文档。详情请见 文档的部分更新。
delete
删除一个文档。详情请见 删除文档。
metadata 应该 指定被索引、创建、更新或者删除的文档的 _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"} } 

多大是太大了?
整个批量请求都需要由接收到请求的节点加载到内存中,因此该请求越大,其他请求所能获得的内存就越少。 批量请求的大小有一个最佳值,大于这个值,性能将不再提升,甚至会下降。 但是最佳值不是一个固定的值。它完全取决于硬件、文档的大小和复杂度、索引和搜索的负载的整体情况。

幸运的是,很容易找到这个 最佳点 :通过批量索引典型文档,并不断增加批量大小进行尝试。 当性能开始下降,那么你的批量大小就太大了。一个好的办法是开始时将 1,000 到 5,000 个文档作为一个批次, 如果你的文档非常大,那么就减少批量的文档个数。

密切关注你的批量请求的物理大小往往非常有用,一千个 1KB 的文档是完全不同于一千个 1MB 文档所占的物理大小。 一个好的批量大小在开始处理后所占用的物理大小约为 5-15 MB。

上一篇下一篇

猜你喜欢

热点阅读