Skip to content

2.3.0

Latest

Choose a tag to compare

@rhukster rhukster released this 13 Feb 18:03
· 3 commits to main since this release
29af602

Security Fixes

  • Cache table identifier hardening: Added strict validation for cache table names in QueryCache (/^[a-zA-Z_][a-zA-Z0-9_]{0,63}$/) before SQL interpolation. Invalid names now throw CacheException.

Performance Improvements

  • searchMultiple() merge efficiency: Removed repeated array_merge copying in result aggregation and eliminated duplicate indexExists() checks by tracking validated indices in one pass.
  • Levenshtein prefilter optimization: In SearchEngine::generateLevenshteinVariations(), query-term bigrams are now computed once per query term instead of once per indexed-term candidate.
  • Suggestion query roundtrip reduction: Added per-call memoization for count() checks in generateSuggestion() and generateSuggestions() to avoid repeated database checks for identical candidate queries.
  • Field-weight candidate pool tuning: Reduced default overfetch for field-weight scoring and made candidate sizing configurable:
    • field_weight_candidate_multiplier (default 20)
    • field_weight_candidate_min (default 200)
    • field_weight_candidate_max (default 2000)
    • field_weight_candidate_cap (optional per-query/config cap)

Internationalization

  • UTF-8-safe hot paths: Switched key text-processing paths to UTF-8-safe handling:
    • Snippet extraction in SearchEngine::extractSnippet()
    • Suggest title normalization/matching in SearchEngine::suggest()
    • Tokenization/term-position extraction in SqliteStorage
    • Field-weighted phrase/term matching in SqliteStorage::calculateFieldWeightedScore()

Bug Fixes

  • Filter operator correctness in storage queries: Fixed inconsistent operator handling between direct columns and JSON fields in SqliteStorage::buildFilterClause() / buildJsonFilterClause(). Added proper support for between and is not null semantics, and corrected in/not in empty-array behavior to avoid invalid SQL or silent filter bypass.
  • Multi-index ranking in searchMultiple(): Fixed merged result ordering to sort by actual score output (with fallback keys), instead of relying on missing rank/_score keys that could produce non-relevance ordering.
  • Cache wiring and bypass propagation: Top-level cache config is now passed into storage connection config, and bypass_cache set on SearchQuery options is now propagated from SearchEngine to storage queries.

Tests

  • Added integration coverage for metadata and direct-column filter operators:
    • between and is not null regression assertions in tests/Integration/Storage/MetadataFilterTest.php
  • Added multi-index ranking regression test:
    • test_search_multiple_indices_sorts_by_score in tests/Integration/Storage/SearchMultipleTest.php
  • Added query cache integration coverage:
    • tests/Integration/Storage/QueryCacheIntegrationTest.php verifies top-level cache config wiring and bypass_cache behavior
  • Added tests/Integration/Storage/FieldWeightCandidateLimitTest.php for default and explicit candidate cap behavior.
  • Added tests/Integration/Search/Utf8HighlightTest.php for UTF-8 highlight/snippet behavior.
  • Extended tests/Integration/Storage/QueryCacheIntegrationTest.php with invalid cache table name rejection coverage.