How can I return vector_cosine_distance from search results?

I'm currently testing AshAi's embeddings support, and implemented a search based on the docs. I struggle to return the result of vector_cosine_distance(full_text_vector, ^search_vector) for debugging purposes. I tried to use a calculation, but I won't have access to search_vector. In Ecto I'd use a virtual field and use select_merge. What is the correct approach in Ash here?
read :search do
argument :query, :string, allow_nil?: false

prepare before_action(fn query, context ->
case YourEmbeddingModel.generate([query.arguments.query], []) do
{:ok, [search_vector]} ->
Ash.Query.filter(
query,
vector_cosine_distance(full_text_vector, ^search_vector) < 0.5
)
|> Ash.Query.sort(
{calc(vector_cosine_distance(full_text_vector, ^search_vector),
type: :float
), :asc}
)
|> Ash.Query.limit(10)

{:error, error} ->
{:error, error}
end
end)
end
read :search do
argument :query, :string, allow_nil?: false

prepare before_action(fn query, context ->
case YourEmbeddingModel.generate([query.arguments.query], []) do
{:ok, [search_vector]} ->
Ash.Query.filter(
query,
vector_cosine_distance(full_text_vector, ^search_vector) < 0.5
)
|> Ash.Query.sort(
{calc(vector_cosine_distance(full_text_vector, ^search_vector),
type: :float
), :asc}
)
|> Ash.Query.limit(10)

{:error, error} ->
{:error, error}
end
end)
end
Solution:
You can use calculations with arguments, and load that calculation in this preparation
Jump to solution
3 Replies
Solution
ZachDaniel
ZachDaniel4mo ago
You can use calculations with arguments, and load that calculation in this preparation
ZachDaniel
ZachDaniel4mo ago
load(vector_cosine_distance: %{search: search})
marot
marotOP4mo ago
Thanks! For reference:
prepare before_action(fn query, _context ->
search_query = query.arguments.query

case Sprout.Stories.EmbeddingModel.generate([search_query], []) do
{:ok, [search_vector]} ->
query
|> Ash.Query.filter(
vector_cosine_distance(full_text_vector, ^search_vector) < 0.99
)
|> Ash.Query.sort(vector_distance: {%{search_vector: search_vector}, :asc})
|> Ash.Query.limit(20)
|> Ash.Query.load(vector_distance: %{search_vector: search_vector})

{:error, error} ->
{:error, error}
end
end)
prepare before_action(fn query, _context ->
search_query = query.arguments.query

case Sprout.Stories.EmbeddingModel.generate([search_query], []) do
{:ok, [search_vector]} ->
query
|> Ash.Query.filter(
vector_cosine_distance(full_text_vector, ^search_vector) < 0.99
)
|> Ash.Query.sort(vector_distance: {%{search_vector: search_vector}, :asc})
|> Ash.Query.limit(20)
|> Ash.Query.load(vector_distance: %{search_vector: search_vector})

{:error, error} ->
{:error, error}
end
end)
calculate :vector_distance,
:float,
expr(vector_cosine_distance(full_text_vector, ^arg(:search_vector))) do
description "Calculates the cosine distance between the story's vector and a search vector"

argument :search_vector, {:array, :float} do
allow_nil? false
end

public? true
end
calculate :vector_distance,
:float,
expr(vector_cosine_distance(full_text_vector, ^arg(:search_vector))) do
description "Calculates the cosine distance between the story's vector and a search vector"

argument :search_vector, {:array, :float} do
allow_nil? false
end

public? true
end

Did you find this page helpful?