From a74c532ae4987abd89089a1e32ad4676238ec259 Mon Sep 17 00:00:00 2001 From: Dor Forer Date: Wed, 26 Aug 2026 10:06:38 +0300 Subject: [PATCH] [MOD-18075] Allow custom HNSW neighbor debug implementations --- src/VecSim/algorithms/hnsw/hnsw.h | 2 +- src/VecSim/algorithms/hnsw/hnsw_tiered.h | 2 +- src/VecSim/vec_sim_debug.cpp | 57 +----------------------- src/VecSim/vec_sim_interface.h | 11 +++++ 4 files changed, 14 insertions(+), 58 deletions(-) diff --git a/src/VecSim/algorithms/hnsw/hnsw.h b/src/VecSim/algorithms/hnsw/hnsw.h index 2c1fae87f..8232c795f 100644 --- a/src/VecSim/algorithms/hnsw/hnsw.h +++ b/src/VecSim/algorithms/hnsw/hnsw.h @@ -285,7 +285,7 @@ class HNSWIndex : public VecSimIndexAbstract, return idToMetaData.data() + internal_id; } vecsim_stl::vector safeCollectAllNodeIncomingNeighbors(idType node_id) const; - VecSimDebugCommandCode getHNSWElementNeighbors(size_t label, int ***neighborsData); + VecSimDebugCommandCode getHNSWElementNeighbors(size_t label, int ***neighborsData) override; void insertElementToGraph(idType element_id, size_t element_max_level, idType entry_point, size_t global_max_level, const void *vector_data); void removeVectorInPlace(idType id); diff --git a/src/VecSim/algorithms/hnsw/hnsw_tiered.h b/src/VecSim/algorithms/hnsw/hnsw_tiered.h index a4d5e08e4..62b9c82a8 100644 --- a/src/VecSim/algorithms/hnsw/hnsw_tiered.h +++ b/src/VecSim/algorithms/hnsw/hnsw_tiered.h @@ -245,7 +245,7 @@ class TieredHNSWIndex : public VecSimTieredIndex { this->getHNSWIndex()->unlockSharedIndexDataGuard(); } - VecSimDebugCommandCode getHNSWElementNeighbors(size_t label, int ***neighborsData) { + VecSimDebugCommandCode getHNSWElementNeighbors(size_t label, int ***neighborsData) override { this->mainIndexGuard.lock_shared(); auto res = this->getHNSWIndex()->getHNSWElementNeighbors(label, neighborsData); this->mainIndexGuard.unlock_shared(); diff --git a/src/VecSim/vec_sim_debug.cpp b/src/VecSim/vec_sim_debug.cpp index c83790111..1a1eb4224 100644 --- a/src/VecSim/vec_sim_debug.cpp +++ b/src/VecSim/vec_sim_debug.cpp @@ -8,65 +8,10 @@ */ #include "vec_sim_debug.h" #include "VecSim/vec_sim_index.h" -#include "VecSim/algorithms/hnsw/hnsw.h" -#include "VecSim/algorithms/hnsw/hnsw_tiered.h" -#include "VecSim/types/bfloat16.h" extern "C" int VecSimDebug_GetElementNeighborsInHNSWGraph(VecSimIndex *index, size_t label, int ***neighborsData) { - - // Set as if we return an error, and upon success we will set the pointers appropriately. - *neighborsData = nullptr; - VecSimIndexBasicInfo info = index->basicInfo(); - if (info.algo != VecSimAlgo_HNSWLIB) { - return VecSimDebugCommandCode_BadIndex; - } - if (!info.isTiered) { - if (info.type == VecSimType_FLOAT32) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else if (info.type == VecSimType_FLOAT64) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else if (info.type == VecSimType_BFLOAT16) { - return dynamic_cast *>(index) - ->getHNSWElementNeighbors(label, neighborsData); - } else if (info.type == VecSimType_FLOAT16) { - return dynamic_cast *>(index) - ->getHNSWElementNeighbors(label, neighborsData); - } else if (info.type == VecSimType_INT8) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else if (info.type == VecSimType_UINT8) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else { - assert(false && "Invalid data type"); - } - } else { - if (info.type == VecSimType_FLOAT32) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else if (info.type == VecSimType_FLOAT64) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else if (info.type == VecSimType_BFLOAT16) { - return dynamic_cast *>(index) - ->getHNSWElementNeighbors(label, neighborsData); - } else if (info.type == VecSimType_FLOAT16) { - return dynamic_cast *>(index) - ->getHNSWElementNeighbors(label, neighborsData); - } else if (info.type == VecSimType_INT8) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else if (info.type == VecSimType_UINT8) { - return dynamic_cast *>(index)->getHNSWElementNeighbors( - label, neighborsData); - } else { - assert(false && "Invalid data type"); - } - } - return VecSimDebugCommandCode_BadIndex; + return index->getHNSWElementNeighbors(label, neighborsData); } extern "C" void VecSimDebug_ReleaseElementNeighborsInHNSWGraph(int **neighborsData) { diff --git a/src/VecSim/vec_sim_interface.h b/src/VecSim/vec_sim_interface.h index 9454b2534..8f6208b62 100644 --- a/src/VecSim/vec_sim_interface.h +++ b/src/VecSim/vec_sim_interface.h @@ -148,6 +148,17 @@ struct VecSimIndexInterface : public VecsimBaseObject { */ virtual VecSimDebugInfoIterator *debugInfoIterator() const = 0; + /** + * @brief Return the HNSW graph neighbors for a label, grouped by level. + * + * Non-HNSW indexes return VecSimDebugCommandCode_BadIndex. The caller owns successful + * output and must release it with VecSimDebug_ReleaseElementNeighborsInHNSWGraph. + */ + virtual VecSimDebugCommandCode getHNSWElementNeighbors(size_t label, int ***neighborsData) { + *neighborsData = nullptr; + return VecSimDebugCommandCode_BadIndex; + } + /** * @brief A function to be implemented by the inheriting index and called by rangeQuery. * @param queryBlob binary representation of the query vector. Blob size should match the index