Read-action preparation that turns an Ash read into a vector search — dense kNN, sparse (learned-sparse / BM25-style) kNN, or hybrid fusion (dense/sparse/full-text arms). Attach it to a read action whose arguments carry the query data:
# dense (default kind)
read :semantic_search do
argument :query_vector, {:array, :float}, allow_nil?: false
argument :k, :integer, allow_nil?: false
prepare {AshArcadic.Preparations.VectorSearch, index: :embedding}
end
# sparse
read :sparse_search do
argument :query_tokens, {:array, :integer}, allow_nil?: false
argument :query_weights, {:array, :float}, allow_nil?: false
argument :k, :integer, allow_nil?: false
prepare {AshArcadic.Preparations.VectorSearch, kind: :sparse, index: :sparse_embedding}
end
# hybrid — arms name the indexes/properties (developer config); the caller passes the values
read :hybrid_search do
argument :query_vector, {:array, :float}, allow_nil?: false
argument :query_tokens, {:array, :integer}, allow_nil?: false
argument :query_weights, {:array, :float}, allow_nil?: false
argument :text_query, :string, allow_nil?: false
argument :k, :integer, allow_nil?: false
prepare {AshArcadic.Preparations.VectorSearch,
kind: :hybrid,
arms: [{:dense, :embedding}, {:sparse, :sparse_embedding}, {:fulltext, :body}],
fusion: :rrf}
endOptions:
:kind(default:dense) —:dense|:sparse|:hybrid.:index(required for:dense/:sparse, atom) — the declaredvector_index/sparse_vector_indexname.:arms(required for:hybrid) — a list (len ≥ 2) of{:dense, index}|{:sparse, index}|{:fulltext, property}. The full-text arm'spropertyis an attribute with a host-created full-text index (there is no full-text DSL declaration — that is a later slice); the caller passes the:text_queryargument.:fusion(:rrfdefault |:dbsf|:linear),:weights,:group_by,:group_sizeride the fused output. A single:kargument bounds every arm and the fused result.:allow_global?(defaultfalse) — permit a cross-tenant search when no tenant is resolved. The Ash action must ALSO permit the no-tenant read (multitenancy :allow_global/:bypass), else Ash rejects it upstream withTenantRequired.:ef_search,:max_distance— dense only (sparse/fuse reject them);:group_by,:group_size— sparse pass-through.
It reads the query arguments, resolves the declared index metadata, validates a dense vector's
length against the declared dimensions, and stashes the request onto the query context
(:vector_search), which the data layer's set_context/3 copies onto %AshArcadic.Query{}.
All failures are value-free (never echo a vector / tokens / weights / text value).
Summary
Functions
Callback implementation for Ash.Resource.Preparation.supports/1.
Functions
Callback implementation for Ash.Resource.Preparation.supports/1.