(
&self,
collection: &str,
field_name: &str,
query: &[f32],
k: usize,
filter: Option<&MetadataFilter>,
)
| 96 | } |
| 97 | |
| 98 | pub(super) async fn vector_search_field_impl( |
| 99 | &self, |
| 100 | collection: &str, |
| 101 | field_name: &str, |
| 102 | query: &[f32], |
| 103 | k: usize, |
| 104 | filter: Option<&MetadataFilter>, |
| 105 | ) -> NodeDbResult<Vec<SearchResult>> { |
| 106 | // Field-aware path: use the 2-arg form of `vector_distance` so |
| 107 | // the planner scopes the HNSW lookup to the named column. The |
| 108 | // single-arg form `vector_distance(ARRAY[...])` only works on |
| 109 | // collections that have exactly one vector column. |
| 110 | let coll = quote_identifier(collection); |
| 111 | let field = quote_identifier(field_name); |
| 112 | let vec_lit = format_vector_array(query); |
| 113 | let where_clause = match filter { |
| 114 | Some(f) => { |
| 115 | let rendered = render_metadata_filter_public(f)?; |
| 116 | format!(" WHERE {rendered}") |
| 117 | } |
| 118 | None => String::new(), |
| 119 | }; |
| 120 | let sql = format!( |
| 121 | "SELECT id, vector_distance({field}, {vec_lit}) AS distance \ |
| 122 | FROM {coll}{where_clause} \ |
| 123 | ORDER BY vector_distance({field}, {vec_lit}) \ |
| 124 | LIMIT {k}" |
| 125 | ); |
| 126 | |
| 127 | let (columns, rows) = self.query_raw(&sql, &[]).await?; |
| 128 | let id_idx = columns.iter().position(|c| c == "id").unwrap_or(0); |
| 129 | let dist_idx = columns.iter().position(|c| c == "distance").unwrap_or(1); |
| 130 | |
| 131 | let mut results = Vec::with_capacity(rows.len()); |
| 132 | for row in &rows { |
| 133 | let id = row |
| 134 | .get(id_idx) |
| 135 | .and_then(|v| v.as_str()) |
| 136 | .unwrap_or("") |
| 137 | .to_string(); |
| 138 | let distance = row.get(dist_idx).and_then(|v| v.as_f64()).unwrap_or(0.0) as f32; |
| 139 | results.push(SearchResult { |
| 140 | id, |
| 141 | node_id: None, |
| 142 | distance, |
| 143 | metadata: HashMap::new(), |
| 144 | }); |
| 145 | } |
| 146 | Ok(results) |
| 147 | } |
| 148 | |
| 149 | pub(super) async fn vector_insert_impl( |
| 150 | &self, |
no test coverage detected