-
Notifications
You must be signed in to change notification settings - Fork 20
Add Scalable Vector Search (SVS) library integration [MOD-8811] #598
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
b0520e7
to
3193382
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #598 +/- ##
==========================================
- Coverage 97.23% 96.52% -0.71%
==========================================
Files 106 110 +4
Lines 5713 6194 +481
==========================================
+ Hits 5555 5979 +424
- Misses 158 215 +57 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
fb170d9
to
7b4483e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very exciting!
For future development, please pay special attention to in-code comments that explain the logic and purpose behind key parts of the code.
Please note that any internal implementation of SVS dependency that uses threads should not be used.
Our library has its own thread pool, which should be used via RediSearch API to ensure proper resource management.
The same applies to logging—the SVS loger should point to the VecSimIndexInterface logging function
I also noticed a warning raised both in our CI and when building locally:
svs_extensions.h:57:17: note: '#pragma message: SVS LVQ is not available'
Is this expected?
Additionally, I observed that the SVS unit tests take significantly longer to run compared to their equivalent HNSW tests. Could you clarify why that might be?
auto prefetch_parameters = | ||
svs::index::vamana::extensions::estimate_prefetch_parameters(data); | ||
auto builder = svs::index::vamana::VamanaBuilder( | ||
graph, data, std::move(distance), parameters, threadpool, prefetch_parameters); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so actually the distance calculator component of the index is not going to be used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SVS has it's own distance calculation component with support of LVQ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so why is it initialized in svs factory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, do not understand the question.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'll open a pr to allow creating an index without a distance calculator component
Thank you much @meiravgri for the review.
Sure, I will add comments in most questionable parts of code. I see that many questions in the review were related to SVS API limitations and requirements - so I will try to explain the logic behind.
For the performance purpose, SVS utilizes kind of 'backend' parallelization which is based on internal threadpool. I agree that it would prefer to use RediSearch threadpool, but unfortunately, SVS TP usage do not match to RedisSearch behavior: RediSearch thread pool is seemed like 'asynchronous' - current thread is not blocked by tasks submitted to RediSearch TP. When SVS requires 'synchronous' threadpool - current thread should be blocked util all tasks are finished.
Yes, it is kind of warning that LVQ feature is not enabled for the SVS version you got.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!
Added a few comments to continue @meiravgri's review.
Let's make sure that commented code is removed and TODOs are handled before we continue the review. Thanks!
@@ -48,6 +48,43 @@ static VecSimResolveCode _ResolveParams_EFRuntime(VecSimAlgo index_type, VecSimR | |||
return VecSimParamResolver_OK; | |||
} | |||
|
|||
static VecSimResolveCode _ResolveParams_WSSearch(VecSimAlgo index_type, VecSimRawParam rparam, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add unit tests for errors use cases as well for coverage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unit tests added to 'test_svs.cpp'
src/VecSim/CMakeLists.txt
Outdated
set(SVS_REPOSITORY "https://github.com/intel/ScalableVectorSearch.git" CACHE STRING "SVS repository") | ||
|
||
include(FetchContent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a particular reason to use FetchContent
rather than using a submodule?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just followed existing VecSim approach: here is no .gitmodules
but googletest
, google_benchmark
, pybind11
linked using FetchContent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, since svs is a substantial submodule that is not only required for testing, we will want to have it as a git submodule to have a more convenient mechanism for tracking and changing the versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've switched SVS to submodule, but got PR builds fail because submodule update is not run in CI builds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be fixed now
6555a2d
to
6d8b83d
Compare
@alonre24, @meiravgri, I've made most of requested changes except cases where I need your answers/decisions (see my comments). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, and well done on improving the comments!
I’ve mostly completed the review—batch iterator is still WIP, but you can start addressing the requested modifications.
My main concerns:
-
Redundant allocation of preprocessors and index calculators.
-
Duplicate preprocessing happening in both VecSim and SVS.
-
Thread safety—what ensures it in the current implementation? I didn’t see any locks. Correct me if I’m wrong, but we agreed that this phase would include global locks.
fb22f24
to
8e82d4d
Compare
0a19127
to
feca261
Compare
memcpy(processed_blob.get(), original_data, data_size); | ||
// Preprocess each vector in place | ||
for (size_t i = 0; i < n; i++) { | ||
this->preprocessQueryInPlace(static_cast<DataType *>(processed_blob.get()) + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
correct. We should have an equivalent preprocessForStorageInPlace
that's on me to implement
} | ||
|
||
int addVectorsImpl(const void *vectors_data, const labelType *labels, size_t n) { | ||
if (n == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as discussed, assert n == 1 until tiered index is supported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
n==1
is the normal case to implement VecSimIndexInterface
see int addVector(const void *vector_data, labelType label) override
at line 288
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. i meant this is the only acceptable case for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like I have to remove the svs_bulk_vectors_add_delete_test
unit test as well.
But revert it back in tiered index.
Agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. In general, consider separting tiered svs and vanila tests
eca8bc4
to
8ed29d2
Compare
VecSimIndex_Free(index); | ||
} | ||
|
||
TYPED_TEST(SVSTest, resolve_ws_search_runtime_params) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alonre24 , please check if tests here and below meet this request: #598 (comment)
* Add new index algorithm 'SVS' including * New SVSindex class * SVS index factory * SVS-specific index parameters * SVS-specific runtime parameters * Implement SVS unit_test * Add 'SVS' algorithm support to Python bindings Co-authored-by: Dorin-Marian Ionita <dorin-marian.ionita@intel.com> Co-authored-by: Maria Markova <maria.markova@intel.com>
* Resolve formatting issues * Fix test_svs.py * Fix CMake options
* Shared ownership of SVS index implementation is removed from SVS_BatchIterator * More accurate index capacity calculation * Renamed template parameter for SVSGraphBuilder * Cleaned up includes * Refactored SVS index parameters handling * Added bulk-of-vectors preprocessing feature * Cleaned artefact comments
Renames: * VecSimOptionBool -> VecSimOptionMode * VecSimOption_DEFAULT -> VecSimOption_AUTO * Add "AUTO" option support to ResolveParams_UseSearchHistory()
* Defined CMake cache variable SVS_SHARED_LIB (default: OFF) to download and link SVS LVQ shared library
* Renamed internal helper functions SVSIndexVectorSize() -> QuantizedVectorSize() * Empty index capacity is 0 * Remove usage of VecSimQueryParams::batchSize from rangeQuery()
b811141
to
1599163
Compare
// clang-format off | ||
using SVSDataTypeSet = ::testing::Types<SVSIndexType<VecSimType_FLOAT32, float, VecSimSvsQuant_NONE> | ||
#if HAVE_SVS_LVQ | ||
,SVSIndexType<VecSimType_FLOAT32, float, VecSimSvsQuant_8> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to test other quantisation variants?
2f716e4
to
4d888fa
Compare
5cd2c63
to
48c5f7f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2 issues to deal in next PR
.dataSize = dataSize, | ||
.metric = svsParams.metric, | ||
.blockSize = svsParams.blockSize, | ||
.multi = false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to fail if we are given multi
is true
until we support this capability - index creation should return null
with proper logging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming there is no way to request creation of SVS index with multi=true
because no such option in the SVSParams
- in opposite to HNSD or BruteForce where .multi
field exists.
Am I wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right.
When will we have support to create SVS index of type multi as well?
@@ -1,2 +1,3 @@ | |||
pip>=21.1 | |||
poetry==1.4.2 | |||
mkl-devel>=2025.1.0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add the installation of mkl
to the install_script.sh
using sudo apt install intel-oneapi-mkl-devel
instead of here?
Also if you can add this line to the codeql-analysis.yml after "Install Cmake" step that would be great (not a must)
This PR introducing new index algorithm based on the Scalable Vector Search library.
Scalable Vector Search (SVS) is a performance library for vector similarity search based on Vamana indexing algorithm.
Thanks to the use of Locally-adaptive Vector Quantization (LVQ) and its highly optimized indexing and search algorithms,
SVS provides vector similarity search:
This enables application and framework developers using similarity search to unleash its performance on Intel ® Xeon CPUs (2nd generation and newer).
Full information about Scalable Vector Search functionalities and features described in the SVS documentation.
Change details
API changes
SVSParams
SVSRuntimeParams
Build configuration changes
SVS
library dependencySVS_REPOSITORY
allows to specify Scalable Vector Search repository URLSVS library integration sources
svs.h
-SVSIndex
class to implement new algorithmsvs_batch_iterator.h
- Batch Iterator implementation forSVSIndex
svs_utils.h
- Utility classes and functions for 'SVS' algorithm implementationsvs_extensions.h
- OptionalLVQ
supportsvs_factory.h
,svs_factory.cpp
- Index factory utilities for the 'SVS' algorithmtest_svs.cpp
- Unit tests for 'SVS' algorithm implementationTODO