删除API

Delete API

删除API容许根据ID从指定索引中删除一个类型化的JSON文档。html

DELETE /twitter/_doc/1

返回结果以下:node

{
  "_index": "twitter",
  "_type": "_doc",
  "_id": "1",
  "_version": 3,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 2,
  "_primary_term": 8
}

Versioning

索引的每一个文档都是版本化的。 删除文档时,能够指定版本,防止咱们要删除的文档实际上已被删除,可是在这期间没有更改。 每一个在文档上执行的写操做,包括删除,都会使其版本增长。 已删除文档的版本号在删除后短期内保持可用,以容许控制并发操做。 删除文档版本保持可用的时间长度由 index.gc_deletes 索引设置肯定,默认为60秒。算法

Routing

创建索引时使用了路由,那么删除文档,也必须提供路由值。 例如:api

DELETE /twitter_01/_doc/2?routing=user1

返回结果以下:数组

{
  "_index": "twitter_01",
  "_type": "_doc",
  "_id": "2",
  "_version": 2,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 2
}

以上将删除id为2的twitter_01,但会根据用户进行路由。 请注意,若是路由不正确,那么删除操做就会失败,文档不会被删除。并发

当_routing 映射设置为必须的,若是不指定路由值,删除API就会抛出RoutingMissingException并拒绝请求。elasticsearch

自动建立索引

若是使用外部版本,以前还没有建立索引,则删除操做会自动建立一个索引,而且若是以前未建立映射,还会为指定类型自动建立动态类型映射。ide

Distributed

经过hash计算出某个分片ID。 而后删除操做被重定向到该ID组中的主分片,而且被复制(若是须要)到该ID分组内的分片副本(有点不理解,应该是删除操做会在副本上执行一遍)。oop

等待活跃的Shards

在发出删除请求时,能够设置 wait_for_active_shards 参数,使得处理删除请求以前,必须知足最小数量的分片副本处于活动状态,不然会等待而不会立刻执行删除,。 有关更多详细信息和用法示例,请参阅此处post

Refresh

控制此请求所作的更改对搜索是否可见。 请参阅。

Timeout

执行删除操做时,分配的主分片可能不可用。 形成这种状况的一些缘由多是主分片目前正在从存储中恢复或正在进行迁移。 默认状况下,删除操做将等待主分片最多1分钟,若是仍是不可用则响应并显示错误。 timeout参数可用于显式指定它等待的时间。 如下是将其设置为5分钟的示例: DELETE /twitter/_doc/1?timeout=5m 

Delete By Query API

 _delete_by_query 的最简单用法是对每一个匹配查询的文档执行删除操做。 这里是API:

POST twitter/_delete_by_query
{
  "query": { 
    "match": {
      "message": "some message"
    }
  }
}

查询能够与Search API的方式相同,做为一个值传递给query键(就像上面这样)。 您也能够按照与search api相同的方式使用q参数。
返回的结果就像下面这样:

{
  "took" : 147,
  "timed_out": false,
  "deleted": 119,
  "batches": 1,
  "version_conflicts": 0,
  "noops": 0,
  "retries": {
    "bulk": 0,
    "search": 0
  },
  "throttled_millis": 0,
  "requests_per_second": -1.0,
  "throttled_until_millis": 0,
  "total": 119,
  "failures" : [ ]
}

_delete_by_query 操做在启动和删除时,使用internal版本去查找相应的索引,获取索引的快照。 这意味着若是文档在取得了快照以后还将来得及处理删除时发生了变化,将会发生版本冲突。 当版本匹配时,文档才被删除。
因为internal 版本值0不是有效版本号,所以版本等于零的文档不能使用_delete_by_query进行删除,请求会失败。

在执行_delete_by_query过程当中,会依次执行多个搜索请求,查找全部匹配文档并进行删除。每次找到一批文档时,会执行相应的批处理请求删除这些文档。若是搜索或批量请求被拒绝,_delete_by_query依赖默认策略重试拒绝的请求(最多10次,指数退避算法)。达到最大重试限制会致使_delete_by_query停止,这些失败的文档会响应在failures元素中。已执行的删除操做仍然有效。换句话说,该过程不会回滚,只能停止。
若是首次执行就失败而致使停止,全部失败都会在failures元素中返回;所以有可能存在至关多的失败实体。

若是您想计算版本冲突而不是致使它们停止,能够在url中设置conflicts=proceed 或者在请求正文中使用 "conflicts": "proceed"

向下面这样:

POST twitter/_doc/_delete_by_query?conflicts=proceed
{
  "query": {
    "match_all": {}
  }
}

也能够一次删除多个索引和多个类型的文档,索引和类型之间用/分隔。像search API同样:

POST twitter,blog/_docs,post/_delete_by_query
{
  "query": {
    "match_all": {}
  }
}

若是您提供了路由,那么路由将被复制给滚动查询,限制只有匹配该路由值的分片才能进行处理,从而提高查询效率:

POST twitter/_delete_by_query?routing=1
{
  "query": {
    "range" : {
        "age" : {
           "gte" : 10
        }
    }
  }
}

默认状况下,_delete_by_query使用1000的滚动批处理。您可使用scroll_size 这个URL参数更改批处理大小:

POST twitter/_delete_by_query?scroll_size=5000
{
  "query": {
    "term": {
      "user": "kimchy"
    }
  }
}

URL 参数

除了像pretty这样的标准参数以外,Delete By Query API也支持refresh,wait_for_completion,wait_for_active_shards,timeout and scroll。

发送refresh将刷新参与删除查询的全部分片。这与Delete API的refresh参数不一样,后者只会刷新接收删除请求的分片。

若是请求包含wait_for_completion = false,则Elasticsearch将执行一些预先检查,发起请求,而后返回task,可与Tasks APIs 一块儿使用以取消或获取任务的状态。 Elasticsearch也会在.tasks/task/${taskId}中以文档的形式建立此任务的记录。保留或删除取决于你。当不须要的时候尽可能删除它,以便Elasticsearch能够回收它使用的空间。

wait_for_active_shards控制在处理请求以前多少个分片副本必须处于活动状态。详情请看这里。timeout控制每一个写请求等待不可用分片变得可用的时间。这偏偏也是他们在Bulk API中的工做方式。因为_delete_by_query使用滚动搜索,能够指定scroll参数来控制它保持“搜索上下文” 活着的(alive)时间,例如?scroll=10m,默认状况下为5分钟。

requests_per_second能够设置为任何正十进制数(1.4,6,1000等)来限制速率,在此速率下,_delete_by_query会在批次之间填充等待时间发出删除操做。也就是会在下个批处理以前等一下子,能够经过将requests_per_second设置为-1来禁用限制。

这种限制是经过在批次之间等待来完成的,这样_delete_by_query在内部使用的滚动能够被赋予一个考虑计算填充的超时。填充时间是批处理大小除以requests_per_second与写入时间之间的差值。默认状况下,批处理大小为1000,所以若是requests_per_second设置为500:
target_time = 1000 / 500 per second = 2 seconds
wait_time = target_time - write_time = 2 seconds - .5 seconds = 1.5 seconds
因为批处理是做为单个_bulk请求提出的,所以大批量处理会致使Elasticsearch建立多个请求,而后等待一段时间再开始下一个处理。这是“突发性的”而不是“流畅性的”。默认值是-1。

Response body

响应的JSON向下面这样:

{
  "took" : 147,
  "timed_out": false,
  "total": 119,
  "deleted": 119,
  "batches": 1,
  "version_conflicts": 0,
  "noops": 0,
  "retries": {
    "bulk": 0,
    "search": 0
  },
  "throttled_millis": 0,
  "requests_per_second": -1.0,
  "throttled_until_millis": 0,
  "failures" : [ ]
}

took:整个操做从开始到结束的毫秒数。
timed_out:若是在查询执行删除期间执行的任何请求超时,则此标志设置为true。
total:已成功处理的文档数量。
deleted:已成功删除的文档数量。
batches:经过查询删除返回滚动响应的数量。
version_conflicts:按查询删除的版本冲突数量。
noops:对于按查询删除,此字段始终等于零。 它的存在是为了使查询删除和按查询更新,reindex API返回具备相同结构的响应。

retries:经过查询删除尝试的重试次数。 bulk是已重试的批量操做数,search是已重试的搜索操做数。
throttled_millis:请求睡眠的毫秒数为了符合requests_per_second。
requests_per_second:在按查询删除期间有效执行的每秒请求数。
throttled_until_millis:对于按查询删除,此字段始终等于零。 它只在使用Task API时有意义,它指示下一次将再次执行受限制的请求,以符合requests_per_second。
failures:若是在此处理中存在任何不可恢复的错误,则会出如今failures数组中。 若是非空,那么请求会由于那些失败而停止。 Delete-by-query是使用批处理实现的,任何故障都会致使整个进程停止,但当前批处理中的全部故障都会被收集到数组中。 您可使用conflict选项来防止reindex在版本冲突中停止。

Works with the Task API

可使用Task API获取任何正在运行的delete-by-query请求的状态:

GET _tasks?detailed=true&actions=*/delete/byquery

该响应看起来像下面这样:

{
  "nodes" : {
    "r1A2WoRbTwKZ516z6NEs5A" : {
      "name" : "r1A2WoR",
      "transport_address" : "127.0.0.1:9300",
      "host" : "127.0.0.1",
      "ip" : "127.0.0.1:9300",
      "attributes" : {
        "testattr" : "test",
        "portsfile" : "true"
      },
      "tasks" : {
        "r1A2WoRbTwKZ516z6NEs5A:36619" : {
          "node" : "r1A2WoRbTwKZ516z6NEs5A",
          "id" : 36619,
          "type" : "transport",
          "action" : "indices:data/write/delete/byquery",
          "status" : {    
            "total" : 6154,
            "updated" : 0,
            "created" : 0,
            "deleted" : 3500,
            "batches" : 36,
            "version_conflicts" : 0,
            "noops" : 0,
            "retries": 0,
            "throttled_millis": 0
          },
          "description" : ""
        }
      }
    }
  }
}

返回的status对象包含实际状态。 它就像是total字段的重要补充。 total是reindex预期执行的操做总数。 能够经过添加更新,建立和删除字段来估算进度。 当他们的总数等于total字段,请求将完成。
使用任务ID,您能够直接查找任务:

GET /_tasks/taskId:1

该API的优势是它与wait_for_completion = false集成,以透明地返回已完成任务的状态。 若是任务完成而且wait_for_completion = false已设置,则它将返回results或error字段。 此功能的代价是会在.tasks/task/$ {taskId}处建立wait_for_completion = false的文档。 删不删除该文档取决于你。

Works with the Cancel Task API

任何经过查询删除的操做均可以使用Task Cancel API来取消:

POST _tasks/task_id:1/_cancel

可使用上面的tasks API找到task_id。

取消应该会很快发生,但可能须要几秒钟。 上面的task status API将继续列出任务,直到它被唤醒以取消本身。

Rethrottling

运行中的查询删除,其中的request_per_second的值可使用_rethrottle API更改:

POST _delete_by_query/task_id:1/_rethrottle?requests_per_second=-1

可使用上面的tasks API找到task_id。

request_per_second就和在_delete_by_query API上设置同样,能够是-1来禁用限制,或者任何十进制数字如1.7或12来限制到相应的级别。 加快查询速度的Rethrottling会当即生效,但下降查询速度的rethrotting则在完成当前批次后生效。 这能够防止滚动超时。

Slicing

Delete-by-query支持切片滚动去并行化删除处理。这种并行化能够提升效率,并提供一种方便的方式将请求分解成更小的部分。

手动切片
为delete-by-query的每一个请求手动提供一个切片ID和切片总数:

POST twitter/_delete_by_query
{
  "slice": {
    "id": 0,
    "max": 2
  },
  "query": {
    "range": {
      "likes": {
        "lt": 10
      }
    }
  }
}
POST twitter/_delete_by_query
{
  "slice": {
    "id": 1,
    "max": 2
  },
  "query": {
    "range": {
      "likes": {
        "lt": 10
      }
    }
  }
}

可使用下面的代码来验证工做状况:

GET _refresh
POST twitter/_search?size=0&filter_path=hits.total
{
  "query": {
    "range": {
      "likes": {
        "lt": 10
      }
    }
  }
}

合理的total结果像下面这样:

{
  "hits": {
    "total": 0
  }
}

自动切片

还可让delete-by-query自动并行。 使用slices 指定要使用的切片数量:

POST twitter/_delete_by_query?refresh&slices=5
{
  "query": {
    "range": {
      "likes": {
        "lt": 10
      }
    }
  }
}

一样也能够验证你的工做:

POST twitter/_search?size=0&filter_path=hits.total
{
  "query": {
    "range": {
      "likes": {
        "lt": 10
      }
    }
  }
}

合理的total结果像下面这样:

{
  "hits": {
    "total": 0
  }
}

设置slices为auto将让Elasticsearch选择要使用的切片数量。该设置将使每一个分片一个切片,直到某个限制。若是有多个源索引,它将根据分片数最少的索引来选择切片的数量。

向_delete_by_query添加slices只是使上述部分中使用的手动过程自动化,建立子请求,这意味着它有一些怪异:

  • 能够在Tasks APIs中看到这些请求。这些子请求是具备slices请求的任务的“子”任务。
  • 具备slices的请求,获取任务的状态只包含已完成切片的状态。
  • 这些子请求可单独寻址,例如取消和从新限制。
  • 限制带slices 的请求将也会适当地限制未完成的子请求。
  • 取消带slices的请求也将会取消每一个子请求。
  • 用切片取消请求将取消每一个子请求。
  • 因为切片的性质,每一个子请求得到的文档不会被均匀分布。全部文档都将被寻址,但有些切片可能比其余切片大。 指望更大的切片具备更均匀的分布。
  • 诸如request_per_second和size之类的参数,具备slices的请求会按比例分配给每一个子请求。结合上面关于分布不均匀的观点,你应该得出结论:使用size和slices可能不会致使正确的size文档变为`_delete_by_query`ed (这句不通,贴个原文:the using  size  with  slices  might not result in exactly  size  documents being `_delete_by_query`ed.)。
  • 每一个子请求都会获取与索引略微不一样的快照,尽管这些快照几乎都是在同一时间取得的。

选择切片的数量

若是是自动切片,将slices 设置为 auto将为大多数索引选择合理的数字。若是是手动切片或调整自动切片,请采用这种方式。

当slices数等于索引中的分片数时,查询性能最为有效。若是这个数字很大(例如500),请选择一个较小的数字,由于太多的slices会损害性能。若是slices数高于分片数,一般不会提升效率反而会增长开销。

删除性能在可用资源与切片数量之间成线性变化。

不管是查询仍是删除,影响性能的主要因素仍是重建索引的文档和群集资源。

官方文档:

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html

相关文章
相关标签/搜索