From 2af9dec9cc8802462103813c57c37bf73cab5c60 Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Wed, 26 Aug 2026 18:35:36 +0000 Subject: [PATCH] feat(vectordata): add the canonical facet-name alias table Ports the StandardFacet canonical/alias table: base_vectors and kin are the dataset.yaml keys, with base, train, query, gt, ground_truth, the metadata shorthands, and the prefiltered/postfiltered families accepted as aliases. The test pins the whole table so drift from the reference is a deliberate change, not an accident. --- .../io/nosqlbench/vectordata/FacetNames.java | 57 ++++++++++++++++++ .../nosqlbench/vectordata/FacetNamesTest.java | 60 +++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 nb-vectordata/src/main/java/io/nosqlbench/vectordata/FacetNames.java create mode 100644 nb-vectordata/src/test/java/io/nosqlbench/vectordata/FacetNamesTest.java diff --git a/nb-vectordata/src/main/java/io/nosqlbench/vectordata/FacetNames.java b/nb-vectordata/src/main/java/io/nosqlbench/vectordata/FacetNames.java new file mode 100644 index 000000000..0d33772fe --- /dev/null +++ b/nb-vectordata/src/main/java/io/nosqlbench/vectordata/FacetNames.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2026 The NoSQLBench Authors. + * + * 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. + */ +package io.nosqlbench.vectordata; + +/// Canonical facet names and their accepted shorthand aliases, ported +/// from the `vectordata-rs` `StandardFacet` table. The canonical key is +/// what `dataset.yaml` profile definitions use (`base_vectors`, +/// `query_vectors`, `neighbor_indices`, ...); the aliases are the +/// shorter names YAML authors and legacy `knn_entries` catalogs use +/// (`base`, `query`, `gt`, ...). Every facet lookup and every manifest +/// key resolves through this one table, so a dataset published with +/// canonical keys and one published with aliases read identically. +public final class FacetNames { + private FacetNames() { } + + /// Resolves a facet name to its canonical key. Canonical keys and + /// unrecognized (custom-facet) names pass through unchanged. + public static String canonical(String name) { + return switch (name) { + case "base", "train" -> "base_vectors"; + case "query", "queries", "test" -> "query_vectors"; + case "indices", "neighbors", "ground_truth", "gt" -> "neighbor_indices"; + case "distances" -> "neighbor_distances"; + case "content", "meta_content", "meta_base" -> "metadata_content"; + case "meta_predicates" -> "metadata_predicates"; + case "meta_results", "predicate_results", "metadata_indices" -> "metadata_results"; + case "layout", "meta_layout" -> "metadata_layout"; + case "prefiltered_indices", "prefiltered_gt", "prefiltered_ground_truth", "prefilter_indices", + "filtered_neighbor_indices", "filtered_indices", "filtered_gt", "filtered_ground_truth" -> + "prefiltered_neighbor_indices"; + case "prefiltered_distances", "prefilter_distances", "prefiltered_neighbors", + "filtered_neighbor_distances", "filtered_distances", "filtered_neighbors" -> + "prefiltered_neighbor_distances"; + case "postfiltered_indices", "postfiltered_gt", "postfiltered_ground_truth", "postfilter_indices" -> + "postfiltered_neighbor_indices"; + case "postfiltered_distances", "postfilter_distances", "postfiltered_neighbors" -> + "postfiltered_neighbor_distances"; + // Retained pre-table Java aliasing, documented in + // RUST_COMPATIBILITY.md before the full table was ported. + case "filtered" -> "prefiltered"; + default -> name; + }; + } +} diff --git a/nb-vectordata/src/test/java/io/nosqlbench/vectordata/FacetNamesTest.java b/nb-vectordata/src/test/java/io/nosqlbench/vectordata/FacetNamesTest.java new file mode 100644 index 000000000..38994dc35 --- /dev/null +++ b/nb-vectordata/src/test/java/io/nosqlbench/vectordata/FacetNamesTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026 The NoSQLBench Authors. + * + * 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. + */ +package io.nosqlbench.vectordata; + +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +/// Pins the complete `StandardFacet` canonical/alias table from +/// `vectordata-rs` so any drift between the reference implementation +/// and this port is a deliberate change, not an accident. +@Tag("unit") +class FacetNamesTest { + @Test void everyRustAliasResolvesToItsCanonicalKey() { + Map> table = Map.ofEntries( + Map.entry("base_vectors", List.of("base", "train")), + Map.entry("query_vectors", List.of("query", "queries", "test")), + Map.entry("neighbor_indices", List.of("indices", "neighbors", "ground_truth", "gt")), + Map.entry("neighbor_distances", List.of("distances")), + Map.entry("metadata_content", List.of("content", "meta_content", "meta_base")), + Map.entry("metadata_predicates", List.of("meta_predicates")), + Map.entry("metadata_results", List.of("meta_results", "predicate_results", "metadata_indices")), + Map.entry("metadata_layout", List.of("layout", "meta_layout")), + Map.entry("prefiltered_neighbor_indices", List.of( + "prefiltered_indices", "prefiltered_gt", "prefiltered_ground_truth", "prefilter_indices", + "filtered_neighbor_indices", "filtered_indices", "filtered_gt", "filtered_ground_truth")), + Map.entry("prefiltered_neighbor_distances", List.of( + "prefiltered_distances", "prefilter_distances", "prefiltered_neighbors", + "filtered_neighbor_distances", "filtered_distances", "filtered_neighbors")), + Map.entry("postfiltered_neighbor_indices", List.of( + "postfiltered_indices", "postfiltered_gt", "postfiltered_ground_truth", "postfilter_indices")), + Map.entry("postfiltered_neighbor_distances", List.of( + "postfiltered_distances", "postfilter_distances", "postfiltered_neighbors"))); + table.forEach((canonical, aliases) -> { + assertEquals(canonical, FacetNames.canonical(canonical), "canonical keys pass through"); + for (String alias : aliases) assertEquals(canonical, FacetNames.canonical(alias), alias); + }); + } + + @Test void customFacetNamesPassThroughUnchanged() { + assertEquals("custom_scores", FacetNames.canonical("custom_scores")); + } +}