Elasticsearch学习笔记(六)—Elasticsearch文档及其CRUD操作

一、文档

最顶层结构或者根对象(root object)序列化成的JSON数据(以唯一ID标识并存储于Elasticsearch中),可以认为对象(object)和文档(document)是等价相通的。

文档元数据

节点说明
_index文档存储的地方
_type文档代表的对象的类
_id文档的唯一标识

_index
索引(index)类似于关系型数据库里的“数据库”——它是我们存储和索引关联数据的地方。数据被存储和索引在分片(shards)中, 索引只是一个把一个或多个分片分组在一起的逻辑空间。索引名必须是全部小写, 不能以下划线开头, 不能包含逗号

_type
在关系型数据库中, 我们经常将相同类的对象存储在一个表里, 因为它们有着相同的结构。 同理, 在Elasticsearch中, 我们使用相同类型(type)的文档表示相同的“事物”, 因为他们的数据结构也是相同的

_id
id仅仅是一个字符串, 它与 _index 和 _type 组合时, 就可以在ELasticsearch中唯一标识一个文档。 当创建一个文档, 你可以自定义 _id , 也可以让Elasticsearch帮你自动生成

二、文档CRUD操作

1. 索引文档

指定id创建文档 ,使用put
put /website/blog/1
{
  "title":"first blog",
  "date":"2019/10/28"
}

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

响应指出请求的索引已经被成功创建, 这个索引中包含 _index 、 _type 和 _id 元数据,版本号是1

注意使用put并不能保证每次都是新建文档,如果再次put相同id的文档,会对原有的文档进行覆盖。

PUT /website/blog/1
{
  "title": "three blog",
  "feel":"nice",
  "date": "2019/10/28"
}

//响应
{
  "_index": "website",
  "_type": "blog",
  "_id": "1",
  "_version": 2,   //版本号自增
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "created": false   //表示不是新建,而是覆盖
}

在内部, Elasticsearch已经标记旧文档为删除并添加了一个完整的新文档。 旧版本文档不会立即消失, 但你也不能去访问它。 Elasticsearch会在你继续索引更多数据时清理被删除的文档

不指定id,使用post
post /website/blog
{
   "title":"second blog",
  "date":"2019/10/28"
}

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

自动生成id:AW4TC7FgHfHdzvmX4JMA,每次都是新建文档,不会覆盖

自动生成的id,长度为20个字符,URL安全,base64编码,GUID,分布式系统并行生成时不可能会发生冲突

使用put创建新文档
PUT /website/blog/1?op_type=create
{
  "title": "four blog",
  "feel":"nice",
  "date": "2019/10/28"
}

//响应
{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[blog][1]: version conflict, document already exists (current version [2])",
        "index_uuid": "oqUDP19MSL2Y9XmPxCf1cA",
        "shard": "3",
        "index": "website"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[blog][1]: version conflict, document already exists (current version [2])",
    "index_uuid": "oqUDP19MSL2Y9XmPxCf1cA",
    "shard": "3",
    "index": "website"
  },
  "status": 409
}

存在不会进行覆盖,报409错误

也可以这样写,效果和上面相同

PUT /website/blog/3/_create
{
  "title": "five blog",
  "feel":"nice",
  "date": "2019/10/28"
}

2. 检索文档

使用Get

GET /website/blog/1
{
  "_index": "website",
  "_type": "blog",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "title": "first blog",
    "date": "2019/10/28"
  }
}

响应包含了现在熟悉的元数据节点, 增加了 _source 字段, 它包含了在创建索引时我们发送给Elasticsearch的原始文档

检索文档部分内容

get /website/blog/1?_source=title
{
  "_index": "website",
  "_type": "blog",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "title": "first blog"
  }
}

只需要返回source字段

get /website/blog/1/_source
{
  "title": "first blog",
  "date": "2019/10/28"
}

查询对应索引下所有文档

get /website/_search
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1,
    "hits": [
      {
        "_index": "website",
        "_type": "blog",
        "_id": "AW4TC7FgHfHdzvmX4JMA",
        "_score": 1,
        "_source": {
          "title": "second blog",
          "date": "2019/10/28"
        }
      },
      {
        "_index": "website",
        "_type": "blog",
        "_id": "1",
        "_score": 1,
        "_source": {
          "title": "first blog",
          "date": "2019/10/28"
        }
      }
    ]
  }
}

字段解释:

took
整个搜索请求花费的毫秒数。

timeout
查询超时与否,如果响应速度比完整的结果更重要,可以指定超时时间

get /website/_search?timeout=10ms

shards

  • total 字段 参与查询的分片数
  • successful 字段 有多少是成功的
  • failed 字段 有多少的是失败的

hits
total 字段 表示匹配到的文档总数

hits 数组包含了匹配到的前10条数据,hits 数组中的每个结果都包含 _index 、 _type 和文档的 _id 字段,每个节点都有一个 _score 字段, 这是相关性得分(relevance score), 它衡量了文档与查询的匹配程度。 默认的, 返回的结果中关联性最大的文档排在首位; 这意味着, 它是按照 _score 降序排列的。max_score 指的是所有文档匹配查询中 _score 的最大值

3. 修改文档

  • put是对原有文档的覆盖,使用新的文档替换旧文档

  • update API对文档可以进行局部更新

post /website/blog/1/_update
{
  "doc":{
    "action":"go to the moives",
    "date":"2019/10/29"
  }
}

get /website/blog/1
{
  "_index": "website",
  "_type": "blog",
  "_id": "1",
  "_version": 5,
  "found": true,
  "_source": {
    "title": "one blog",
    "feel": "nice",
    "date": "2019/10/29",
    "action": "go to the moives"
  }
}

最简单的 update 请求表单接受一个局部文档参数 doc , 它会合并到现有文档中,存在的标量字段被覆盖, 新字段被添加。例如上述例子新加了action字段,修改了date值

可以使用Groovy实现局部更新,我们可以在脚本中写各种逻辑,然后执行即可。

4. 删除文档

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

删除一个文档也不会立即从磁盘上移除, 它只是被标记成已删除。 Elasticsearch
将会在你之后添加更多索引的时候才会在后台进行删除内容的清理。

未找到对应删除文档,删除失败

DELETE /website/blog/AW4
{
  "found": false,
  "_index": "website",
  "_type": "blog",
  "_id": "AW4",
  "_version": 1,
  "result": "not_found",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}

三、版本控制与更新冲突

对于多用户的局部更新,由于网络原因,可能会出现旧值覆盖新值的情况,或者多线程常见的问题。

ES使用乐观版本并发控制,为每个文档指定版本号,通过CAS比较,如果不是期望的版本号,也就是说中间被人修改过该文档,就让本次更新请求失败

使用内部版本号
PUT /website/blog/3?version=2
{
  "title": "five blog",
  "feel":"sad",
  "date": "2019/10/29"
}

//响应
{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[blog][3]: version conflict, current version [1] is different than the one provided [2]",
        "index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
        "shard": "4",
        "index": "website"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[blog][3]: version conflict, current version [1] is different than the one provided [2]",
    "index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
    "shard": "4",
    "index": "website"
  },
  "status": 409
}

文档3的版本号是1,这里传入的version参数值为2,所以发生冲突,更新失败

注意,这里传入参数version值必须和文档现有的version值完全相等,精确匹配,否则失败

使用外部版本号
PUT /website/blog/4?version=3&version_type=external
{
  "title": "six blog",
  "feel":"funny",
  "date": "2019/10/29"
}

指定该文档的版本为4,外部版本号必须是整数, 大于0小于 9.2e+18

PUT /website/blog/4?version=3&version_type=external
{
  "title": "six blog",
  "feel":"funny",
  "date": "2019/10/29"
}
//响应
{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[blog][4]: version conflict, current version [3] is higher or equal to the one provided [2]",
        "index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
        "shard": "2",
        "index": "website"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[blog][4]: version conflict, current version [3] is higher or equal to the one provided [2]",
    "index_uuid": "lhDIRTZ7S9mYFUIj9z6AcA",
    "shard": "2",
    "index": "website"
  },
  "status": 409
}

报错的原因是因为外部版本号要求更新传入的version > 当前文档版本号,而不是精确匹配,否则报错,这里讲version值传入4即可成功更新

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值