Elasticsearch 索引文档时create、index、update的区别【学习记录】

本文基于elasticsearch7.3.0版本。

一、思维导图

elasticsearch中create、index、update都可以实现插入功能,但是实现原理并不相同。

Elasticsearch 索引文档时create、index、update的区别【学习记录】_第1张图片

二、验证index和create

由上面思维导图可以清晰的看出create、index的大致区别,下面我们来验证下思维导图中的场景:

1、首先明确一点:如何指定是create操作还是index操作?可以通过在ES DSL指令后面拼接op_type=create_create实现。

例:假设目前我有一个索引为my_index,现在要向ES中索引一条doc,并指定是create操作:

POST my_index/_doc/1?op_type=create
{
  "tag":"指定id为1,并指定为create操作"
}
# 上面请求等价于
POST my_index/_doc/1/_create
{
  "tag":"指定id为1,并指定为create操作"
}

声明:文章后面内容中,所有演示的指令均省略了后面具体doc的内容,请知悉,如下图所示。
在这里插入图片描述


2、思考并验证:当向ES中索引一条doc,执行对应DSL指令时,ES底层默认触发什么操作?

场景1)向ES中索引一条数据,没有指定id,执行指令POST my_index/_doc时:

当您在指令中不提供文档ID时,Elasticsearch会自动生成一个唯一的文档ID,并使用该ID进行create操作。

场景2)向ES中索引一条数据,指定的id不存在,执行指令POST my_index/_doc/1(doc id为1的文档不存在)时:

当您在指令中指定的文档ID不存在时,则会使用指定的文档ID来执行create操作。

场景3)向ES中索引一条数据,指定了id并且id存在,执行指令POST my_index/_doc/1(doc id为1的文档存在)时:

当您在指令中指定的文档ID已经存在时,则会使用指定文档ID来执行index操作,更新该文档。这是因为index操作在存在相同文档ID时会执行更新操作(版本号在原有基础上+1),而不是创建新文档。

场景4.)向ES中索引一条数据,指定了id并且id存在,并指定了版本号,执行指令POST my_index/_doc/1?version=7&version_type=external时:

上述指令在Elasticsearch中,假设ID为1的文档已经存在,则会执行Elasticsearch的index操作。

在这个请求中,通过指定version参数为7和version_type参数为external,您告诉Elasticsearch在执行index操作时,将指定的版本号与文档的当前版本号进行比较。如果指定的版本号与当前版本号符合匹配规则,则会执行更新操作,否则会返回版本冲突错误。

补充:DSL中如何指定一个版本号?POST my_index/_doc/1?version=7&version_type=external_gte

  • version:外部指定版本号
  • version_type:外部版本号校验类型,有两种:external(默认,外部版本号必须要大于内部版本号),external_gte(外部版本号大于等于内部版本号)

注意:如果DSL指令如果指定了版本号,那么必须指定doc id,否则会报错。

3、下面我们演示思维导图中几种执行报错的场景:

场景1)执行create操作时,指定doc id并且id存在时,会报错。执行POST my_index/_doc/1?op_type=create指令,执行结果如下:[1] :版本冲突,文档已存在(当前版本[7])
Elasticsearch 索引文档时create、index、update的区别【学习记录】_第2张图片

场景2)执行create操作时,指定外部版本号时,会报错。那么执行POST my_index/_doc/1?op_type=create&version=8&version_type=external指令,执行结果如下:验证失败:1:创建操作仅支持内部版本控制。改为使用索引;
Elasticsearch 索引文档时create、index、update的区别【学习记录】_第3张图片

场景3)通过index更新数据时,指定的外部版本号没有超过当前版本号时,会报错。

先执行GET my_index/_doc/1指令,查看doc id为1的数据对应的version,可以看到id为1的doc,version为7。
Elasticsearch 索引文档时create、index、update的区别【学习记录】_第4张图片
当我们执行指令POST my_index/_doc/1?version=7&version_type=external时(指定了版本号没有指定op_type时,默认就是index操作),执行结果如下:[1] :版本冲突,当前版本[7]高于或等于提供的版本[7]
Elasticsearch 索引文档时create、index、update的区别【学习记录】_第5张图片

三、index和create小结

  1. 执行DSL指令,不指定文档id或指定文档id不存在时,系统会默认生成一个唯一的id,执行create操作,索引一个新文档;
  2. 执行DSL指令,指定了doc id并且存在时,默认执行index操作,会执行更新操作而不是索引新文档(如果此处显示的指定了create操作会报错);
  3. 执行DSL指令,指定了doc id并且存在时,默认执行index操作,如果此时又指定了外部版本号又显示指定操作类型为create,由于create操作只支持内部版本控制,会报错;
  4. 执行DSL指令,指定了doc id并且存在,同时又指定了外部版本号,此时指定的外部版本号必须大于或大于等于当前版本号,否则会执行错误。

四、update操作

在Elasticsearch的DSL指令中,可以使用以下方式来更新文档:

1、使用update指令:update指令用于更新指定文档的内容。更新可以是部分更新或完整替换,具体取决于您提供的更新内容。下面是一个示例:

其中,index_name是索引名称,doc_id是要更新的文档ID,field1是要更新的字段名称,new_value是要更新的字段值。

POST /index_name/_update/doc_id
{
  "doc": {
    "field1": "new_value"
  }
}

使用doc_as_upsert参数:如果要更新的文档doc_id不存在,您可以通过设置doc_as_upsert参数为true来执行全量覆盖操作。此时Elasticsearch会将doc参数中的内容作为新文档插入索引。下面是一个示例:

POST /index_name/_update/doc_id
{
  "doc": {
    "field1": "new_value"
  },
  "doc_as_upsert": true
}

2、使用update_by_query指令:update_by_query指令用于根据查询条件批量更新文档。您可以在查询条件中指定要更新的文档范围,然后提供要进行更新的内容。下面是一个示例:

POST /index_name/_update_by_query
{
  "query": {
    "match": {
      "field1": "value"
    }
  },
  "script": {
    "source": "ctx._source.field1 = 'new_value'"
  }
}

除了上述示例中的方式,还可以使用其他的更新方式,如通过script脚本来指定更新逻辑,或者使用upsert选项来指定如果文档不存在时要执行的操作。

请注意,具体的更新语法和选项可能会因Elasticsearch的版本而有所不同。建议参考官方文档或特定版本的API文档以获取准确的语法和选项。

五、index和update小结

1、在Elasticsearch中,如何选择使用index还是update进行doc更新?

  • index操作:使用index操作时,无论文档是否已存在,都会将提供的文档数据进行索引。如果指定的文档ID已存在,将会更新该文档的内容。这意味着index操作既可以用于创建新文档,也可以用于更新现有文档。

  • update操作:使用update操作时,可以对现有文档进行部分更新,而不是替换整个文档。通过update操作,您可以指定要应用的更新脚本或部分文档,以及如何更新现有文档的字段。这种方式更适合于需要对文档进行增量更新的情况。

因此,您可以根据具体的需求来选择使用index操作还是update操作。如果您希望完全替换文档或创建新文档,可以使用index操作。如果您只需要对文档的部分内容进行更新,可以选择update操作。

2、Elasticsearch的update和Lucene的update有哪些区别?

  • 粒度不同:Lucene的update操作是底层索引库的操作,它以文档为单位进行更新。而Elasticsearch的update操作是在更高级别的抽象上进行的,可以对文档的部分内容进行更新。

  • 更新方式不同:Lucene的update操作是通过先删除原始文档,再插入新文档来实现更新。而Elasticsearch的update操作可以通过使用更新脚本、部分文档或者提供的更新内容,对现有文档进行增量更新。

  • 并发处理不同:Lucene的update操作是在单个节点上执行的,不支持分布式并发更新。而Elasticsearch的update操作是分布式的,可以在多个节点上并发执行更新操作。

  • 功能扩展性不同:Elasticsearch的update操作提供了更丰富的功能和灵活性,如支持脚本更新、条件更新、局部更新等。而Lucene的update操作相对较为基础,功能较为有限。

总的来说,Lucene的update操作是底层索引库的原子操作,而Elasticsearch的update操作是在Lucene之上进行的更高级别的操作,提供了更多的功能和灵活性,适用于分布式环境下的文档更新需求。

3、ES 的DSL指令什么时候会使用Lucene的更新操作?

在Elasticsearch的DSL指令中,并不会直接使用Lucene的更新操作。Elasticsearch的DSL指令是在更高级别的抽象上操作的,当您使用Elasticsearch的DSL指令(如update、update_by_query等)来更新文档时,Elasticsearch解析DSL指令,并根据指令中提供的更新内容,在内部生成相应的Lucene更新操作。

虽然在DSL指令中没有直接使用Lucene的更新操作,但是Elasticsearch底层的引擎是基于Lucene的,它会利用Lucene的功能来实现文档的更新。

你可能感兴趣的:(Elastic,Stack,elasticsearch,大数据)