Skip to content

feat: add diskann index#369

Open
richyreachy wants to merge 91 commits into
alibaba:mainfrom
richyreachy:feat/diskann_index
Open

feat: add diskann index#369
richyreachy wants to merge 91 commits into
alibaba:mainfrom
richyreachy:feat/diskann_index

Conversation

@richyreachy
Copy link
Copy Markdown
Collaborator

Add diskann index into Zvec to lower memory usage in vector search as per the description: #325

Comment thread src/db/index/common/doc.cc
-Wl,--whole-archive
$<TARGET_FILE:core_knn_flat_static>
$<TARGET_FILE:core_knn_flat_sparse_static>
$<TARGET_FILE:core_knn_hnsw_static>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

代码有重复,可以调整一下

run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libaio-dev
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

如果用户的环境没有装libaio-dev,会发生什么?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

现在默认使用是需要安装libaio,可以通过配置的方式进行区分,千问的建议是通过linux安装包的方式安装libaio库:

Installation

zvec requires the libaio system library on linux platform.

On Ubuntu/Debian:

sudo apt-get install libaio1 libaio-dev
pip install zvec

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

如果没有安装,会发生什么?这里预期的行为应该是 如果用户不安装aio,不影响除diskann的其他功能使用

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

在新的PR里做了调整:#378

Comment thread .github/workflows/03-macos-linux-build.yml
}

auto &pool = ctx->expanded_nodes();
for (uint32_t i = 0; i < pool.size(); i++) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

可以使用std::remove_if + erase,效率高一些

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done


virtual ~DiskAnnQueryParams() = default;

int list_size() const {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

加上参数的注释吧

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/core/algorithm/diskann/diskann_builder.cc
Comment thread src/core/algorithm/diskann/diskann_builder.cc Outdated

sector_internal_id_++;
if (sector_internal_id_ >= sector_vec_num_) {
std::vector<uint8_t> padding_(padding_size_, 0);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

没有必要allocate一个临时的std::vector?

std::memset(data_ptr + data_size_, 0, padding_size_);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/core/algorithm/diskann/diskann_indexer.h Outdated
Comment thread src/core/algorithm/diskann/CMakeLists.txt Outdated
Comment thread src/include/zvec/db/query_params.h
"proxima.stratified.trainer.cluster_params_in_level_";

static const std::string MULTI_CHUNK_CLUSTER_COUNT =
"proxima.cluster.multi_chunk_cluster.count";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

新代码要切换到zvec.xxx吗?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

等一起统一调整,这个其它索引里还没有改掉


//! Init
int init() {
// file_.open(path, std::ios::in | std::ios::out);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

清理下注释掉的代码吧

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

typedef std::shared_ptr<MultiChunkClusterAlgorithm> Pointer;

//! Constructor
MultiChunkClusterAlgorithm(void) {}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

使用default,{}会影响编译器优化,析构函数类似

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

"ValueType must be arithmetic");

//! Constructor
MultiChunkNumericalAlgorithm(void) {}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

同上

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done


bool result = algorithm.cluster_once(*local_threads, &cost);
if (result != true) {
LOG_ERROR("(%u) Failed to cluster.", i + 1);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

%u打印会有编译warning,建议%zu (size_t)xxx打印

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

(*finished)++;
}

return;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

函数尾部的return可以去掉

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

int cleanup(void);

//! Reset Cluster
int reset(void);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

void可以去掉,c++里面reset()即可

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

}
}

(*out)[id * chunk_count_ + chunk] = static_cast<uint32_t>(sel_index);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

不用cast,sel_index本身是uint32的

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

entity_.set_neighbors(id, pruned_list);
lock_pool_[lock_idx].unlock();

ret = inter_insert(id, pruned_list, ctx);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

return inter_insert...否则会丢失错误

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

return core::IndexError_Unsupported;
}

param_ = dynamic_cast<const DiskAnnIndexParam &>(param);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

重复cast

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/include/zvec/db/index_params.h Outdated
return pq_chunk_num_;
}

void pq_chunk_num(int pq_chunk_num) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

其他的都带set,这个也加上吧

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

20
)pbdoc");
diskann_params
.def(py::init<int>(), py::arg("list_size") = 10, R"pbdoc(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

c++默认为300,注释也写默认300,这里是10

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Default is ``MetricType.IP`` (inner product).
max_degree (int):.
list_size (int): .
pq_chunk_num (bool): .
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

pq_chunk_num (bool): —— 类型是 int,不是 bool。
示例里 >>> print(params.n_list) / >>> print(params.nprobe) 引用的属性 DiskAnn 类上根本不存在

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/core/algorithm/diskann/diskann_searcher.h
Comment thread src/core/algorithm/diskann/CMakeLists.txt
Comment thread src/core/algorithm/diskann/diskann_builder.cc Outdated
uint64_t n_retries = 0) {
#if (defined(__linux) || defined(__linux__))
uint64_t iters =
DiskAnnUtil::round_up(read_reqs.size(), MAX_EVENTS) / MAX_EVENTS;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

用div_round_up,省一次除

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

break;
}
}
n_tries++;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

retry不起作用,错误路径都返回或者break了

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done


if (ret != (int)n_ops) {
LOG_WARN(
"io_submit failed; returned: %d, expected=%lu, errno=%d, %s, "
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

libaio不会设置errno,直接打印ret吧

Image

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

Comment thread src/core/algorithm/CMakeLists.txt Outdated
)
if(MSVC)
# MSVC: STATIC-only stub to avoid creating an empty DLL with no exports
cc_library(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这里是有什么问题?之前ci也能跑?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

调整和主干一致了

// every other index type stays fully functional.
int EnsureDiskAnnRuntimeReady() {
const int status = ::zvec::LoadDiskAnnPlugin();
if (status == ::zvec::kDiskAnnPluginOk) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

zvec前面的::可以去掉?应该不太会冲突

src/binding/python/binding.cc
35:      [](const std::string &path) { return ::zvec::LoadDiskAnnPlugin(path); },
40:  m.def("is_diskann_plugin_loaded", &::zvec::IsDiskAnnPluginLoaded,
42:  m.def("is_libaio_available", &::zvec::IsLibAioAvailable,
48:  m.attr("DISKANN_PLUGIN_OK") = static_cast<int>(::zvec::kDiskAnnPluginOk);
50:      static_cast<int>(::zvec::kDiskAnnPluginUnsupportedPlatform);
52:      static_cast<int>(::zvec::kDiskAnnPluginLibAioMissing);
54:      static_cast<int>(::zvec::kDiskAnnPluginDlopenFailed);

src/core/plugin/diskann_plugin.cc
88:  if (::dladdr(reinterpret_cast<void *>(&::zvec::LoadDiskAnnPlugin), &info) ==
105:  if (::dladdr(reinterpret_cast<void *>(&::zvec::LoadDiskAnnPlugin), &info) ==

src/core/interface/indexes/diskann_index.cc
34:  const int status = ::zvec::LoadDiskAnnPlugin();
35:  if (status == ::zvec::kDiskAnnPluginOk) {
39:    case ::zvec::kDiskAnnPluginLibAioMissing:
46:    case ::zvec::kDiskAnnPluginUnsupportedPlatform:
51:    case ::zvec::kDiskAnnPluginDlopenFailed:

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

LOG_ERROR("Failed to open streamer, path: %s", file_path_.c_str());
return core::IndexError_Runtime;
}
is_trained_ = true;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

设置is_trained_后面add直接报错,这里创建streamer的作用是什么?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

这个streamer是提供readonly查询的,不提供add能力,和ivf保持一致

auto holder =
std::make_shared<zvec::core::MultiPassIndexHolder<DataType::DT_FP16>>(
param_.dimension);
for (auto doc : doc_cache_) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ivf_index.cc也有类似实现,抽个公共实现吧

input_vector_meta_.dimension() * input_vector_meta_.unit_size());

std::lock_guard<std::mutex> lock(mutex_);
while (doc_cache_.size() <= doc_id) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

已经上锁了,可以直接

if (size() <= doc_id) {
    doc_cache_.resize(doc+1, {kInvalidKey, fake_data});
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

auto dumper = core::IndexFactory::CreateDumper("FileDumper");

dumper->create(file_path_);
builder_->dump(dumper);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

需要检查错误?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done


int flush(void) override {
return IndexError_NotImplemented;
return 0;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

只读的场景什么时候需要flush?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

fixed

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

这里因为index调用到了flush,所以还是做了0值返回,保证接口的一致。

// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef ZVEC_PLUGIN_DISKANN_PLUGIN_H
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

用#pragma once吧

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

# --------------------------------------------------------------------------- #
# Plugin gating.
# --------------------------------------------------------------------------- #
_PLUGIN_LOAD_STATUS = zvec.load_diskann_plugin()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

这里最好不要让用户手动调用一次吧,import zvec内可以自动调用load_diskann_plugin

Copy link
Copy Markdown
Collaborator Author

@richyreachy richyreachy May 29, 2026

Choose a reason for hiding this comment

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

这个load_diskann_plugin不是必须调用,可以注释掉,或者去掉,会做隐式加载。如果没有load成功,会报错。

... ...
def main() -> int:
# ---- 1. Load the DiskAnn plugin. -------------------------------------- #
#status = zvec.load_diskann_plugin()
#if status != 0:
# print(
# f"[error] DiskAnn plugin failed to load (status={status}). "
# "Make sure libzvec_diskann_plugin.so sits next to _zvec.so.",
# file=sys.stderr,
# )
# return 1
#print("[ok] DiskAnn plugin loaded.")

# ---- 2. Prepare a throwaway workspace and the collection. ------------- #
... 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants