fix hnsw panic

main
Ziyang Hu 1 year ago
parent 72c77fe9d4
commit d8e6ee5887

@ -10,7 +10,7 @@ use std::collections::BTreeMap;
use std::sync::Arc; use std::sync::Arc;
use itertools::Itertools; use itertools::Itertools;
use miette::{ensure, miette, Diagnostic, Result}; use miette::{ensure, miette, Diagnostic, Result, bail};
use smartstring::{LazyCompact, SmartString}; use smartstring::{LazyCompact, SmartString};
use thiserror::Error; use thiserror::Error;
@ -254,6 +254,12 @@ pub(crate) fn parse_sys(
_ => return Err(miette!("Invalid option: {}", opt_name.as_str())), _ => return Err(miette!("Invalid option: {}", opt_name.as_str())),
} }
} }
if ef_construction == 0 {
bail!("ef_construction must be set");
}
if max_elements == 0 {
bail!("m_neighbours must be set");
}
SysOp::CreateVectorIndex(HnswIndexConfig { SysOp::CreateVectorIndex(HnswIndexConfig {
base_relation: SmartString::from(rel.as_str()), base_relation: SmartString::from(rel.as_str()),
index_name: SmartString::from(name.as_str()), index_name: SmartString::from(name.as_str()),

@ -178,7 +178,7 @@ impl<'a> SessionTx<'a> {
self, self,
&[], &[],
&[DataValue::from(i64::MIN)], &[DataValue::from(i64::MIN)],
&[DataValue::from(1)], &[DataValue::from(0)],
) )
.next(); .next();
if let Some(ep) = ep_res { if let Some(ep) = ep_res {
@ -802,6 +802,8 @@ impl<'a> SessionTx<'a> {
.collect_vec(); .collect_vec();
encountered_singletons |= neigbours.is_empty(); encountered_singletons |= neigbours.is_empty();
for (neighbour_key, neighbour_idx, neighbour_subidx, _) in neigbours { for (neighbour_key, neighbour_idx, neighbour_subidx, _) in neigbours {
// REMARK: this still has some probability of disconnecting the graph.
// Should we accept that as a consequence of the probabilistic nature of the algorithm?
let mut out_key = vec![DataValue::from(layer)]; let mut out_key = vec![DataValue::from(layer)];
out_key.extend_from_slice(tuple_key); out_key.extend_from_slice(tuple_key);
out_key.push(DataValue::from(idx as i64)); out_key.push(DataValue::from(idx as i64));

@ -737,7 +737,7 @@ impl<'a> SessionTx<'a> {
for prefix in ["fr", "to"] { for prefix in ["fr", "to"] {
for col in rel_handle.metadata.keys.iter() { for col in rel_handle.metadata.keys.iter() {
let mut col = col.clone(); let mut col = col.clone();
col.name = SmartString::from(format!("{}_{}", prefix, config.index_name)); col.name = SmartString::from(format!("{}_{}", prefix, col.name));
idx_keys.push(col); idx_keys.push(col);
} }
idx_keys.push(ColumnDef { idx_keys.push(ColumnDef {

@ -849,3 +849,37 @@ fn test_vec_index() {
println!("{} {} {}", row[0], row[1], row[2]); println!("{} {} {}", row[0], row[1], row[2]);
} }
} }
#[test]
fn test_insertions() {
let db = DbInstance::new("mem", "", "").unwrap();
db.run_script(
r":create a {k => v: <F32; 100> default rand_vec(100)}",
Default::default(),
)
.unwrap();
db.run_script(r"?[k] <- [[1]] :put a {k}", Default::default())
.unwrap();
db.run_script(r"?[k, v] := *a{k, v}", Default::default())
.unwrap();
db.run_script(
r"::hnsw create a:i {fields: [v], dim: 100, ef: 200, m: 50}",
Default::default(),
)
.unwrap();
db.run_script(r"?[count(fr_k)] := *a:i{fr_k}", Default::default())
.unwrap();
db.run_script(r"?[k] <- [[1]] :put a {k}", Default::default())
.unwrap();
db.run_script(r"?[k] := k in int_range(1000) :put a {k}", Default::default()).unwrap();
let res = db
.run_script(
r"?[dist, k] := ~a:i{k | query: v, bind_distance: dist, k:10, ef: 200}, *a{k: 333, v}",
Default::default(),
)
.unwrap();
println!("results");
for row in res.into_json()["rows"].as_array().unwrap() {
println!("{} {}", row[0], row[1]);
}
}

Loading…
Cancel
Save