Skip to content

Elasticsearch vector store

Elasticsearch 8.x with indexed kNN over dense_vector and BM25 full-text search, selected via VECTOR_STORE_PROVIDER=elasticsearch.

Enable it

bash
VECTOR_STORE_PROVIDER=elasticsearch
ELASTICSEARCH_URL=http://localhost:9200
ELASTICSEARCH_API_KEY=your-api-key
# or, instead of the API key:
ELASTICSEARCH_USER=elastic
ELASTICSEARCH_PASSWORD=your-password

Install the client: pip install elasticsearch.

Configuration

VariableDefaultDescription
VECTOR_STORE_PROVIDERpgvectorSet to elasticsearch to use this store.
ELASTICSEARCH_URLhttp://localhost:9200URL of the Elasticsearch 8.x cluster.
ELASTICSEARCH_API_KEY(none)Optional API-key auth.
ELASTICSEARCH_USER(none)Optional basic-auth username, paired with the password.
ELASTICSEARCH_PASSWORD(none)Optional basic-auth password, paired with the user.

Notes

  • Unit-tested against a mocked Elasticsearch client, not integration-tested against a live cluster. The kNN/BM25 request bodies are asserted structurally, not executed, so smoke-test before production use.
  • Requires Elasticsearch 8.x for the dense_vector field with indexed kNN and cosine similarity. ES 7.x kNN via script_score is not implemented as a fallback.
  • keyword_search is native BM25 via a match query over the analyzed payload.data field; scores are unbounded (unlike ts_rank's 0..1) and the caller normalizes before fusion.
  • list/search cap out at ES's max_result_window (10k by default); deep offset paging past that raises rather than silently truncating.
  • increment_access uses update_by_query with a painless script: it is not transactional, and a concurrent write can cause a version conflict (retried once, then skipped). Writes use refresh="wait_for" so read-after-write behaves like Postgres, and valid_to uses a far-future sentinel date for 'infinity'.

The memory layer for AI agents.