Skip to content

feat: enable SearchV PREFILTER support in HQL#899

Open
aiSynergy37 wants to merge 2 commits into
HelixDB:mainfrom
aiSynergy37:fix/searchv-prefilter-834
Open

feat: enable SearchV PREFILTER support in HQL#899
aiSynergy37 wants to merge 2 commits into
HelixDB:mainfrom
aiSynergy37:fix/searchv-prefilter-834

Conversation

@aiSynergy37
Copy link
Copy Markdown

@aiSynergy37 aiSynergy37 commented Apr 9, 2026

Summary

  • enable parser grammar for SearchV<...>(..., k)::PREFILTER(...)
  • wire prefilter generation into root SearchV analysis path (start-node and expression forms)
  • align generated prefilter closure binding to val so generated predicates compile against &HVector
  • guard graph-step ::SearchV from silently dropping prefilters by surfacing an analyzer error
  • add parser/analyzer tests covering PREFILTER parsing, valid simple predicates, and invalid non-boolean traversal usage

Notes

  • this implementation intentionally supports simple property predicates (for example: _::{category}::EQ("tech")) for prefilter closures

Validation

  • unable to run cargo test in this environment because cargo is not installed

Closes #834

Greptile Summary

This PR enables SearchV<T>(..., k)::PREFILTER(...) in HQL by uncommenting the grammar rule, wiring build_search_vector_pre_filter into the root SearchV analysis path, aligning the generated closure binding to val, and blocking PREFILTER on graph-step SearchV with an E601 diagnostic. Support is intentionally scoped to simple property predicates (_::{field}::BoolOp(value)).

Important Files Changed

Filename Overview
helix-db/src/grammar.pest Uncomments the optional ("::" ~ pre_filter)? suffix on search_vector, enabling PREFILTER syntax in HQL.
helix-db/src/helixc/analyzer/methods/infer_expr_type.rs Adds build_search_vector_pre_filter and validator helpers; test fixtures use [F64] with an [F32] schema and compound And/Or prefilter paths are untested.
helix-db/src/helixc/analyzer/methods/traversal_validation.rs Wires build_search_vector_pre_filter into the root SearchV analysis path, replacing the previously dead let pre_filter = None.
helix-db/src/helixc/analyzer/methods/graph_step_validation.rs Guards graph-step SearchV from silently dropping prefilters by emitting E601 when sv.pre_filter is set.
helix-db/src/helixc/generator/source_steps.rs Changes closure binding from v to val so generated predicates compile against the val identifier emitted by the traversal renderer; doc comment is now stale.
helix-db/src/helixc/parser/expression_parse_methods.rs Adds a parser-level test confirming that SearchV<T>(..., k)::PREFILTER(...) round-trips through HelixParser::parse_source without error.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["HQL: SearchV<T>(vec, k)::PREFILTER(expr)"] --> B{Root or graph-step?}
    B -->|Root StartNode| C["traversal_validation.rs\nbuild_search_vector_pre_filter()"]
    B -->|Graph step| D["graph_step_validation.rs\nEmit E601 error"]
    C --> E["infer_expr_type()\nparent_ty = Type::Vector(T)"]
    E --> F{stmt result}
    F -->|Traversal| G["BoExp::Expr(tr)"]
    F -->|BoExp| H["BoExp directly"]
    F -->|Other / None| I["Emit E306 / E601\nreturn None"]
    G --> J["is_supported_search_vector_prefilter_expr()"]
    H --> J
    J -->|Valid: PropertyFetch + BoolOp| K["Some(vec![pre_filter])"]
    J -->|Invalid: Exists / Empty / wrong steps| L["Emit E601\nreturn None"]
    K --> M["SearchVector { pre_filter: Some(...) }\nsource_steps.rs Display:\n|val: &HVector, txn: &RoTxn| ..."]
    L --> N["SearchVector { pre_filter: None }"]
Loading

Reviews (1): Last reviewed commit: "fix(hql): silence unused txn in generate..." | Re-trigger Greptile

@aiSynergy37
Copy link
Copy Markdown
Author

@xav-db linking this here for visibility: this PR implements issue #834 (SearchV PREFILTER support) with parser + analyzer/codegen wiring and tests.

pre_filter
.iter()
.map(|f| format!("|v: &HVector, txn: &RoTxn| {f}"))
.map(|f| format!("|val: &HVector, txn: &RoTxn| {f}"))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 txn will always be unused in valid prefilter closures

The closure parameter txn: &RoTxn is declared but is never referenced in the generated body for valid prefilter expressions. The validator in is_supported_search_vector_prefilter_traversal restricts accepted traversals to exactly two steps (PropertyFetch + BoolOp), and bool_ops.rs renders those as val.get_property(...).map_or(false, |v| ...) — a path that only touches val. Any traversal needing txn (i.e., the multi-step G::from_iter(&db, &txn, ...) path) is already rejected by the validator. This will emit an unused-variable warning on every compiled prefilter closure; use _txn to suppress it.

Suggested change
.map(|f| format!("|val: &HVector, txn: &RoTxn| {f}"))
.map(|f| format!("|val: &HVector, _txn: &RoTxn| {f}"))

@aiSynergy37
Copy link
Copy Markdown
Author

Addressed the unused xn warning in generated prefilter closures by renaming it to _txn in codegen.\n\nFix commit: 6d56b81

@aiSynergy37
Copy link
Copy Markdown
Author

Opened a separate CI-fix PR for the cli_tests.yml parser failure noise: #900

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add prefilter support to SearchV for filtered vector search

2 participants