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
| API | Call | Notes |
|---|---|---|
| Get | GET /idx/_doc/{id} | real-time; reads translog if not yet refreshed |
| Update | POST /idx/_update/{id} | partial merge, script, or upsert |
| Delete | DELETE /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_sourcemust be enabled. - Upsert —
doc_as_upsert:trueor anupsertblock inserts when the id is absent, updates when present. retry_on_conflict=Nauto-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
GETafter delete —GETis real-time, but a_searchmay still return the doc until the next refresh. - Update needs
_source— disabling_sourceto save disk silently breaks Update, Reindex, and update_by_query.