In a store that answers only by key, which index shape suits a lookup by exact value, and which suits 'the twenty most recent'?
answer
- the access path picks the shape
- membership versus ranking
- one entry per value, one per path
- opaque bytes remove the choice
- an ordered index needs a bound
basics
~20 sAn exact-value lookup needs one index entry per value, holding an unordered member collection of matching keys. A ranked lookup needs a score-ordered collection. Both are application-maintained entries, and which the store can hold at all varies.
solid answer
~50 sThe access path decides the shape. "Which accounts have status suspended" is a membership question: one index entry per distinct value, `index:account-by-status:suspended`, holding an unordered member collection of account keys, with add on write and remove on change. "The twenty most recently active accounts" is an ordering question: one score-ordered collection for the access path, where the score carries the ordering you want to read back. The catch is that neither shape exists on every store. Where the server treats values as opaque bytes it only hands back, a many-member index has to be encoded into a single value you read whole, change and write back — which races with every other writer and is bounded by how large one entry may grow. On such a store the honest design is one small index entry per value and no ranked access path in the tier at all.
go deeper
Recall that both shapes are entries your code writes. Say what the index is keyed by and what it holds, before worrying about how the store represents it.
Explain why a membership lookup and a ranked lookup need different index entries, and count the operations each shape costs on create, change and delete.
State what changes where the server only hands back opaque bytes: no partial change, a read-modify-write per add, and a ranked access path that may not belong in the tier at all.
Challenge the number of access paths rather than the shape of each. Each one is permanent write amplification and permanent repair surface across every service that writes.
## Start from the access path, not the data An application-maintained index is a second entry the application writes so it can look something up by a value. It is built for exactly one question, and the question decides the shape. Two questions cover almost every case seen in practice. - **"Which accounts have this value?"** — a membership question. The answer is a set of keys and their order does not matter. - **"Which twenty accounts are most recent?"** — a ranking question. The answer is a slice of an order, and which slice you want is part of the read. Getting these confused is the usual design error: a membership index cannot answer a ranked question without the caller reading all of it, and an ordered index used for membership pays for an ordering nobody reads. ## The two shapes | | Membership lookup | Ranked lookup | |---|---|---| | Index entry | one per distinct value | one per access path | | Value held | an unordered member collection of keys | a score-ordered collection of keys | | Write on create | add the key to the entry for its value | add the key with its score | | Write on change | remove from the old value's entry, add to the new | write the new score for the same key | | Growth driver | the count of distinct indexed values | the count of keys ever added | | Bound needed | none beyond entry size | trimming, or it grows without limit | A concrete membership index: `index:account-by-status:suspended` holding the keys of suspended accounts. A concrete ranked index: `index:account-by-last-seen` holding each account key with a numeric score derived from when it was last seen. Both key strings are conventions a team invented, not a product surface. ## What varies between stores, and why it matters here This is the part that decides whether either shape is available at all. - Where the server **understands the value as a collection and can read or write part of it**, adding one key to a membership index is one small operation against a large index, and a ranked index can hand back the slice you asked for without the caller reading the rest. - Where the server treats values as **opaque bytes it only hands back**, there is no partial change. Every add is read the whole value, decode it, insert, encode, write it back. That has three consequences: two concurrent writers can overwrite each other's change, the index is capped by how large one entry may grow, and the cost of one add rises with how much the index already holds. So the same design question has two honest answers depending on the store, and a candidate who states only one is describing the store they know. On an opaque-value store the workable pattern is one small entry per indexed value — `index:account-by-email:[email protected]` holding a single key — and an acceptance that the ranked access path is not expressible in the tier and belongs to the engine that owns the data. ## What each shape costs on every write Both shapes turn one logical write into several operations: 1. Creating the account writes the entry and adds to the index. 2. Changing the indexed value removes the key from the old value's index entry and adds it to the new one — two index operations, not one. 3. Deleting the account has to remove the key from the index as well. A ranked index adds a fourth obligation: something has to bound it. Nothing removes a key from an ordered index because it got old, so without a trim on write or a periodic pass it accumulates every key ever added, and it becomes one of the largest entries in the keyspace. A **lifetime attached to the index entry** does not solve this either — it removes the whole index, not the stale members inside it. ## The shape that should make you stop When a design needs several values combined — "suspended accounts in this region, most recent first" — each combination is another index to write, another to repair, and the write amplification multiplies. That is the point at which an application-maintained index has stopped being a shortcut. Either a deployment has an **optional indexing add-on** that maintains value-level lookups server-side, in which case the store owns the correctness and you own its operational surface, or the question belongs to a system whose job is answering questions about values rather than returning what you named.
- Why does a ranked index need trimming when a membership index usually does not?A membership index shrinks naturally: the key leaves when its value changes or the account goes. A ranked index has no such event — a key that has not been touched for a year still sits in the order with an old score. Nothing removes it unless a write trims the tail or a periodic pass does, so it grows with every key ever added.
- On a store that only hands back opaque bytes, what makes a many-member index dangerous beyond being slow?Every add is a full read-modify-write, so two concurrent writers can both read the same version and the second write erases the first's member. The index then looks healthy and is quietly missing keys. The remedy belongs to the tier's concurrency tools — a grouped write or an optimistic check-and-set where the store offers one — not to the index design itself.
saying these in an interview costs you the question
- Picks the shape from the data, not from the lookup it must answer
- Assumes every store can change one member of a collection in place
- Leaves a ranked index unbounded because nothing complains
- Adds an index per value combination without counting the write amplification
- Thinks a lifetime on the index entry trims stale members inside it