Solving single queries

by: Eric S. Téllez

using SimilaritySearch

This example shows how to perform single queries instead of solving a batch of them. This is particularly useful for some applications, and we also show how they are solved, which could be used to avoid some memory allocations.

dim = 8
db = MatrixDatabase(randn(Float32, dim, 10^4))
queries = db = MatrixDatabase(randn(Float32, dim, 100))
dist = Dist.SqL2()
G = SearchGraph(; dist, db)
ctx = SearchGraphContext()
index!(G, ctx)

Suppose you want to compute some \(k\) nearest neighbors, for this we use the structure KnnResult which is a priority queue of maximum size \(k\).


for _ in 1:10
    res = knnqueue(ctx, 3)

    @time search(G, ctx, randn(Float32, dim), res)
    @show minimum(res), maximum(res), argmin(res), argmax(res)
    @show collect(IdView(res))
    @show collect(DistView(res))
end
  0.321223 seconds (207.71 k allocations: 12.447 MiB, 99.97% compilation time)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (6.767519f0, 11.06007f0, 0x00000050, 0x0000005d)
collect(IdView(res)) = UInt32[0x00000050, 0x0000002c, 0x0000005d]
collect(DistView(res)) = Float32[6.767519, 7.7759, 11.06007]
  0.000016 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (3.3617616f0, 3.8380947f0, 0x0000000d, 0x00000004)
collect(IdView(res)) = UInt32[0x0000000d, 0x0000000e, 0x00000004]
collect(DistView(res)) = Float32[3.3617616, 3.796413, 3.8380947]
  0.000008 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (8.2357645f0, 9.138306f0, 0x00000053, 0x00000046)
collect(IdView(res)) = UInt32[0x00000053, 0x00000050, 0x00000046]
collect(DistView(res)) = Float32[8.2357645, 8.300881, 9.138306]
  0.000005 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (2.001161f0, 4.3428016f0, 0x00000063, 0x00000026)
collect(IdView(res)) = UInt32[0x00000063, 0x00000007, 0x00000026]
collect(DistView(res)) = Float32[2.001161, 2.1582375, 4.3428016]
  0.000004 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (3.4559214f0, 5.295722f0, 0x00000006, 0x00000053)
collect(IdView(res)) = UInt32[0x00000006, 0x00000034, 0x00000053]
collect(DistView(res)) = Float32[3.4559214, 4.200401, 5.295722]
  0.000004 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (2.8278906f0, 3.5725486f0, 0x00000034, 0x0000005d)
collect(IdView(res)) = UInt32[0x00000034, 0x0000002d, 0x0000005d]
collect(DistView(res)) = Float32[2.8278906, 3.2030373, 3.5725486]
  0.000003 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (3.2511568f0, 4.2245016f0, 0x0000000a, 0x00000007)
collect(IdView(res)) = UInt32[0x0000000a, 0x00000001, 0x00000007]
collect(DistView(res)) = Float32[3.2511568, 3.513402, 4.2245016]
  0.000002 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (2.131893f0, 3.3929784f0, 0x00000007, 0x00000001)
collect(IdView(res)) = UInt32[0x00000007, 0x0000003f, 0x00000001]
collect(DistView(res)) = Float32[2.131893, 3.2005408, 3.3929784]
  0.000004 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (1.8304625f0, 5.305498f0, 0x00000004, 0x0000001d)
collect(IdView(res)) = UInt32[0x00000004, 0x00000054, 0x0000001d]
collect(DistView(res)) = Float32[1.8304625, 5.2072606, 5.305498]
  0.000005 seconds (2 allocations: 128 bytes)
(minimum(res), maximum(res), argmin(res), argmax(res)) = (2.8658602f0, 3.7731998f0, 0x0000003e, 0x0000003f)
collect(IdView(res)) = UInt32[0x0000003e, 0x00000050, 0x0000003f]
collect(DistView(res)) = Float32[2.8658602, 3.6418056, 3.7731998]

Knn queue

This structure is the container for the result and it is also used to specify the number of elements to retrieve. As mentioned before, it is a priority queue


res = knnqueue(ctx, 4)
push_item!(res, 1, 10)
push_item!(res, 2, 9)
push_item!(res, 3, 8)
push_item!(res, 4, 7)
push_item!(res, 6, 5)
@show collect(viewitems(res))

# it also supports removals; yet `pop_min!` is not exported since currently is available only for `KnnSorted` queue backend.
@show :pop_min! => SimilaritySearch.pop_min!(res) 
push_item!(res, 7, 0.1)
@show :push_item! => res
@show :pop_max! => pop_max!(res)
res
# It can be iterated

@show collect(viewitems(res))
collect(viewitems(res)) = SimilaritySearch.IdDist[SimilaritySearch.IdDist(0x00000006, 5.0f0), SimilaritySearch.IdDist(0x00000004, 7.0f0), SimilaritySearch.IdDist(0x00000003, 8.0f0), SimilaritySearch.IdDist(0x00000002, 9.0f0)]
:pop_min! => SimilaritySearch.pop_min!(res) = :pop_min! => SimilaritySearch.IdDist(0x00000006, 5.0f0)
:push_item! => res = :push_item! => SimilaritySearch.KnnSorted{Vector{SimilaritySearch.IdDist}}(SimilaritySearch.IdDist[SimilaritySearch.IdDist(0x00000007, 0.1f0), SimilaritySearch.IdDist(0x00000004, 7.0f0), SimilaritySearch.IdDist(0x00000003, 8.0f0), SimilaritySearch.IdDist(0x00000002, 9.0f0)], 1, 4, 4, 0, 0)
:pop_max! => pop_max!(res) = :pop_max! => SimilaritySearch.IdDist(0x00000002, 9.0f0)
collect(viewitems(res)) = SimilaritySearch.IdDist[SimilaritySearch.IdDist(0x00000007, 0.1f0), SimilaritySearch.IdDist(0x00000004, 7.0f0), SimilaritySearch.IdDist(0x00000003, 8.0f0)]
3-element Vector{IdDist}:
 IdDist(0x00000007, 0.1f0)
 IdDist(0x00000004, 7.0f0)
 IdDist(0x00000003, 8.0f0)

Environment and dependencies

Julia Version 1.10.11
Commit a2b11907d7b (2026-03-09 14:59 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (x86_64-apple-darwin24.0.0)
  CPU: 8 × Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, skylake)
Threads: 8 default, 0 interactive, 4 GC (on 8 virtual cores)
Environment:
  JULIA_NUM_THREADS = auto
  JULIA_PROJECT = @.
  JULIA_LOAD_PATH = @:@stdlib
Status `~/Research/SimilaritySearchDemos/Project.toml`
  [aaaa29a8] Clustering v0.15.8
  [944b1d66] CodecZlib v0.7.8
  [5ae59095] Colors v0.13.1
  [a93c6f00] DataFrames v1.8.1
  [c5bfea45] Embeddings v0.4.6
  [f67ccb44] HDF5 v0.17.2
  [916415d5] Images v0.26.2
  [b20bd276] InvertedFiles v0.9.2
 [682c06a0] JSON v0.21.4
  [23fbe1c1] Latexify v0.16.10
  [eb30cadb] MLDatasets v0.7.21
  [06eb3307] ManifoldLearning v0.9.0
 [ca7969ec] PlotlyLight v0.11.0
  [27ebfcd6] Primes v0.5.7
  [ca7ab67e] SimSearchManifoldLearning v0.4.0
  [053f045d] SimilaritySearch v0.14.3
 [2913bbd2] StatsBase v0.33.21
  [7f6f6c8a] TextSearch v0.20.0
Info Packages marked with  and  have new versions available. Those with  may be upgradable, but those with  are restricted by compatibility constraints from upgrading. To see why use `status --outdated`