Elasticsearch(五)数据操作

目录

1、文档概述

元数据

其他元数据

2、索引(存储数据)

自定义 ID

自增 ID

3、查询刚才创建的文档

检索文档的一部分

4、检测文档是否存在

 

5、更新文档

6、创建一个新文档(如果已存在则不创建)

7、删除文档

8、版本控制(乐观锁)

冲突问题

1. 悲观并发控制(Pessimistic concurrency control)

2. 乐观并发控制(Optimistic concurrency control)

乐观并发控制

9、文档局部更新

10、检索多个文档(Mget)

11、批量操作


1、文档概述

通常情况下,对象和文档时等价相通的。不过也有所差别:对象是一个 JSON 结构体——类似于哈希、hashmap、字典或者关联数据;对象中还可能包含其他对象。在Elasticsearch 中,文档特指最顶层结构或者 跟对象序列化成的 JSON数据(以唯一 ID 标识并存储于 Elasticsearch 中)。

元数据

一个文档不只有数据,它还包含了 元数据(metadata)—— 关于文档的信息。三个必须的元数据节点是:

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

索引(index) —— 相当于关系型数据库里的 数据库 ——它是存储和索引关联数据的地方。

类型(Type)—— 每个文档(对象)都属于某一个类型(type),相同类型(Type)的文档表示相同的“事物" ,因为他们的数据结构也是相同的。相当于数据库中的表。

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

其他元数据

待续

2、索引(存储数据)

文档通过 index API 被索引 —— 使数据可以被存储和搜索。

创建 website索引

curl -H "Content-Type: application/json" -XPUT 'http://10.24.54.241:9200/website' -d '{"settings" : {"number_of_shards" : 2,"number_of_replicas" : 1}}'

自定义 ID

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

例如我们的索引叫做“website”,类型叫做“blog”,我们选择的ID是“123”,那么这个索引请求就像这样:

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

对应 命令

curl -H "Content-Type: application/json" -XPUT 'http://10.24.54.241:9200/website/blog/123' -d '{"title": "My first blog entry","text":  "Just trying this out...","date":  "2014/01/01"}'

结果:

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

响应指出请求的索引已经被成功创建,这个索引中包含_index_type_id元数据,以及一个新元素:_version

自增 ID

Elasticsearch 自动生成 ID。请求结构发生了变化:PUT 方法 —— “在这个URL中存储文档”  变成了 POST 方法 —— “在这个类型下存储文档”,通俗讲:原来把文档存储到某个 ID 对应的空间,现在是把这个文档添加到 某个 _type 下。

命令变为

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

改成命令行模式:

curl -H "Content-Type: application/json" -XPOST 'http://10.24.54.241:9200/website/blog' -d '{"title": "My second blog entry","text":  "Still trying this out...","date":  "2014/01/01"}'

结果:

{
    "_index":"website",
    "_type":"blog",
    "_id":"BBVwkGoB1YPGGlWYBvT-",
    "_version":1,
    "result":"created",
    "_shards":{
        "total":2,
        "successful":2,
        "failed":0
    },
    "_seq_no":0,
    "_primary_term":1
}

_id 为自动生成的值。

3、查询刚才创建的文档

curl -XGET 'http://10.24.54.241:9200/website/blog/123?pretty'

结果:

{
  "_index" : "website",
  "_type" : "blog",
  "_id" : "123",
  "_version" : 2,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "My second blog entry",
    "text" : "Still trying this out...",
    "date" : "2014/01/01"
  }
}

_source:包含了创建索引时发送给 Elasticsearch 的原始文档。

_found:找到此文档 true,不存在为 false。

检索文档的一部分

curl -XGET 'http://10.24.54.241:9200/website/blog/123?pretty&_source=title,text'

结果:

{
  "_index" : "website",
  "_type" : "blog",
  "_id" : "123",
  "_version" : 2,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "text" : "Still trying this out...",
    "title" : "My second blog entry"
  }
}

_source 数据被过滤了

只要 _source 数据

curl -XGET 'http://10.24.54.241:9200/website/blog/123/_source?pretty'

结果:

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

4、检测文档是否存在

使用 HEAD 请求不会返回响应体,只有 HTTP 头:

curl -i -XHEAD 'http://10.24.54.241:9200/website/blog/123'

结果:

HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-length: 205

不存在的返回结果:

HTTP/1.1 404 Not Found
content-type: application/json; charset=UTF-8
content-length: 61

 

5、更新文档

文档在 Elasticsearch 中是不可变得 —— 我们不能修改他们。如果需要更新已存在的文档,我们需要重建索引或者替换掉它。

curl -H "Content-Type: application/json" -XPUT 'http://10.24.54.241:9200/website/blog/123' -d '{"title": "Update My first blog entry","text":  "Update Just trying this out...","date":  "2014/01/01"}'

运行后,再次查询这个记录,如下:

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

_version 自增了

_source 内容改变了。

6、创建一个新文档(如果已存在则不创建)

想要保证文档是新加入的最简单的方式是使用 POST 方法让 Elasticsearch 自动生成唯一 ID。

如果想使用自定义的 ID,我们必须判断此文档是否存在,不存在时才创建,存在时则抛出异常,这里可以使用 op_type 查询参数:

PUT /website/blog/123?op_type=create
{ ... }

或者第二种方法是在URL后加/_create做为端点:

PUT /website/blog/123/_create
{ ... }

如果请求成功的创建了一个新文档,Elasticsearch将返回正常的元数据且响应状态码是201 Created

另一方面,如果包含相同的_index_type_id的文档已经存在,Elasticsearch将返回409 Conflict响应状态码,错误信息类似如下:

{
  "error" : "DocumentAlreadyExistsException[[website][4] [blog][123]:
             document already exists]",
  "status" : 409
}

7、删除文档

使用 DELETE 方法:

curl -XDELETE 'http://10.24.54.241:9200/website/blog/124'

8、版本控制(乐观锁)

冲突问题

例如:我们使用 Elasticsearch 存储大量在线商店的库存信息,每当销售一个商品,Elasticsearch 中的库存就要减一。如果两个同时运行的 Web 进程,两者同时减一件商品的库存:

img-data-lww

如图,就可能造成库存减一,实际卖了两件。

在传统数据库中有两种方式解决这种问题:

1. 悲观并发控制(Pessimistic concurrency control)

在关系型数据库中典型的例子是在读一行数据前锁定这行,然后确保只有加锁的那个线程可以修改这行数据。

2. 乐观并发控制(Optimistic concurrency control)

被 Elasticsearch 使用,假如冲突不经常发生,如果在读写过程中数据发生了变化,更新操作将失败。这时候由程序决定在失败后如何解决冲突。实际情况中,可以重新尝试更新,刷新数据或者直接返回给用户。

乐观并发控制

Elasticsearch 是分布式的。当文档被创建、更新或删除,文档的新版本会被复制到集群的其他节点。

Elasticsearch 即是同步的又是异步的,意思是这些复制请求都是平行发送的,并无序的到达目的地。这就需要一种方法确保老版本的文档永远不会覆盖新的版本。

Elasticsearch 使用 _version 保证所有修改都被正确排序。当一个旧版本出现在新版本之后,它会被简单的忽略。

第 6 创建一个新文档 章节,已经讲了如何指定版本已经存在则会报错,这时就要获取新的文档版本号,重试更新库存。

9、文档局部更新

更新文档部分内容,例如新增字段:

curl -H "Content-Type: application/json" -XPOST 'http://10.24.54.241:9200/website/blog/123/_update' -d '{"doc": {"title": "doc title","tags":  ["tag1"],"views":  0}}'

更新后结果:

{
  "_index" : "website",
  "_type" : "blog",
  "_id" : "123",
  "_version" : 4,
  "_seq_no" : 3,
  "_primary_term" : 2,
  "found" : true,
  "_source" : {
    "title" : "doc title",
    "text" : "Update Just trying this out...",
    "date" : "2014/01/01",
    "views" : 0,
    "tags" : [
      "tag1"
    ]
  }
}

更新了 title 字段;

新增了 tags、views字段。

10、检索多个文档(Mget)

合并多个请求可以避免每个请求单独的网络开销。

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

11、批量操作

mget允许我们一次性检索多个文档一样,bulk API允许我们使用单一请求来实现多个文档的createindexupdatedelete。这对索引类似于日志活动这样的数据流非常有用,它们可以以成百上千的数据为一个批次按序进行索引。

bulk请求体如下,它有一点不同寻常:

{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...

这种格式类似于用"\n"符号连接起来的一行一行的JSON文档流(stream)。两个重要的点需要注意:

  • 每行必须以"\n"符号结尾,包括最后一行。这些都是作为每行有效的分离而做的标记。

  • 每一行的数据不能包含未被转义的换行符,它们会干扰分析——这意味着JSON不能被美化打印。

action/metadata这一行定义了文档行为(what action)发生在哪个文档(which document)之上。

行为(action)必须是以下几种:

行为解释
create当文档不存在时创建之。详见《创建文档》
index创建新文档或替换已有文档。见《索引文档》和《更新文档》
update局部更新文档。见《局部更新》
delete删除一个文档。见《删除文档》

例子:

在 linux 进入某个目录下,创建一个 bulk.json 文件,文件内容为:

{ "update": { "_index": "website", "_type": "blog", "_id": "123", "_retry_on_conflict" : 3}}
{ "doc" : {"title" : "My updated blog post"} }

运行命令:

curl -i -H "Content-Type: application/json" -XPOST 'http://10.24.54.241:9200/website/blog/_bulk?pretty' --data-binary @bulk.json

批量运行后的返回值:

HTTP/1.1 200 OK
Warning: 299 Elasticsearch-6.7.2-56c6e48 "Deprecated field [_retry_on_conflict] used, expected [retry_on_conflict] instead"
content-type: application/json; charset=UTF-8
content-length: 412

{
  "took" : 191,
  "errors" : false,
  "items" : [
    {
      "update" : {
        "_index" : "website",
        "_type" : "blog",
        "_id" : "123",
        "_version" : 5,
        "result" : "updated",
        "_shards" : {
          "total" : 2,
          "successful" : 2,
          "failed" : 0
        },
        "_seq_no" : 4,
        "_primary_term" : 2,
        "status" : 200
      }
    }
  ]
}

文档更新后的结果:

{
  "_index" : "website",
  "_type" : "blog",
  "_id" : "123",
  "_version" : 5,
  "_seq_no" : 4,
  "_primary_term" : 2,
  "found" : true,
  "_source" : {
    "title" : "My updated blog post",
    "text" : "Update Just trying this out...",
    "date" : "2014/01/01",
    "views" : 0,
    "tags" : [
      "tag1"
    ]
  }
}

title的值改变了。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值