Skip to content

perf: Optimize oneOf validation and add schema/validator caching#1197

Merged
nathan-stender merged 1 commit into
mainfrom
perf/optimize-oneof-validation-and-caching
Apr 30, 2026
Merged

perf: Optimize oneOf validation and add schema/validator caching#1197
nathan-stender merged 1 commit into
mainfrom
perf/optimize-oneof-validation-and-caching

Conversation

@nathan-stender

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #1196 targeting the remaining validation bottlenecks, identified via cProfile on a 135MB Biacore T200 .bme file (917 measurements, 35M data points).

  • Fast oneOf for typed arraystDimensionArray and tMeasureArray are oneOf over 3 typed array refs (number/boolean/string). The default oneOf validator validates against the first matching branch, then re-validates against ALL remaining branches to confirm uniqueness. We short-circuit by inspecting the first element's type to select the correct branch directly. (~6s saved)
  • Fast oneOf for array-vs-objectoneOf[tDimensionArray, tFunction] patterns: if the instance is a list, it must be the array branch (tFunction is an object). Skip the redundant validation. (917 calls saved)
  • Schema + validator caching — Cache schema JSON, RefResolver, and FastDraft202012Validator instances per schema path to avoid redundant disk I/O and object construction on repeated validations. (~1.7s saved on first call)
  • Eliminate redundant fields() callunstructure() called fields() twice per dataclass (once for iteration, once to build a set for custom_information_document check). Reuse the tuple.

Benchmark (135MB .bme file)

Phase Before #1196 After #1196 After this PR
unstructure 13s 0.2s 0.2s
validate 147s 12.8s 5.0s
Total ~176s ~38s ~25s

Test plan

  • Full test suite passes (1,119 tests)
  • Lint + mypy clean
  • Verified oneOf fast validator correctly handles: number/string/boolean arrays, nullable arrays, mixed-type rejection, non-array oneOf fallback, array-vs-object disambiguation
  • Benchmarked end-to-end against 135MB .bme file

🤖 Generated with Claude Code

Follow-up to #1196 targeting the remaining validation bottlenecks for
large data cube files (profiled on a 135MB Biacore T200 .bme file with
35M float values across 917 measurements).

1. Fast oneOf for typed arrays (tDimensionArray/tMeasureArray): the
   default oneOf validator checks all branches then re-validates to
   confirm uniqueness. We short-circuit by inspecting the first
   element's type to pick the correct branch directly.

2. Fast oneOf for array-vs-object (tDimensionArray | tFunction): if the
   instance is a list it must be the array branch, skip the object check.

3. Cache schema JSON, RefResolver, and validator instances per schema
   path to avoid redundant disk I/O and object construction.

4. Eliminate redundant fields() call in unstructure — reuse the tuple
   from the iteration loop.

Validation time: 12.8s → 5.0s. Total pipeline: ~38s → ~25s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nathan-stender
nathan-stender requested a review from a team as a code owner April 30, 2026 14:41
@nathan-stender
nathan-stender merged commit 61dcc1d into main Apr 30, 2026
9 checks passed
@nathan-stender
nathan-stender deleted the perf/optimize-oneof-validation-and-caching branch April 30, 2026 16:00
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.

2 participants