use crate::load_hnsw;
use ahash::HashMap;
use clap::Args;
use itertools::Itertools;
use libcorenn::cfg::Cfg;
use libcorenn::metric::StdMetric;
use libcorenn::store::schema::DbNodeData;
use libcorenn::store::schema::ID_TO_KEY;
use libcorenn::store::schema::KEY_TO_ID;
use libcorenn::store::schema::NODE;
use libcorenn::CoreNN;
use std::path::PathBuf;
use std::sync::Arc;
#[derive(Args)]
pub struct MigrateHnswArgs {
#[arg()]
path: PathBuf,
#[arg(long)]
out: PathBuf,
#[arg(long)]
dim: usize,
#[arg(long)]
metric: StdMetric,
}
impl MigrateHnswArgs {
pub async fn exec(self: MigrateHnswArgs) {
let index = load_hnsw(self.dim, &self.path);
let cfg = Cfg {
dim: self.dim,
max_add_edges: index.m,
max_edges: index.m,
metric: self.metric,
query_search_list_cap: index.ef,
update_search_list_cap: index.ef_construction,
..Default::default()
};
let corenn = CoreNN::create(self.out, cfg);
let db = corenn.internal_db();
tracing::info!("created database");
let hnsw_label_to_corenn_id = index
.labels()
.enumerate()
.map(|(id, l)| (l, id + 1))
.collect::<HashMap<_, _>>();
let mut vectors = index
.labels()
.map(|hnsw_label| {
(
hnsw_label_to_corenn_id[&hnsw_label],
index.get_data_by_label(hnsw_label).to_vec(),
)
})
.collect::<HashMap<_, _>>();
let mut graph = index
.labels()
.map(|label| {
let neighbors = index
.get_merged_neighbors(label, 0)
.into_iter()
.map(|hnsw_label| hnsw_label_to_corenn_id[&hnsw_label])
.collect_vec();
let corenn_id = hnsw_label_to_corenn_id[&label];
(corenn_id, neighbors)
})
.collect::<HashMap<_, _>>();
{
let entry_label = index.entry_label();
let entry_id = hnsw_label_to_corenn_id[&entry_label];
NODE.put(db, 0, DbNodeData {
version: 0,
neighbors: graph[&entry_id].clone(),
vector: Arc::new(vectors[&entry_id].clone().into()),
});
};
for (label, id) in hnsw_label_to_corenn_id {
let key = label.to_string();
KEY_TO_ID.put(db, &key, id);
ID_TO_KEY.put(db, id, &key);
NODE.put(db, id, DbNodeData {
version: 0,
neighbors: graph.remove(&id).unwrap(),
vector: Arc::new(vectors.remove(&id).unwrap().into()),
});
}
drop(corenn);
tracing::info!("all done!");
}
}