This is an automated email from the ASF dual-hosted git repository.
JingsongLi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/paimon-rust.git
The following commit(s) were added to refs/heads/main by this push:
new 10bf6c5f fix(c): align append vector filter with core behavior (#793)
10bf6c5f is described below
commit 10bf6c5fe29d9b4bb74cdb6b6d1acdf94911261c
Author: QuakeWang <[email protected]>
AuthorDate: Fri Sep 11 14:21:13 2026 +0800
fix(c): align append vector filter with core behavior (#793)
---
bindings/c/src/tests.rs | 54 ++++++++++++++++++++++++++---------------
bindings/c/src/vector_search.rs | 5 +++-
2 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/bindings/c/src/tests.rs b/bindings/c/src/tests.rs
index 31b62de2..6cf7bdb4 100644
--- a/bindings/c/src/tests.rs
+++ b/bindings/c/src/tests.rs
@@ -3263,32 +3263,48 @@ fn vector_search_pk_filter_excludes_neighbor() {
}
#[test]
-fn vector_search_append_filter_returns_invalid_input() {
- let path = "memory:/vsearch_append_filter_err";
+fn vector_search_append_filter_matches_rust() {
+ let path = "memory:/vsearch_append_filter_read";
let table = build_append_vector_table(path);
+ let query = [1.0f32, 0.0];
+ let limit = 3;
+
+ let unfiltered = rust_execute_read_pairs(&table, "embedding",
query.to_vec(), limit, None);
+ assert!(
+ unfiltered.iter().any(|(id, _)| *id == 0),
+ "fixture must include the filtered nearest neighbor in the unfiltered
Top-K"
+ );
+
+ let rust_filter = PredicateBuilder::new(table.schema().fields())
+ .greater_or_equal("id", Datum::Int(1))
+ .unwrap();
+ let rust_pairs = rust_execute_read_pairs(
+ &table,
+ "embedding",
+ query.to_vec(),
+ limit,
+ Some(rust_filter),
+ );
+ assert_eq!(
+ rust_pairs.len(),
+ limit,
+ "filter-before-Top-K must refill the result after excluding id 0"
+ );
+ assert!(
+ rust_pairs.iter().all(|(id, _)| *id >= 1),
+ "Rust core returned a row excluded by the filter"
+ );
+
let handle = unsafe { wrap_table(table) };
unsafe {
let predicate = build_predicate_ge(handle, "id", 1);
- let builder = c_vector_builder(handle, "embedding", &[1.0f32, 0.0], 3,
predicate);
- let result = paimon_vector_search_builder_execute_read(builder);
- paimon_vector_search_builder_free(builder);
+ let builder = c_vector_builder(handle, "embedding", &query, limit,
predicate);
+ let c_pairs = c_execute_read_pairs(builder);
- assert!(
- result.reader.is_null(),
- "errored read must not yield a reader"
- );
- assert!(!result.error.is_null(), "DE filter must fail loud");
assert_eq!(
- (*result.error).code,
- PaimonErrorCode::InvalidInput as i32,
- "DE filter error must map to InvalidInput"
- );
- let message = error_message(result.error);
- assert!(
- message.contains("primary-key vector path"),
- "unexpected error message: {message}"
+ c_pairs, rust_pairs,
+ "filtered C pairs must match the Rust core reference"
);
- paimon_error_free(result.error);
unwrap_table(handle);
}
}
diff --git a/bindings/c/src/vector_search.rs b/bindings/c/src/vector_search.rs
index 80d79efe..f63e152d 100644
--- a/bindings/c/src/vector_search.rs
+++ b/bindings/c/src/vector_search.rs
@@ -185,7 +185,10 @@ pub unsafe extern "C" fn
paimon_vector_search_builder_with_options(
std::ptr::null_mut()
}
-/// Set an optional scalar residual filter for a vector-search builder.
+/// Set an optional scalar predicate applied before vector Top-K.
+///
+/// The Rust core resolves the predicate to an allow-list for the selected
+/// primary-key or data-evolution/global-index search path.
///
/// The predicate is consumed (ownership transferred to the builder). Pass null
/// to clear any previously set filter.