How to save a KDTree properly

I want to save a KDTree into the disk and reuse it again with JLD2, but ran into problem after loading it,

using NearestNeighbors
using FileIO, JLD2

kdtree = KDTree(rand(2, 100))
save("/tmp/test.jld2", "kdtree", kdtree) # it works

but I got warning when loading the saved one,

julia> kdt = load("/tmp/test.jld2", "kdtree");
┌ Warning: type StaticArrays.SArray{Tuple{2},Float64,1,2} does not exist in workspace; reconstructing
└ @ JLD2 ~/.julia/packages/JLD2/KjBIK/src/data.jl:1153
┌ Warning: type Distances.Euclidean does not exist in workspace; reconstructing
└ @ JLD2 ~/.julia/packages/JLD2/KjBIK/src/data.jl:1153
┌ Warning: type parameters for KDTree{getfield(JLD2.ReconstructedTypes, Symbol("##StaticArrays.SArray{Tuple{2},Float64,1,2}#366")),getfield(JLD2.ReconstructedTypes, Symbol("##Distances.Euclidean#367")),Float64} do not match type KDTree in workspace; reconstructing
└ @ JLD2 ~/.julia/packages/JLD2/KjBIK/src/data.jl:1133

and got an error when attempting to query with the loaded tree

julia> knn(kdt, [1, 2.0], 3)
ERROR: MethodError: no method matching knn(::getfield(JLD2.ReconstructedTypes, Symbol("##KDTree{getfield(JLD2.ReconstructedTypes, Symbol("##StaticArrays.SArray{Tuple{2},Float64,1,2}#366")),getfield(JLD2.ReconstructedTypes, Symbol("##Distances.Euclidean#367")),Float64}#368")), ::Array{Float64,1}, ::Int64)
Closest candidates are:
  knn(::NNTree{V,P} where P<:Distances.Metric, ::AbstractArray{T<:Number,1}, ::Int64) where {V, T<:Number} at /Users/fineday/.julia/packages/NearestNeighbors/N7lgR/src/knn.jl:40
  knn(::NNTree{V,P} where P<:Distances.Metric, ::AbstractArray{T<:Number,1}, ::Int64, ::Any) where {V, T<:Number} at /Users/fineday/.julia/packages/NearestNeighbors/N7lgR/src/knn.jl:40
  knn(::NNTree{V,P} where P<:Distances.Metric, ::AbstractArray{T<:Number,1}, ::Int64, ::Any, ::Function) where {V, T<:Number} at /Users/fineday/.julia/packages/NearestNeighbors/N7lgR/src/knn.jl:40
  ...
Stacktrace:
 [1] top-level scope at none:0

so what’s the proper way to save it?

1 Like

For saving arbitrary Julia data I never find anything that works well so I always fall back to serialize:

julia> using Serialization

julia> serialize("/tmp/test", kdtree)

julia> deserialize("/tmp/test")
KDTree{StaticArrays.SArray{Tuple{2},Float64,1,2},Euclidean,Float64}
  Number of points: 100
  Dimensions: 2
  Metric: Euclidean(0.0)
  Reordered: true

Note that you might not be able to load serialized data from previous julia versions but so far it has been pretty stable in practice.

3 Likes

It works perfectly, thanks so much.

1 Like