Wizhut Research · Evaluation

Kyori

Ordering an autocomplete list with nothing but the strings

Every autocomplete box does two jobs. It filters the catalogue down to what begins with the typed text, and then it orders what is left — the job people notice, because the right suggestion either comes first or it does not. Kyori, our open-source JavaScript string library, carries a ranking cost built for that second job: four ordered rules and a tie-break, with no popularity data, no model and no index. This page is where Kyori 0.5.0 stands: how well it orders real searches, measured against the libraries applications already use.

Open source, MITKyori 0.5.0 on npmReport of 26 September 2026
0.404
mean reciprocal rank, held out

On 11,607 AmazonQAC prefixes the design never saw. Level with Fuse.js, fuzzysort and sorting by length: no gap between them survives a significance test.

+0.036
from one tie-break

Among equal costs, the shorter completion first. It cuts tied cases from 85% to 47%, and the gain holds on the split it was not chosen from.

+0.018
is what popularity adds

Ordering by how often people search for a completion beats every string method. It is the one signal that separates candidates of equal length.

120 µs
per query, at the median

Among the slower keys measured. Three quarters of it goes on normalising the same strings again, not on the rules.

Kyori 0.5.0

Four rules, tried in order, and a tie-break.

The cost compares what was typed with one candidate: 0 is a perfect match, lower is better, and the first rule that applies decides. There are no weights, nothing learned and no frequency data, so the same pair costs the same everywhere. Each rule has a precedent in error-tolerant search; what is Kyori’s own is the arrangement, the constants and the last rule’s formula.

  • R1
    Identical
    returns 0

    Equal as typed, or equal once both strings are folded: accents stripped, lowercase, dashes read as spaces.

  • R2
    Same words, another order
    returns 1

    The same words as a bag, reordered: "hotel bel-air" against "bel-air hotel".

  • R3
    A typed prefix
    returns its edits

    The fewest edits between what was typed and any start of the candidate, first letter fixed; the unread rest is free. No typo below three typed characters, one for 3–5, two for 6–8.

  • R4
    Everything else
    returns a sum

    The length difference, plus how far each typed word lands from where it was typed, its length again if it only matches mid-word, and its typo distance to the nearest word when it is missing.

  • Tie
    Shorter first
    orders equal costs

    rank() sorts by the cost, then by the candidate's length, then alphabetically; rankKey() is that order as one number.

The library’s similarity() is a different function on purpose: the share of words two strings have in common. It never looks at characters, and it is not meant as a ranking key — the results below say why.

The evaluation · 11,607 held-out prefixes

Level with the best libraries, below popularity.

The data is AmazonQAC, the query-autocomplete dataset Amazon published at EMNLP 2024: real prefixes people typed into a search box, each with the search it ended in. Each candidate list is exactly what a typo-tolerant prefix filter returns from the catalogue, and ties are reported rather than broken by the alphabet. Kyori was designed on the test split, so the figures that count come from a sample of the train split drawn afterwards and never consulted — and every comparison is tested case by case, corrected across all 19.

Mean reciprocal rank is 1 when the answer comes first, ½ when it comes second, and so on, averaged over every case. The band is how far a tie policy alone could move each score: a narrow band means the method decided the order itself. Every figure was measured on the code released as Kyori 0.5.0.

MethodTest splitHeld outBandTiedIn top 10
Most popular completion
Prefix matches, most searched first
—0.4220.413–0.44818%0.638
Kyori 0.5.0
The cost, then shorter first
0.4090.4040.393–0.41647%0.616
ORDER BY length
The zero-library rule
0.4080.4030.385–0.44150%0.615
fuzzysort 4
Subsequence match
0.4090.4030.390–0.42147%0.617
Fuse.js 7
Bitap match, weighted by length
0.4080.4020.355–0.49966%0.612
match-sorter 8
Match tiers
0.3890.3760.276–0.94282%0.582
Kyori, cost alone
No tie-break
0.3810.3680.257–0.98885%0.577
Character trigrams
Trigram cosine
0.3690.3650.364–0.41115%0.591
Jaro–Winkler
Name-matching similarity
0.3570.3530.343–0.36548%0.594
Kyori similarity as a key
Word overlap
0.2790.2710.210–0.70682%0.460
Damerau–Levenshtein
Edit distance
0.2670.2570.245–0.27264%0.459

Expected values under a random order inside ties. Most-popular-completion needs Amazon’s search counts, which only the train split carries, so it has no test-split score. “In top 10” is the share of cases where the answer is among the first ten suggestions.

+0.001

Kyori over sorting by length, the same on both splits and significant on neither once corrected (p = 0.21 and 0.24). Level, not ahead.

+0.028

Kyori over match-sorter, whose tiers leave 82% of cases tied. A real gap: p < 0.01 after correction.

+0.133

The cost over the library’s own similarity used as a key — the case for keeping ranking and resemblance as separate functions.

By list size

Where the tie-break helps, and where popularity does.

The same held-out cases, split by how many candidates the filter returned. Ordering nine completions of a long prefix and ordering a thousand completions of one letter are different jobs, and the three rankers below tell them apart.

Kyori, cost alone Kyori 0.5.0 Most popular completion
2–9
3,172 cases
10–49
2,259 cases
50–199
2,428 cases
200–999
2,869 cases
1000+
879 cases
Mean reciprocal rank by the number of candidates the filter returned. The tie-break helps at every size. Popularity is level on short lists and pulls ahead from ten candidates up. Past a thousand — one or two typed letters — every method is below 0.04: that regime needs more than a string or a count.
Show the numbers
CandidatesCasesKyori, cost aloneKyori 0.5.0Most popular completion
2–93,1720.7590.7870.787
10–492,2590.4540.4990.519
50–1992,4280.2020.2480.273
200–9992,8690.1150.1510.185
1000+8790.0140.0320.036

Where Kyori stands

As good as the libraries in use, not better.

The question was whether a cost assembled from known parts could order a filtered list better than what applications already use. It orders it as well, not better — and the evaluation shows where the order of such a list actually comes from.

The order comes from a length prior

The four string methods at the top share one idea. Sorting by length has nothing else, Fuse.js weighs field length, fuzzysort subtracts the candidate's length from its score, and Kyori breaks its ties that way. Once a list already starts with what was typed, "shorter first" is most of what a string can say.

Popularity is the signal strings lack

Most-popular-completion leads by 0.018 (interval 0.013–0.022) and is the only method that separates candidates of equal length. It is level with Kyori on lists of 2–9 and ahead from ten candidates up — and still below 0.04 past a thousand.

Other jobs have other leaders

As a measure of resemblance, Kyori's word-overlap similarity trails the methods that weigh rare words up: character trigrams lead it by 0.172 on Abt–Buy's product titles. On 400 real misspellings the cost trails Jaro–Winkler by 0.058 and is level with Damerau–Levenshtein. Its strength is the typed prefix and the reordered phrase, not spelling correction.

The time goes on folding, not rules

Every method is interactive on autocomplete lists, and 95% of Kyori's queries finish within 2 ms. A profile puts 76% of the ranking key's time into normalising strings — both are folded again on every comparison — while the rules themselves are cheap.

What this evidence does not cover

One catalogue: US product searches on Amazon from September and October 2023. The catalogue is built from the evaluated searches themselves, so every answer is in it; a real catalogue is larger and sometimes lacks the answer. Amazon’s counts bound that from below — 1.8% of held-out answers were searched only once that month, and scoring them as misses costs every method about 0.008. The filter admits a typo in only 8% of cases, so typo handling is lightly exercised. There is no session or user signal, the timings come from one machine, and the misspellings are set against random words rather than near ones. Read the direction of the results and the tested gaps, not the third decimal.

Open source

It is on npm, and it is free.

Kyori is MIT-licensed: five string metrics behind one API, the ranking cost measured on this page and a ready-made autocomplete index, in plain JavaScript with no heavyweight dependencies. Version 0.5.0 is the code every figure here was measured on.