Get / Update / Delete APIs

The single-document read and mutate APIs: fetch by _id, partially modify a doc in place, or tombstone it — all addressed by primary key, not by query.

Why it matters

These are the OLTP-style operations on top of a search engine. GET is the only truly real-time read in Elasticsearch (it bypasses refresh); Update spares you a read-modify-write round-trip; Delete is a logical tombstone, not an immediate disk reclaim. Knowing what each actually does on segments prevents surprises about latency, disk usage, and lost updates.

How it works

APICallNotes
GetGET /idx/_doc/{id}real-time; reads translog if not yet refreshed
UpdatePOST /idx/_update/{id}partial merge, script, or upsert
DeleteDELETE /idx/_doc/{id}marks doc deleted in its segment
  • Update is not in-place — it GETs the [[documents|_source]], applies a partial doc or Painless script, then re-indexes the whole document. So _source must be enabled.
  • Upsertdoc_as_upsert:true or an upsert block inserts when the id is absent, updates when present.
  • retry_on_conflict=N auto-retries the read-modify-write loop on version conflicts — essential for hot counters.
  • Delete reclaims nothing immediately — space returns only when segment merges purge tombstones.

Example

POST /products/_update/SKU-22
{ "doc": { "price": 5.0 }, "doc_as_upsert": true }

POST /counters/_update/page-7?retry_on_conflict=5
{ "script": { "source": "ctx._source.views += params.n",
              "params": { "n": 1 } } }

The script path avoids fetching views to the client, but ES still re-indexes the full doc under the hood.

Pitfalls

  • Frequent updates = segment churn — every update writes a new doc + a tombstone; high-churn fields belong in a counter store or are batched, not updated per event.
  • Stale GET after deleteGET is real-time, but a _search may still return the doc until the next refresh.
  • Update needs _source — disabling _source to save disk silently breaks Update, Reindex, and update_by_query.

See also