mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-08-13 18:44:52 -07:00
13 KiB
13 KiB
Changelog
v0.4.0 - 2026-03-22
Breaking Changes
Rust & JavaScript
- Word indexing now stores all prefixes of each word and compound, increasing memory usage proportionally to total word character count — previously only full words and full compounds were indexed (Rust source, JS source)
New Features
Rust & JavaScript
- Added prefix indexing: every prefix of each word is now stored in the word index (e.g., "dominance" registers "d", "do", "dom", ..., "dominance"), so short queries like "dom" directly match items containing "dominance" without relying on trigram fallback (Rust source, JS source)
- Added prefix indexing for compound words: adjacent word pairs index all prefixes starting from the second word's first character (e.g., "hash" + "rate" indexes "hashr", "hashra", ..., "hashrate"), enabling partial compound matching
- Changed
prefix_scorefrom exact word matching to prefix matching (starts_within Rust, length comparison in JS), so query word "pric" is recognized as a prefix of item word "price" and scored accordingly (Rust source, JS source) - Added union fallback: when word intersection yields no common items and trigram matching produces no results, the algorithm falls back to union of all known word sets, returning partial matches instead of empty results (Rust source, JS source)
- Changed search flow to try trigram matching first when unknown words exist; if trigram results are found they're returned immediately, otherwise falls back to ranking known-word candidates (intersection or union)
Examples
- Added
examples/compare.rswith 80+ test queries covering exact matches, compound words, typos, short prefixes, acronyms, reverse word order, and unknown terms against a metrics dataset (source)
Internal Changes
Rust
- Extracted ranking logic into a standalone
fn rank()method that takes an iterator of(*const str, usize)candidates and produces bucket-sorted results (source) - Added
intersect_sets()method that returnsOption<FxHashSet>(returningNoneinstead of empty set to distinguish "no known words" from "empty intersection") - Added
union_sets()method that merges multipleFxHashSetreferences into a single set - Changed query word deduplication from a separate
FxHashSetto inlineseen.insert()filtering during collection, then dropping the set immediately - Used lifetime elision (
QuickMatch<'_>) inSendandSynctrait implementations - Removed doc comments from
prefix_scorefree function
JavaScript
- Replaced flat sorting by
(prefixScore, trigramScore, length)with a 3-bucket ranking approach: items are bucketed by prefix score (0, 1, 2), each bucket is independently sorted by(score, length), and results are filled from the highest bucket first until the limit is reached (source) - Added
union()helper function that merges multiple index arrays into a deduplicated result using aSet - Changed
intersect()to returnnullinstead of an empty array when intersection is empty, distinguishing "no results" from "no input" - Added duplicate prevention in
addToIndex(): checksarr[arr.length - 1] !== valuebefore pushing, preventing duplicate entries from prefix indexing - Removed standalone
indexTrigrams()function; trigram indexing is now inlined in the constructor alongside prefix indexing - Condensed JSDoc class-level documentation to include behavioral descriptions (e.g., "Supports exact words, prefixes, joined words, and typo tolerance")
v0.3.2 - 2026-03-21
Breaking Changes
Rust & JavaScript
- Default separators changed from
['_', '-', ' ']to['_', '-', ' ', ':', '/'], meaning colon-separated and path-like strings are now split into words by default (Rust source, JS source)
New Features
Rust & JavaScript
- Added compound word indexing: adjacent words in items are indexed as concatenated pairs (e.g., "hash" + "rate" → "hashrate"), so queries like
hashratenow match items likehash_ratewithout relying on trigram fallback (Rust source, JS source) - Added prefix-based result ranking via a new
prefix_scorefunction that scores items as exact match (2), prefix match (1), or no match (0) — results are now sorted by prefix score first, then trigram score, then length, producing significantly more relevant ordering for autocomplete (Rust source, JS source) - Added
with_min_score(n)(Rust) /withMinScore(n)(JS) configuration option to set the minimum trigram score required for fuzzy matches — higher values require more trigram overlap, reducing noise in results (default: 2) (Rust source, JS source)
Documentation
- Added
docs/README.mdwith comprehensive usage examples for both Rust and JavaScript, a "How it works" section explaining the 3-stage matching pipeline (word → compound → trigram), a configuration options table, and performance benchmarks (~26μs/query Rust, ~29μs/query JS) (source)
Examples
- Added
examples/colon_test.rsandexamples/colon_test.mjsdemonstrating separator behavior with colon-containing items and queries under both default and custom separator configurations (Rust source, JS source)
CI
- Added
.github/workflows/outdated.ymlworkflow that runs daily (and on manual trigger) to detect outdated Rust dependencies usingcargo-outdated(source)
Bug Fixes
Rust
- Fixed
max_word_lencalculation that was incorrectly using the full item length instead of individual word length, which could cause valid long words to be rejected from queries (source) - Fixed query normalization ordering so that emptiness and length checks now happen after trimming whitespace and lowercasing, correctly rejecting whitespace-only or non-ASCII-only queries (source)
Internal Changes
Rust
- Changed
query_wordscollection fromFxHashSettoVecto preserve word ordering, which is required for the new prefix scoring algorithm (source) - Removed doc comments from
matches()andmatches_with()public methods
JavaScript
- Replaced string-based separator checking (
separators.includes()) with aUint8Array(128)lookup table for O(1) separator detection instead of O(n) string scanning (source) - Replaced
Map<number, number>score tracking with a pre-allocatedUint32Array(items.length)and a dirty index list, eliminating Map allocation overhead during each search (source) - Merged
sortedByLength()andrankedResults()into a single_rank()method that handles both exact-match and fuzzy-match result paths - Renamed internal functions for brevity:
normalizeQuery→normalize,parseWords→splitWords,addTrigramsToIndex→indexTrigrams,intersectAll→intersect,binarySearch→bsearch,pickTrigramPosition→trigramPosition,scoreByTrigrams→_scoreTrigrams - Condensed JSDoc annotations to single-line
@paramformat
Workspace
- Reorganized project files: moved
LICENSEtodocs/LICENSE.md, setCargo.tomlreadme field todocs/README.md - Added
*metrics*pattern to.gitignore - Added
examplestojsconfig.jsonexclude list
v0.3.1 - 2026-01-22
New Features
JavaScript
- Added comprehensive JSDoc type annotations for
QuickMatchConfigclass properties (separators,limit,trigramBudget) and all public methods (withLimit(),withTrigramBudget(),withSeparators(),matches(),matchesWith()) (source) - Added
@privateannotations for internal methods (scoreByTrigrams(),sortedByLength(),rankedResults()) to indicate non-public API - Added explicit type annotations to Map types:
Map<string, number[]>forwordIndexandtrigramIndex - Added
jsconfig.jsonwith TypeScript-style type checking enabled (checkJs: true,strict: true) for improved IDE support and static analysis (source)
Internal Changes
JavaScript
- Renamed
trigramCountvariable tohitCountfor consistency with Rust implementation - Normalized string quotes to double quotes throughout the codebase
- Reformatted multi-line function parameters for readability
v0.3.0 - 2026-01-22
New Features
JavaScript
- Added complete JavaScript port of the library with identical API to Rust, published as
quickmatch-jsnpm package (source) - Implemented
QuickMatchclass with word indexing and trigram-based fuzzy matching - Implemented
QuickMatchConfigclass with builder methods (withLimit(),withTrigramBudget(),withSeparators()) - Implemented
matches()andmatchesWith()methods returning results sorted by relevance - Uses ES modules (
"type": "module") for modern JavaScript compatibility
Documentation
- Added JavaScript installation instructions to README (
npm install quickmatch-js)
Internal Changes
Rust
- Renamed
trigram_counttohit_countto clarify it tracks successful trigram matches rather than total attempts (source) - Changed trigram budget tracking from increment-based (
trigram_count += 1) to decrement-based (budget -= 1) for clearer remaining budget visibility - Simplified trigram processing loop by removing
processed_trigramsflag and using direct budget check (if budget == 0) for early termination
v0.2.0 - 2026-01-14
New Features
Rust
- Initial release of
quickmatch- a fuzzy string matching library for autocomplete and search-as-you-type interfaces - Added
QuickMatchstruct implementing hybrid matching with word-level indexing and trigram-based fuzzy fallback (source) - Added
QuickMatchConfigfor customizing match behavior with builder pattern methods (source):with_limit(n)- Set maximum results (default: 100)with_trigram_budget(n)- Set fuzzy matching depth (default: 6, range: 0-20)with_separators(chars)- Set word separator characters (default:_,-,)
- Added
new()constructor for default configuration andnew_with()for custom configuration - Added
matches()andmatches_with()methods returning results ranked by match quality and length - Implemented thread-safe design with
SendandSynctraits for concurrent usage - Added zero-copy string storage using pointer-based indexing for memory efficiency
- Implemented smart trigram selection algorithm that samples trigrams at strategic positions (first, last, middle, then alternating) for efficient fuzzy matching
- Added interactive autocomplete example demonstrating product search functionality (source)