@crowi/plugin-search-elasticsearch
v0.1.0-alpha.7
Published
Elasticsearch 9 search driver for Crowi 2.0.
Readme
@crowi/plugin-search-elasticsearch
Elasticsearch 9 search driver for Crowi 2.0. Indexes pages on create /
update / delete, serves the wiki search box, and rebuilds the whole
index from scratch on demand. Targets a <indexName>-current alias so
a rebuild can swap the underlying index atomically.
Install
crowi-admin plugin add @crowi/plugin-search-elasticsearch(or, in dev: pnpm --filter @crowi/api add -D @crowi/plugin-search-elasticsearch)
Configure
1. Activate the driver in crowi.config.json
{
"plugins": ["@crowi/plugin-search-elasticsearch"],
"search": { "driver": "elasticsearch" }
}A server restart is required when search.driver changes — Crowi
reads this file once at boot.
2. Fill in connection settings in the admin UI
Open /admin/plugins and edit @crowi/plugin-search-elasticsearch:
url—https://[user:pass@]host[:port][/indexName]. The URL embeds the cluster password (Bonsai-style), so it is encrypted at rest withCROWI_ENCRYPTION_KEY.indexName— base index name (defaultcrowi). The driver reads / writes the<indexName>-currentalias.requestTimeout— per-request timeout in ms (default5000).analyzer—default/kuromoji/sudachi(see below).
Post-save connectivity verification
Saving url / requestTimeout / the other connection settings from /admin/plugins triggers a non-blocking check after the save already succeeded and hot-reload has already run: a throwaway client (built from exactly the values you just saved, capped at a 10-second request timeout and no retries) calls the cluster's info API once, then closes. The admin UI shows the outcome ("saved, but verification failed" plus a fixed reason — unreachable / authentication failed / not found / unknown) without undoing the save.
This is an info-only check: it never touches an index, a document, or the <indexName>-current alias, and it never reflects whether the selected analyzer is actually usable on the cluster — analyzer plugin availability only surfaces when you run a rebuild (see the Caveats section above). It confirms the cluster is reachable and the credentials in url are accepted, nothing more. The result reflects only the api instance that handled your save request — it is not aggregated across replicas.
Hot-reload (no restart needed)
This plugin implements reconfigure, so saving connection settings
in the admin UI applies without a server restart. When you save:
- the
url/indexName/requestTimeout/analyzerchanges are picked up by the live driver, - a fresh Elasticsearch client is built and the previous one is closed in the background (its HTTP keep-alive pool drains),
- the admin UI shows a "saved — applied immediately" toast.
Mechanics: the driver holds its state in a StateCell (from the plugin
SDK's ctx.state(), not a hand-rolled module-scope variable). Each
operation (query / index / remove / rebuild) reads the cell
through withValue(), which snapshots the state for the call's whole
duration, so a save that lands mid-request cannot retarget an inflight
operation onto a different cluster — the next request sees the new
settings. The previous Elasticsearch client is closed once every
inflight operation that was still using it has settled (not the
instant reconfigure returns), so a save can never cut off a
request that's already in progress.
Caveats
- Analyzer changes need a manual rebuild. Switching
analyzer(default↔kuromoji↔sudachi) updates the setting immediately, but the existing index keeps its old analyzer — Elasticsearch analyzers are fixed at index-creation time. Run a full rebuild from/admin/search(or the rebuild action) to create a new index with the new analyzer and swap the alias to it. - Empty
url→ configuredurlis restart-only. Ifurlwas empty at boot, the driver is not registered and there is nothing forreconfigureto mutate; configure aurland restart once. After that, all further changes hot-reload. Clearing a configuredurl(configured → empty) is handled live — search requests then fail with a clearSearch not configurederror until aurlis set again. - A rebuild that is already running when you reconfigure runs to completion against the cluster / index name it started with.
Analyzer flavours
| Analyzer | Cluster requirement |
|---|---|
| default | No extra Elasticsearch plugin. |
| kuromoji | analysis-kuromoji plugin (Elastic-distributed). The dev image (elasticsearch.Dockerfile) preinstalls it. |
| sudachi | Third-party analysis-sudachi plugin + dictionary. Not bundled in the dev image — operators must build a derived image. Picking this without the plugin makes rebuild() fail. |
Verifying hot-reload in dev
The dev docker compose stack includes an Elasticsearch service, so
you can exercise the hot-reload path end to end:
docker compose up -d— brings up mongo / redis / elasticsearch.pnpm dev— starts api + web.- In
/admin/plugins, set@crowi/plugin-search-elasticsearch'surltohttp://elasticsearch:9200/crowiand save; restart once if the driver was previously unconfigured. - From
/admin/search, run a rebuild to populate the index. - Change
requestTimeout(or pointindexNameat a freshly rebuilt index) and save without restarting. The next search query uses the new settings — confirmed by the api log linereconfigured elasticsearch search driver (...).
See also
- RFC-0001 §"Search" for the migration story from the legacy ES7 indexer.
@crowi/plugin-storage-aws-s3— another driver built on the samectx.state()/StateCellhot-reload pattern.
