Skip to content
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

[Feat] Add Support for Index merge in CAGRA #618

Merged
merged 22 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ba244fb
[Feat] Add Support for Index `merge` in CAGRA
rhdong Jan 27, 2025
1dd5140
Merge remote-tracking branch 'origin/branch-25.02' into rhdong/cagra-…
rhdong Jan 27, 2025
890a89e
Merge remote-tracking branch 'origin/branch-25.02' into rhdong/cagra-…
rhdong Jan 29, 2025
696c660
simplify the memory logic
rhdong Jan 28, 2025
318068c
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Jan 29, 2025
e5067c8
automatically the memory choose & judgment owning for better readability
rhdong Jan 30, 2025
1eb211a
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Jan 30, 2025
0fb7dff
Merge remote-tracking branch 'origin/branch-25.02' into rhdong/cagra-…
rhdong Jan 30, 2025
7af3ad8
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Jan 30, 2025
c69af18
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Jan 31, 2025
89d0a47
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Jan 31, 2025
8b95d7b
add `nullptr` checking & reduce binary size
rhdong Jan 31, 2025
7446f0e
increase max_allowed_size_compressed to '1.2G' with https://github.co…
rhdong Jan 31, 2025
e0633fa
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Feb 2, 2025
690e775
decouple the `merge_params` from `index_params`
rhdong Feb 2, 2025
6592d20
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Feb 4, 2025
afb6026
fix device memory allocation strategy
rhdong Feb 4, 2025
b49e04a
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Feb 5, 2025
da45bdb
add merge strategy for future extension
rhdong Feb 5, 2025
9d3acb0
reserve `PHYSICAL` only
rhdong Feb 6, 2025
ea7991b
revert the std::move
rhdong Feb 6, 2025
ca6c59f
Merge branch 'branch-25.02' into rhdong/cagra-merge
rhdong Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ if(BUILD_SHARED_LIBS)
src/neighbors/cagra_serialize_half.cu
src/neighbors/cagra_serialize_int8.cu
src/neighbors/cagra_serialize_uint8.cu
src/neighbors/cagra_merge_float.cu
src/neighbors/cagra_merge_half.cu
src/neighbors/cagra_merge_int8.cu
src/neighbors/cagra_merge_uint8.cu
src/neighbors/iface/iface_cagra_float_uint32_t.cu
src/neighbors/iface/iface_cagra_half_uint32_t.cu
src/neighbors/iface/iface_cagra_int8_t_uint32_t.cu
Expand Down
146 changes: 146 additions & 0 deletions cpp/include/cuvs/neighbors/cagra.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,17 @@ struct extend_params {
* 0. */
uint32_t max_chunk_size = 0;
};
/**
* @}
*/

/**
* @defgroup cagra_cpp_merge_params CAGRA index merge parameters
* @{
*/
struct merge_params : public index_params {
merge_params(const index_params& params) : index_params(params) {}
};

/**
* @}
Expand Down Expand Up @@ -1747,7 +1758,142 @@ void serialize_to_hnswlib(raft::resources const& handle,
void serialize_to_hnswlib(raft::resources const& handle,
const std::string& filename,
const cuvs::neighbors::cagra::index<uint8_t, uint32_t>& index);
/**
* @}
*/

/**
* @defgroup cagra_cpp_index_merge CAGRA index build functions
* @{
*/

/** @brief Merge multiple CAGRA indices into a single index.
*
* This function merges multiple CAGRA indices into one, combining both the datasets and graph
* structures.
*
* Usage example:
* @code{.cpp}
* using namespace raft::neighbors;
* auto dataset0 = raft::make_host_matrix<float, int64_t>(handle, size0, dim);
* auto dataset1 = raft::make_host_matrix<float, int64_t>(handle, size1, dim);
*
* auto index0 = cagra::build(res, index_params, dataset0);
* auto index1 = cagra::build(res, index_params, dataset1);
*
* std::vector<cagra::index<float, uint32_t>*> indices{&index0, &index1};
* cagra::merge_params params{index_params};
*
* auto merged_index = cagra::merge(res, params, indices);
* @endcode
*
* @param[in] res RAFT resources used for the merge operation.
* @param[in] params Parameters that control the merging process.
* @param[in] indices A vector of pointers to the CAGRA indices to merge. All indices must:
* - Have attached datasets with the same dimensionality.
*
* @return A new CAGRA index containing the merged indices, graph, and dataset.
*/
auto merge(raft::resources const& res,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @chatman, I'm working on cagra::merge. Could you review the API design when you have a moment? Any suggestions would be greatly appreciated. Thanks!

const cuvs::neighbors::cagra::merge_params& params,
std::vector<cuvs::neighbors::cagra::index<float, uint32_t>*>& indices)
-> cuvs::neighbors::cagra::index<float, uint32_t>;

/** @brief Merge multiple CAGRA indices into a single index.
*
* This function merges multiple CAGRA indices into one, combining both the datasets and graph
* structures.
*
* Usage example:
* @code{.cpp}
* using namespace raft::neighbors;
* auto dataset0 = raft::make_host_matrix<half, int64_t>(handle, size0, dim);
* auto dataset1 = raft::make_host_matrix<half, int64_t>(handle, size1, dim);
*
* auto index0 = cagra::build(res, index_params, dataset0);
* auto index1 = cagra::build(res, index_params, dataset1);
*
* std::vector<cagra::index<half, uint32_t>*> indices{&index0, &index1};
* cagra::merge_params params{index_params};
*
* auto merged_index = cagra::merge(res, params, indices);
* @endcode
*
* @param[in] res RAFT resources used for the merge operation.
* @param[in] params Parameters that control the merging process.
* @param[in] indices A vector of pointers to the CAGRA indices to merge. All indices must:
* - Have attached datasets with the same dimensionality.
*
* @return A new CAGRA index containing the merged indices, graph, and dataset.
*/
auto merge(raft::resources const& res,
const cuvs::neighbors::cagra::merge_params& params,
std::vector<cuvs::neighbors::cagra::index<half, uint32_t>*>& indices)
-> cuvs::neighbors::cagra::index<half, uint32_t>;

/** @brief Merge multiple CAGRA indices into a single index.
*
* This function merges multiple CAGRA indices into one, combining both the datasets and graph
* structures.
*
* Usage example:
* @code{.cpp}
* using namespace raft::neighbors;
* auto dataset0 = raft::make_host_matrix<int8_t, int64_t>(handle, size0, dim);
* auto dataset1 = raft::make_host_matrix<int8_t, int64_t>(handle, size1, dim);
*
* auto index0 = cagra::build(res, index_params, dataset0);
* auto index1 = cagra::build(res, index_params, dataset1);
*
* std::vector<cagra::index<int8_t, uint32_t>*> indices{&index0, &index1};
* cagra::merge_params params{index_params};
*
* auto merged_index = cagra::merge(res, params, indices);
* @endcode
*
* @param[in] res RAFT resources used for the merge operation.
* @param[in] params Parameters that control the merging process.
* @param[in] indices A vector of pointers to the CAGRA indices to merge. All indices must:
* - Have attached datasets with the same dimensionality.
*
* @return A new CAGRA index containing the merged indices, graph, and dataset.
*/
auto merge(raft::resources const& res,
const cuvs::neighbors::cagra::merge_params& params,
std::vector<cuvs::neighbors::cagra::index<int8_t, uint32_t>*>& indices)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do agree with Artem that the vector of points is not the prettiest thing, but I don't think variadic templates are the way to fix that (and they overall make things very challenging to work with). I think we can stick with pointers for now and udpate the API later if needed. Initially, this will be needed for Lucene, which will use it through our Java API so at least this public API is localized at the moment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pointers are fine, from the perspective of the Java API. We can work best with memory addresses, since we'll be mmapp'ing the index data from files on disk.

Copy link
Contributor

@chatman chatman Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vector<index> is fine from java's perspective.

-> cuvs::neighbors::cagra::index<int8_t, uint32_t>;

/** @brief Merge multiple CAGRA indices into a single index.
*
* This function merges multiple CAGRA indices into one, combining both the datasets and graph
* structures.
*
* Usage example:
* @code{.cpp}
* using namespace raft::neighbors;
* auto dataset0 = raft::make_host_matrix<uint8_t, int64_t>(handle, size0, dim);
* auto dataset1 = raft::make_host_matrix<uint8_t, int64_t>(handle, size1, dim);
*
* auto index0 = cagra::build(res, index_params, dataset0);
* auto index1 = cagra::build(res, index_params, dataset1);
*
* std::vector<cagra::index<uint8_t, uint32_t>*> indices{&index0, &index1};
* cagra::merge_params params{index_params};
*
* auto merged_index = cagra::merge(res, params, indices);
* @endcode
*
* @param[in] res RAFT resources used for the merge operation.
* @param[in] params Parameters that control the merging process.
* @param[in] indices A vector of pointers to the CAGRA indices to merge. All indices must:
* - Have attached datasets with the same dimensionality.
*
* @return A new CAGRA index containing the merged indices, graph, and dataset.
*/
auto merge(raft::resources const& res,
const cuvs::neighbors::cagra::merge_params& params,
std::vector<cuvs::neighbors::cagra::index<uint8_t, uint32_t>*>& indices)
-> cuvs::neighbors::cagra::index<uint8_t, uint32_t>;
/**
* @}
*/
Expand Down
9 changes: 9 additions & 0 deletions cpp/src/neighbors/cagra.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "detail/cagra/add_nodes.cuh"
#include "detail/cagra/cagra_build.cuh"
#include "detail/cagra/cagra_merge.cuh"
#include "detail/cagra/cagra_search.cuh"
#include "detail/cagra/graph_core.cuh"

Expand Down Expand Up @@ -369,6 +370,14 @@ void extend(
cagra::extend_core<T, IdxT, Accessor>(handle, additional_dataset, index, params, ndv, ngv);
}

template <class T, class IdxT>
index<T, IdxT> merge(raft::resources const& handle,
const cagra::merge_params& params,
std::vector<cuvs::neighbors::cagra::index<T, IdxT>*>& indices)
{
return cagra::detail::merge<T, IdxT>(handle, params, indices);
}

/** @} */ // end group cagra

} // namespace cuvs::neighbors::cagra
35 changes: 35 additions & 0 deletions cpp/src/neighbors/cagra_merge_float.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2025, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cagra.cuh"
#include <cuvs/neighbors/cagra.hpp>

namespace cuvs::neighbors::cagra {

#define RAFT_INST_CAGRA_MERGE(T, IdxT) \
auto merge(raft::resources const& handle, \
const cuvs::neighbors::cagra::merge_params& params, \
std::vector<cuvs::neighbors::cagra::index<T, IdxT>*>& indices) \
->cuvs::neighbors::cagra::index<T, IdxT> \
{ \
return cuvs::neighbors::cagra::merge<T, IdxT>(handle, params, indices); \
}

RAFT_INST_CAGRA_MERGE(float, uint32_t);

#undef RAFT_INST_CAGRA_MERGE

} // namespace cuvs::neighbors::cagra
35 changes: 35 additions & 0 deletions cpp/src/neighbors/cagra_merge_half.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2025, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cagra.cuh"
#include <cuvs/neighbors/cagra.hpp>

namespace cuvs::neighbors::cagra {

#define RAFT_INST_CAGRA_MERGE(T, IdxT) \
auto merge(raft::resources const& handle, \
const cuvs::neighbors::cagra::merge_params& params, \
std::vector<cuvs::neighbors::cagra::index<T, IdxT>*>& indices) \
->cuvs::neighbors::cagra::index<T, IdxT> \
{ \
return cuvs::neighbors::cagra::merge<T, IdxT>(handle, params, indices); \
}

RAFT_INST_CAGRA_MERGE(half, uint32_t);

#undef RAFT_INST_CAGRA_MERGE

} // namespace cuvs::neighbors::cagra
35 changes: 35 additions & 0 deletions cpp/src/neighbors/cagra_merge_int8.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2025, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cagra.cuh"
#include <cuvs/neighbors/cagra.hpp>

namespace cuvs::neighbors::cagra {

#define RAFT_INST_CAGRA_MERGE(T, IdxT) \
auto merge(raft::resources const& handle, \
const cuvs::neighbors::cagra::merge_params& params, \
std::vector<cuvs::neighbors::cagra::index<T, IdxT>*>& indices) \
->cuvs::neighbors::cagra::index<T, IdxT> \
{ \
return cuvs::neighbors::cagra::merge<T, IdxT>(handle, params, indices); \
}

RAFT_INST_CAGRA_MERGE(int8_t, uint32_t);

#undef RAFT_INST_CAGRA_MERGE

} // namespace cuvs::neighbors::cagra
35 changes: 35 additions & 0 deletions cpp/src/neighbors/cagra_merge_uint8.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2025, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cagra.cuh"
#include <cuvs/neighbors/cagra.hpp>

namespace cuvs::neighbors::cagra {

#define RAFT_INST_CAGRA_MERGE(T, IdxT) \
auto merge(raft::resources const& handle, \
const cuvs::neighbors::cagra::merge_params& params, \
std::vector<cuvs::neighbors::cagra::index<T, IdxT>*>& indices) \
->cuvs::neighbors::cagra::index<T, IdxT> \
{ \
return cuvs::neighbors::cagra::merge<T, IdxT>(handle, params, indices); \
}

RAFT_INST_CAGRA_MERGE(uint8_t, uint32_t);

#undef RAFT_INST_CAGRA_MERGE

} // namespace cuvs::neighbors::cagra
Loading
Loading