Secondary index support for efficient value-based queries.
Secondary indexes enable fast lookups by specific value fields without scanning all keys. Each index maintains a mapping from indexed values to the keys that contain those values.
Features
- Automatic Maintenance: Indexes update automatically on put/delete
- Multiple Indexes: Support for multiple indexes per store
- Declarative Extractors: Define indexes with data specs (safe for replication)
- Efficient Lookups: O(1) lookup by indexed value
- Multi-value Support: Index multiple values per key (e.g., tags)
Declarative Extractor Specs (Recommended)
# Index on a map key
:ok = Concord.Index.create("users_by_email", {:map_get, :email})
# Index on a nested path
:ok = Concord.Index.create("by_city", {:nested, [:address, :city]})
# Index on the raw value
:ok = Concord.Index.create("by_value", {:identity})Anonymous function extractors are rejected because executing code references from a replicated log is not deterministic across nodes or code versions.
Summary
Types
Declarative extractor specification
Index name (unique identifier)
Value to index (must be comparable)
Functions
Creates a new secondary index.
Drops an existing secondary index.
Lists all secondary indexes.
Looks up keys by indexed value.
Rebuilds an index from all existing keys. Uses the declarative extractor spec stored in the state machine.
Types
@type extractor() :: Concord.Index.Extractor.spec()
Declarative extractor specification
@type index_name() :: String.t()
Index name (unique identifier)
@type index_value() :: term()
Value to index (must be comparable)
Functions
@spec create(index_name(), extractor(), keyword()) :: :ok | {:error, term()}
Creates a new secondary index.
Accepts a declarative extractor spec. Anonymous functions return
{:error, :invalid_extractor} before a storage command is issued.
Declarative Specs (Recommended)
:ok = Concord.Index.create("by_email", {:map_get, :email})
:ok = Concord.Index.create("by_city", {:nested, [:address, :city]})
:ok = Concord.Index.create("by_value", {:identity})
:ok = Concord.Index.create("by_first", {:element, 0})Options
:reindex- If true, reindex all existing keys (default: false):timeout- Operation timeout in milliseconds (default: 5000)
@spec drop( index_name(), keyword() ) :: :ok | {:error, term()}
Drops an existing secondary index.
Lists all secondary indexes.
@spec lookup(index_name(), index_value(), keyword()) :: {:ok, [String.t()]} | {:error, term()}
Looks up keys by indexed value.
@spec reindex( index_name(), keyword() ) :: :ok | {:error, term()}
Rebuilds an index from all existing keys. Uses the declarative extractor spec stored in the state machine.