CombinationSearchMatcher
Pure, UI-free matcher for the combination / cross-reference search feature.
A query may combine a CONTAINER token-group (a building — or, at a higher layer, a category) with one or more CONTAINED-ENTITY tokens. This class answers the sdk-core half of the problem:
tokenize a raw query (lowercase, NFKD diacritic-strip, split on whitespace/punctuation) into Tokens, classifying each as numeric or text.
scoreContainer a candidate container token-group against a building's CMS NAME WORDS, returning the best of four GENERIC tiers (plus exact) — derived from the name at call time.
partition a tokenized query against a building-name map into token-order-independent {container tokens} + {remaining entity tokens} candidates, one per matching building.
GENERIC, NO maintained list. The biz/bizz -> Business case is reached by the phonetic-PREFIX tier (Metaphone.isPrefixCode) — there is deliberately NO {biz,bizz}->business dictionary in this class. The only explicit-alias path in the product is the existing CMS keyword mechanism (folded into a SearchEntity's keywords), which is a data entry, not code here.
The entity-scoping leg (matching the remaining tokens to entities in the matched building, on name AND short-name) is performed by the UI layer using the existing SearchFilterHelpers.filterSearchableByMatchType / SearchFilterHelpers.filterSearchableByMatchTypeOnMetadata ordering; this class only decides WHICH building(s) are containers and WHICH tokens remain for that entity leg.
Types
One container/entity partition: a building whose name matched containerTokens, with the remaining entityTokens to be scoped to that building's entities by the UI leg.
Result of scoring a container token-group against a building's name words.
Container match tiers, highest tier-weight first.
One engaged candidate from match: its key, the normalized container score, the residual entityTokens to scope to it in the UI leg, and the coverage (fraction of the candidate's name words the container tokens consumed) used as the secondary sort key.
Properties
Threshold for the consolidated match entry point: a token whose best tier score is at or above this counts as a container token for that candidate. Equals the lowest fuzzy tier score (PHONETIC_PREFIX), so any tier firing engages.
Minimum Jaro for the bounded-JARO tier. Rejects biznes(0.686)/biz(0.639)/bizz(0.583).
Functions
Engagement guard: the combination leg may only run when the query has at least two tokens AND at least one of them is a container candidate (a text token). A lone token, or a query of purely numeric tokens, never engages — those fall through to plain unified search.
Derives the GENERIC name-words for a candidate set: a (lowercased) name-word that is SHARED by at least two candidates AND appears in MORE THAN HALF of the candidate names is generic (e.g. "center"/"centre" = 5/5 across the VERIFIED M-University buildings). A name-word's contribution is counted ONCE per candidate (presence, not multiplicity), so a word repeated within one name does not inflate its share.
THE single consolidated entry point both lanes agree on. Tokenizes query, computes the genericWords across candidates, scores each candidate by best-tier-per-token with the length floors AND the DISTINCTIVE-ANCHOR requirement, partitions the tokens into container vs entity, and returns the engaged Matches ordered by score DESC then coverage DESC.
Partitions a tokenized query into combination candidates against buildingNameWords (buildingId -> lowercased CMS name words). For each building that is a container match, the tokens consumed by the container group are removed and the REMAINING text/numeric tokens become that match's CombinationMatch.entityTokens.
Scores a candidate container token-group containerTokens (already lowercased) against a building's nameWords (the CMS long name — and any folded short-name words — split into lowercased words). Returns the best ContainerMatch, or null if the group does not clear any tier.
Tokenizes query: lowercases, strips diacritics (NFKD), and splits on any run of whitespace or punctuation. Empty tokens are dropped. Result preserves left-to-right order for stability, but downstream partitioning is token-order independent.