参考:
https://es.xiaoleilu.com/030_Data/05_Document.html 《ELasticsearch in Action》

以下的操作在ES7.5版本下。

1. 文档

一个文档不只有数据,还包含了元数据,三个必须的元数据是:

_index: 索引,可以理解为mysql中数据库。
_type: 7.5版本后已经强制单索引单类型。
_id: 创建文档的时候可以指定,也可以不指定,es会自定生成。

2. 检索文档

2.1 指定id检索

GET /website/123?pretty

这里指定了id来检索文档,将会只返回一个结果。同时返回的结果中将包括_source自定,其内容是我们新建文档123的时候发送的全部内容。

2.2 检索文档的一部分

GET /website/123?_source=title,text

返回的source里面将只会有title和text字段。

3. 检查文档知否存在

HEAD /megacorp/_doc/1

将返回200 - OK
如果不存在将返回404 - Not Found

4. 更新文档

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

存在将更新,不存在将创建。可以从返回结果的"result" : "updated",看出

{
  "_index" : "website",
  "_type" : "_doc",
  "_id" : "12",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

Es的更新文档操作过程:

  1. 从旧文档中检索JSON
  2. 修改它
  3. 删除旧文档
  4. 索引新文档

5. 创建一个文档

如果想创建一个文档,而不是更新,使用:

POST /website/_doc/12?op_type=create

或者:

POST /website/_doc/12/_create

6. 删除一个文档

DELETE /website/_doc/12

7. 版本控制

7.1 内部版本号

每个文档都有一个_version号码,这个号码在文档被改变时加一。Elasticsearch使用这个_version保证所有修改都被正确排序。当一个旧版本出现在新版本之后,它会被简单的忽略。
我们利用_version的这一优点确保数据不会因为修改冲突而丢失。我们可以指定文档的version来做想要的更改。如果那个版本号不是现在的,我们的请求就失败了。

Let's create a new blog post: 让我们创建一个新的博文:

PUT /website/_doc/1/_create
{
  "title": "My first blog entry",
  "text":  "Just trying this out..."
}

响应体告诉我们这是一个新建的文档,它的_version是1。现在假设我们要编辑这个文档:把数据加载到web表单中,修改,然后保存成新版本。
首先我们检索文档:

GET /website/_doc/1
响应体包含相同的_version是1
{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
  }
}

现在,当我们通过重新索引文档保存修改时,我们这样指定了version参数:

PUT /website/_doc/1?version=1
{
  "title": "My first blog entry",
  "text":  "Starting to get the hang of this..."
}

7.2 外部版本号

如果主数据库有版本字段——或一些类似于timestamp等可以用于版本控制的字段——是你就可以在Elasticsearch的查询字符串后面添加version_type=external来使用这些版本号。版本号必须是整数,大于零小于9.2e+18——Java中的正的long。

外部版本号与之前说的内部版本号在处理的时候有些不同。它不再检查_version是否与请求中指定的一致,而是检查是否小于指定的版本。如果请求成功,外部版本号就会被存储到_version中

8. 局部更新

可以使用以下请求为博客添加一个tags字段和一个views字段:

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

如果文档不存在,将返回404。

8.1 更新不奴存在的文档

在这种情况下,我们可以使用upsert参数定义文档来使其不存在时被创建。

POST /website/_update/1
{
   "script" : "ctx._source.views+=1",
   "upsert": {
       "views": 1
   }
}

9. 检索多个文档

检索多个文档依旧非常快。合并多个请求可以避免每个请求单独的网络开销。如果你需要从Elasticsearch中检索多个文档,相对于一个一个的检索,更快的方式是在一个请求中使用multi-get或者mget API。

mget API参数是一个docs数组,数组的每个节点定义一个文档的_index、_type、_id元数据。如果你只想检索一个或几个确定的字段,也可以定义一个_source参数:

POST /_mget
{
   "docs" : [
      {
         "_index" : "website",
         "_id" :    2
      },
      {
         "_index" : "megacorp",
         "_id" :    1,
         "_source": "views"
      }
   ]
}

响应体也包含一个docs数组,每个文档还包含一个响应,它们按照请求定义的顺序排列。

{
  "docs" : [
    {
      "_index" : "website",
      "_type" : "blog",
      "_id" : "2",
      "found" : false
    },
    {
      "_index" : "megacorp",
      "_type" : "employee",
      "_id" : "1",
      "_version" : 2,
      "_seq_no" : 1,
      "_primary_term" : 1,
      "found" : true,
      "_source" : { }
    }
  ]
}

10. 批量操作

为了将这些放在一起,bulk请求表单是这样的:

POST /_bulk
{ "delete": { "_index": "website", "_type": "blog", "_id": "123" }} <1>
{ "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"} } <2>

<1> 注意delete行为(action)没有请求体,它紧接着另一个行为(action)
<2> 记得最后一个换行符

11. 搜索

为了充分挖掘Elasticsearch的潜力,你需要理解以下三个概念:

映射:Mapping,数据在每个字段中的解释说明
分析:Analysis,全部是如何处理的可以被搜索的
DSL:领域特定语言查询,es中使用的灵活的、强大的查询语言。

11.1 空搜索

GET /_search

将会返回集群中所有文档。

重要:

搜索一个索引有5个主分片和5个索引各有一个分片事实上是一样的。

11.2 简易搜索

search API有两种表单:一种是“简易版”的查询字符串(query string)将所有参数通过查询字符串定义,另一种版本使用JSON完整的表示请求体(request body),这种富搜索语言叫做结构化查询语句(DSL)。

11.3 _all字段

返回包含"mary"字符的所有文档的简单搜索:

GET /_search?q=mary

在前一个例子中,我们搜索tweet或name字段中包含某个字符的结果。然而,这个语句返回的结果在三个不同的字段中包含"mary":

用户的名字是“Mary”
“Mary”发的六个推文
针对“@mary”的一个推文

Elasticsearch是如何设法找到三个不同字段的结果的?
当你索引一个文档,Elasticsearch把所有字符串字段值连接起来放在一个大字符串中,它被索引为一个特殊的字段_all。例如,当索引这个文档:

{
    "tweet":    "However did I manage before Elasticsearch?",
    "date":     "2014-09-14",
    "name":     "Mary Jones",
    "user_id":  1
}

这好比我们增加了一个叫做_all的额外字段值:

"However did I manage before Elasticsearch? 2014-09-14 Mary Jones 1"

若没有指定字段,查询字符串搜索(即q=xxx)使用_all字段搜索。