Reindexing
Rebuild an index when the schema changes, without dropping a query — and understand exactly what a rebuild does and does not fix.
Reindexing rebuilds the whole collection. You need it when the shape of your
data changes, not the data itself: a new field, a changed type, a switch in
facet, sort or tokenization. Content updates do not need a reindex — those go
through delta sync.
Why queries keep working during a rebuild
Search never reads a collection directly. It reads an alias, and the alias points at a versioned collection:
aacsearch_org123_products ← alias, what every query uses
└─ aacsearch_org123_products_v3 ← live collectionA reindex builds _v4 next to _v3. Only when _v4 is completely filled, and
synonyms and curations are replayed into it, does the alias move. The swap is a
single metadata operation, so there is no window where a query hits a
half-filled collection.
Running a reindex
curl -sS -X POST "$AAC_API/indexes/products/reindex" \
-H "Authorization: Bearer $AAC_KEY"No request body. The call answers 202 Accepted at once and queues a
reindex job; a scheduler worker runs the rebuild under a
lease, so no HTTP request is held open:
{
"index": "products",
"job_id": "clx8f2...",
"status": "queued",
"status_url": "/api/v1/jobs/clx8f2...",
"request_id": "req_..."
}Poll the job until status is completed:
curl -sS "$AAC_API/jobs/clx8f2..." -H "Authorization: Bearer $AAC_KEY" | jq '.job | {status, phase, progress, result}'The finished job's result holds documents (written into the new collection)
and duration_ms. A second reindex while a reindex or a snapshot restore is
queued or running answers 409 JOB_CONFLICT with the active job_id.
DELETE /jobs/{jobId} cancels a rebuild that has not reached the alias swap.
?sync=true keeps the old blocking call that answers 200 with
{ index, job_id, documents, duration_ms }. It exists for test suites only, and it
is subject to the same 409 JOB_CONFLICT check. A rebuild only replaces the
target index's live collection; other indexes in the organization are untouched.
Requirements
| Requirement | Why |
|---|---|
Key with settings:write | A reindex changes collection metadata |
Plan feature reindex | Metered on Free |
| Rate limit headroom | Reindex is rate-limited — it must not be triggered in a loop |
Phases
The job reports phase and progress while it runs:
| Phase | Progress | What is happening |
|---|---|---|
queued | 0 | Waiting for a worker |
loading | 10 | Job claimed; new collection being created |
copying | 15 → 88 | Documents written into the new collection, synonyms and curations replayed |
swapping | 90 | Alias being repointed — the job can no longer be cancelled |
done | 100 | status is completed |
If the job fails the alias does not move — old data keeps serving. A failed reindex loses nothing: a collection that an alias serves is never dropped by a failed or cancelled build. If the worker process dies mid-build, the lease expires, the job is claimed again and the abandoned shadow collection is dropped.
Writes that arrive during the build are not lost: right before the swap, the
documents written or changed since the build started, and the documents deleted
meanwhile, are applied to the new collection. Server signals (_popularity,
graph_*) are copied over from the live collection.
Progress is visible through GET /jobs/{jobId} and in the
console (Sync).
Where the documents come from
The build reads from the document mirror — search_document.payload, the copy
of every document kept in the database. Two consequences matter:
- a schema change does not mean re-crawling your source;
- if your CMS is down, the rebuild still runs.
Legacy rows written before the mirror existed have no payload. Those are copied
from the live collection instead, so a mixed index loses nothing.
Rollback
The previous collection is kept after the swap rather than deleted immediately — a rebuild that imports fine can still produce a worse index.
Note: the rollback endpoint is not exposed yet. It is planned on the API surface; until it ships, treat a reindex as one-way and verify the result before running it on production. A retained collection can be repointed manually by support.
This limitation is deliberate to document rather than hide: an index that cannot be rolled back should not be rebuilt on a Friday.
What gets carried over
| Item | Behaviour |
|---|---|
| Documents | Rebuilt from the mirror |
| Synonyms | Replayed after indexing |
| Curations | Replayed, including pins |
| Rules | Stored in the database, unaffected |
| Analytics and clicks | Stored per index, unaffected |
| API keys | Stored per organisation, unaffected |
Cost
A reindex writes every document once. On a metered plan that counts once against your write quota — the same as re-uploading everything, but without downtime.
| Documents | Typical duration |
|---|---|
| 10 000 | seconds |
| 100 000 | a few minutes |
| 1 000 000 | under an hour |
When a reindex is not needed
| Change | Reindex? | Instead |
|---|---|---|
| Document content | No | Delta sync |
| Add an optional field | No | Schema evolution |
| Add a field with a default | No | Schema evolution |
| Change a field type | Yes | — |
Turn facet on or off | Yes | — |
| Change tokenization or stemming | Yes | — |
| Delete a field | Yes | — |
If you only add fields, use schema evolution: it validates the change against the live collection and skips the rebuild entirely.
Verifying the result
curl -sS "$AAC_API/indexes/products" \
-H "Authorization: Bearer $AAC_KEY" \
| jq '{collection: .collectionName, alias: .aliasName, version: .schemaVersion}'aliasName keeps its value after a reindex — that is the point. schemaVersion
increments. If a query behaves oddly after a swap, compare document counts before
assuming a relevance problem:
curl -sS "$AAC_API/indexes/products/documents?per_page=1" \
-H "Authorization: Bearer $AAC_KEY" | jq '.total'A count that dropped between versions means the source was incomplete at build time. Rebuild rather than debug relevance.