Elasticsearch学习-ES中文档的基本操作

这篇具有很好参考价值的文章主要介绍了Elasticsearch学习-ES中文档的基本操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是文档

文档是索引中数据的基本单位,类似于关系型数据库中的一条记录,文档的在ES中以json的数据格式存储。

当一条记录存储到ES中后,ES会为每个文档添加一些除文档内容之外的其他属性信息,用来描述该文档。常用的以用来描述文档的属性有一下这些:

_index:表示文档存放在哪个索引中。索引我们大家都知道,它是一类结构相同的文档集合。看过前面文章"Elasticsearch学习-ES中的一些组件介绍"的老铁都知道,文档其实是被存储在分片中的,而索引仅仅是逻辑上的命名空间, 这个命名空间由一个或者多个分片组合在一起。 然而,这是一个内部细节,我们的应用程序根本不应该关心分片,对于应用程序而言,只需知道文档位于一个索引内即可, ES会帮我们处理这些所有的细节问题。

_type:文档所属的类型,类型是索引对文档的分类,是一种更细粒度的划分。在一个索引中的文档可能会有多种类型,不过在高版本中的ES中,已经弱化了类型的概念,在7.x的版本中,文档只有一种类型:_doc。

_id:ID 是一个字符串,当它和 _index 以及 _type 组合在一起,就可以唯一确定 ES 中的一个文档,当你创建一个新的文档,要么业务自定义id ,要么让ES自动生成。

_version:是文档在ES中的版本,第一次索引一个文档中,版本号是1,后面每次对文档进行更新时,版本号都会递增,文档的版本号,主要用来实现并发更新文档时保证数据的一致性,类似于乐观锁的作用。

_source:是被索引文档的内容。

二、文档的基本操作

下面介绍一下对文档的一些基本操作,对于存储类中间件的操作,通常包括如下四种:增,删,改和差,也就是常说的crud。

新增文档:

上面说过,在索引一个文档时,可以指定id,也可以使用ES来自动生id。

如果使用业务指定的文档id的话,可以使用下面的方式:

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

使用PUT命令,如果文档不存在,就插入,如果文档存在就更新,判断文档是否存在的依据是,index,type和id三个字段的组合是否存在。其中index表示文档要写入到哪个索引,type表示文档是哪种类型,id是业务指定的id。

举个例子,索引称为 website ,类型称为 blog ,并且选择 1 作为 ID ,那么索引请求应该是下面这样:

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

此时ES的响应如下:

{
   "_index":    "website",
   "_type":     "blog",
   "_id":       "1",
   "_version":  1,
   "created":   true
}

其中_id为业务指定的1,_version为文档的当前版本1,created:true表示此次操作为新增。

如果使用ES自动生成文档id的话,可以使用下面这种方式:

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

和上面使用PUT命令不同的是,使用POST命令,不用指定ID,其余参数相同。不过也需要指定文档要写入索引和文档的内容。此时ES的响应如下:

{
   "_index":    "website",
   "_type":     "blog",
   "_id":       "AVFgSgVHUP18jI2wRx0w",
   "_version":  1,
   "created":   true
}

其中id为AVFgSgVHUP18jI2wRx0w,是ES自动帮我们生成的。

自动生成的 ID 是 URL-safe、 基于 Base64 编码且长度为20个字符的 GUID 字符串。 这些 GUID 字符串由可修改的 FlakeID 模式生成,这种模式允许多个节点并行生成唯一 ID ,且互相之间的冲突概率几乎为零

查询文档:

查询文档的方式有多种,可以按照id直接查询,也可以按照指定的其他条件查询,本文先演示基于id查询,其他条件的查询方式,后面用单独文章介绍。和插入类似,查询文档也需要指定index和type,表示从哪个索引中,找那种类型的文档。类似下面这种形式:

GET /{index}/{type}/{id}

查找id=1的文档:

GET /website/blog/1

ES的响应如下:

{
  "_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"
  }
}

在返回的结果中,found表示结果是否找到,如果found值为true,表示找到了目标文档,如果目标文档不存在,那么返回的结果,仍然是一个json结果,只不过found为false。

很多时候,我们可能只需要返回结果的中文档内容,也就是_source字段,此时查询语句可以如下:

GET /website/blog/1/_source

此时返回的结果只有文档内容,结果如下:

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

如果我们只需要文档内容的某些字段的话,此时可以在查询语句中指定要返回的字段名称即可,比如我们只需要title字段,查询语句如下:

GET /website/blog/123?_source=title

ES的返回结果如下:

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 1,
  "found" :   true,
  "_source" : {
      "title": "My first blog entry"
  }
}
修改文档:

修改文档通常是对指定某个文档的内容做修改,此时同样可以使用PUT来完成,比如,将id=1的文档title修改“My first blog entry2”,可以指定如下命令:

PUT /website/blog/1
{
  "title": "My first blog entry2",
  "text":  "Just trying this out...",
  "date":  "2022/01/01"
}

此时ES的返回结果如下:

{
   "_index":    "website",
   "_type":     "blog",
   "_id":       "1",
   "_version":  2,
   "created":   false
}

和第一次执行结果不同的是,本次返回结果中_version为2,created的值变为false。

此时在查看文档,文档的title已经发生了变化:

GET /website/blog/1

ES的响应如下:

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry2",
      "text":  "Just trying this out...",
      "date":  "2014/01/01"
  }
}
删除文档

使用DELETE命令可以删除指定id的文档,具体命令如下:

DELETE /website/blog/123

如果找到该文档,ES会返回一个 200 ok 的 HTTP 响应码,和一个类似以下结构的响应体。注意,字段 _version 值已经增加:

{
  "found" :    true,
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 3
}

如果文档没有找到,我们将得到 404 Not Found 的响应码:

{
  "found" :    false,
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "123",
  "_version" : 4
}

即使文档不存在( found 是 false ), _version 值仍然会增加。这是 ES内部记录本的一部分,用来确保这些改变在跨多节点时以正确的顺序执行。

三、如何解决并发更新问题

数据冲突

当使用ES api对文档进行并发更新时,可能会导致部分更新丢失,这对某些业务来说是不可接受,以电商商品库存量为例:在ES索引中的每一个文档记录着每个商品的信息和该商品的库存量。每当有用户下单,存库就会减1。当多个用户同时下单时,可能就会导致库更新错误,导致商品超卖。具体如下图:
Elasticsearch学习-ES中文档的基本操作
用户1和用户2同时下单,下单后,库存量正常应该是98,但是由于并发的原因,导致存库量仍然是99,导致了库存量错误。

因为在整个下单的过程中,会涉及多个独立操作:获取当前库存量库存量减1更新库存量。当变更越频繁读数据和更新数据的间隙越长,也就越可能丢失变更。

这种并发更新导致数据不一致的问题,在关系型数据库中的解决方案有两种:悲观锁和乐观锁。

悲观锁并发控制:这种方法被关系型数据库广泛使用,它假定有变更冲突可能发生,因此阻塞访问资源以防止冲突。 一个典型的例子是读取一行数据之前先将其锁住,确保只有放置锁的线程能够对这行数据进行修改。

乐观锁并发控制:该方法假定冲突是不可能发生的,并且不会阻塞正在尝试的操作。 然而,如果源数据在读写当中被修改,更新将会失败。应用程序接下来将决定该如何解决冲突。 例如,可以重试更新、使用新的数据、或者将相关情况报告给用户。

关于悲观锁和乐观锁的详细内容,可以参考“悲观锁和乐观锁的原理与实践”

乐观锁解决方案

在ES中,并发更新情况下数据冲突的解决方案是乐观锁。而在每个文档中都有一个_version属性,每次更新操作后,_version的值都会增加,ES就是利用该字段实现乐观锁的。

使用乐观锁解决并发情况下数据一致性的核心逻辑是保证请求处理顺序性。在ES中利用_version来保证请求处理顺序性:相同版本的请求,只处理先到达的,后到达请求会被拒绝处理。为了方便理解,我们看一下下面这个例子:

向文档中插入一条文档:

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

查看文档的版本:

GET /website/blog/1

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
  }
}

此时文档的_version=1。

此时我们我们修改文档内容,并指定版本号为1:

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

更新请求的响应为:

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "1",
  "_version": 2
  "created":  false
}

此时_version=2。

假如在上面执行更新操作的同时,还有另外一个客户端也在执行更新,更新请求的版本号同样是1,那么此时ES就会拒绝更新,返回结果如下:

{
   "error": {
      "root_cause": [
         {
            "type": "version_conflict_engine_exception",
            "reason": "[blog][1]: version conflict, current [2], provided [1]",
            "index": "website",
            "shard": "3"
         }
      ],
      "type": "version_conflict_engine_exception",
      "reason": "[blog][1]: version conflict, current [2], provided [1]",
      "index": "website",
      "shard": "3"
   },
   "status": 409
}

返回的结果的状态码为409,失败原因为版本冲突。

这里需要注意一下,在高版本的ES中,不再使用_version作为判断数据冲突的依据,而是利用 _seq_no和**_primary_term**两个字段作为判断依据,但是原理是相通的,这里不再赘述。

除了使用内部_version作为并发控制外,ES中还有一种使用外部版本号的方式,这里的外部主要是强调版本号是业务自己指定的,而非ES自动生成的。

外部版本号的处理方式和我们之前讨论的内部版本号的处理方式有些不同, ES不是检查当前 _version 和请求中指定的版本号是否相同, 而是检查当前 _version 是否 小于 指定的版本号。 如果请求成功,外部的版本号作为文档的新 _version 进行存储。

如下,我们使用外部版本号进行文档更新:

PUT /website/blog/2?version=5&version_type=external
{
  "title": "My first external blog entry",
  "text":  "Starting to get the hang of this..."
}

从请求的响应中,我们可以看到此时_version=5。

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 5,
  "created":  true
}

如果我们想让接下来对该文档更新成功的话,必须将_version设置为大于5的数值。如将_version设置为10:

PUT /website/blog/2?version=10&version_type=external
{
  "title": "My first external blog entry",
  "text":  "This is a piece of cake..."
}

响应的结果标识_version为10.

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 10,
  "created":  true
}

而如果制定_version为小于等于5的数字是,更新将会失败。

四、总结

看到使用乐观锁来解决并发问题,你有没有发现,很多知识都是相同的,乐观锁不仅可以在ES中使用,在关系型数据库中使用的也很广泛,很多基础性原理知识,不会随着新框架的迭代而淘汰,类似于之前学习的数据结构,操作系统等课程,所以,在日常的学习过程中,一定要学习基础性知识,只有这些知识学好了,学习其他新的框架才能更快。文章来源地址https://www.toymoban.com/news/detail-401834.html

到了这里,关于Elasticsearch学习-ES中文档的基本操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch 实战之三:ES 基本操作

    目录 0. 数据格式说明 1. ES的基本操作 1.1 索引操作 1.1.1 建立索引 1.1.2  删除索引 1.1.3  查询索引 1.2 映射操作 1.2.1 建立映射 1.2.2 查询映射 1.3 基本操作-CRUD 1.3.1 新增和替换文档 1.3.2 查询文档 在实战开始之前,为了便于书写和沟通,本文先来约定一下如何在文章中表达请求

    2024年02月11日
    浏览(30)
  • Elasticsearch使用系列-ES增删查改基本操作+ik分词

    ES是一个NoSql数据库应用。和其他数据库一样,我们为了方便操作查看它,需要安装一个可视化工具 Kibana。 官网: https://www.elastic.co/cn/downloads/kibana 和前面安装ES一样,选中对应的环境下载,这里选择windows环境,注意安装的版本一定要和ES的版本一致,不然可能会启动不起来。

    2024年02月01日
    浏览(41)
  • elasticsearch 7.9.3知识归纳整理(二)之 es基本原理及使用kibana操作es的常见命令

    一、es的基本原理与基础概念 1.1 倒排索引 倒排索引 源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。带

    2024年02月12日
    浏览(35)
  • 【ES】---ES的基本操作

    ES有4种客户端,分别是:Jest client、Rest client、Transport client、Node client。 ES支持两种协议 HTTP协议,支持的客户端有Jest client和Rest client Native Elasticsearch binary协议,也就是Transport client【7.0弃用】和Node client【2.3弃用】 Jest client非官方支持,在ES5.0之前官方提供的客户端只有Trans

    2024年02月08日
    浏览(26)
  • java 操作es 的基本操作

    创建索引 创建索引别名 索引的相关设置 查询索引数据 bulk 导入数据 持续更新中~ pom的坐标

    2024年01月20日
    浏览(33)
  • es基本操作使用

    es映射关系(对应数据库) ———————————————— 1.创建索引 创建索引时指定属性名,即映射关系 2.修改索引 3.删除索引 eg:delete /test/type1/1,表示删除test索引库中类型(表)为type1中id属性为1的document(记录)。 4.查询索引 表示查询某一个属性名为name的值为张

    2024年02月15日
    浏览(23)
  • 一些es的基本操作

    用postMan: 给名为population_portrait_hash_seven的索引增加了一个text类型的字段。 用chrome插件Elasticvue 的Rest接口,本质上应该也是发HTTP請求: 给这个接口增加了一个keyword类型的字段。 好像直接删除是不支持的。要建个新索引,再使用 Reindex API 将数据从旧索引复制到新索引,排除不

    2024年01月25日
    浏览(33)
  • kibana创建索引、文档基本操作

    众所周知,es和数据库的操作十分相似,只是在一些称呼上有所不同,如图 因此,想要在es上存储文档,就得先 创建索引 (好比想要在数据库存储数据,就得先创建表,才能在表里插入数据)。这次笔者主要是通过kibana进行es相应操作,所以给出kibana对应的索引、文档操作。

    2023年04月23日
    浏览(38)
  • Es的索引操作(代码中的基本操作)

    // 1.创建客户端对象 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost(\\\"localhost\\\", 9200, \\\"http\\\")) ); (1)创建索引 // 创建索引 - 请求对象 CreateIndexRequest request = new CreateIndexRequest(\\\"user\\\"); // 发送请求,获取响应 CreateIndexResponse response = client.indices().create(request, RequestOp

    2024年02月13日
    浏览(29)
  • ES基本操作(postman篇)

    关系型数据库 - Databases(库) - Tables(表) - Rows(行) - Columns(列)。 Elasticsearch - Indeces(索引) - Types(类型) - Documents(文档) - Fields(属性)。 需要注意的是:type的概念在es7.0之后已经删除了。  以下仅做刚入门学习使用,工作中基本不会使用这个方式 创建Index 其中shopping是Index的名称,注

    2024年02月12日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包