Skip to content

Instantly share code, notes, and snippets.

@NZhuravlev
Last active May 15, 2026 13:20
Show Gist options
  • Select an option

  • Save NZhuravlev/1e547df5a4c485dfde4aaf63958dd273 to your computer and use it in GitHub Desktop.

Select an option

Save NZhuravlev/1e547df5a4c485dfde4aaf63958dd273 to your computer and use it in GitHub Desktop.

Taxonomy Redirect Resolution — How It Works

When taxonomy dimensions are retired (e.g., a motor type is split into two, a trim is reclassified), users searching for old cat values get redirected to the current ones.

Concepts

  • Category (cat): a combination of dimensions like ma13gr100037mt1314 (make=BMW, modelGroup=1 Series, motorType=M135)
  • Rule: maps a retired dimension value to its replacement(s). Example: motor type "M135" (id 1314) → "1er M" (id 903)
  • Patch: what a rule produces — the new dimension values to apply

How it works

  1. Parse the input cat parameter
  2. Find rules that match (all "from" dimensions present in the input)
  3. Remove retired dimensions from the input → base
  4. Sort patches (size ascending, then dimension priority sum descending) and apply them one by one:
    • If the patch introduces NEW dimensions → merge into existing results
    • If ALL patch dimensions ALREADY EXIST → split (create additional cat with those dims replaced)
    • If SOME patch dimensions exist and some don't → drop + log warning (partial overlap edge case)

Examples

1. Simple rename

A motor type was renamed.

Rule: motorType 1314 (M135) → motorType 903 (1er M)

Input:  ma13gr100037mt1314
        BMW, 1 Series, M135

Base:   ma13gr100037  (remove retired: mt1314)
Patch:  mt903

Apply mt903 → no motorType in base → merge
Result: ma13gr100037mt903
        BMW, 1 Series, 1er M

2. Simple rename (two rules, no splits)

A motor type was renamed AND a trim was renamed (independently).

Rules:

  • trim 1 → motorType 2
  • motorType 3 → trim 4
Input:  tr1mt3

Base:   (empty — both dims retired)
Patches (size 1): mt2 (priority=2), tr4 (priority=1)
Sorted: mt2, tr4

Apply mt2 → no motorType → merge → [mt2]
Apply tr4 → no trim → merge → [mt2tr4]

Result: mt2tr4

3. Dimension shift (trim splits into motor + trim)

A trim "6.2L AMG" was reclassified: "6.2L" is actually the motor type, "AMG" is the trim.

Rule: trim 16420 (6.2L AMG) → motorType 12610 (6.2L) + trim 479759 (AMG)

Input:  ma47gr100056tr16420
        Mercedes C-Class, trim "6.2L AMG"

Base:   ma47gr100056  (remove retired: tr16420)
Patch:  mt12610tr479759

Apply mt12610tr479759 → no motorType or trim in base → merge
Result: ma47gr100056mt12610tr479759
        Mercedes C-Class, motor "6.2L", trim "AMG"

4. Same-dimension conflict → split

Two independent rules both produce the same dimension.

Rules:

  • trim 1 → variant 3
  • motorType 2 → variant 4
Input:  tr1mt2

Base:   (empty)
Patches (size 1): va3 (priority=3), va4 (priority=3)
Same dims → order doesn't matter

Apply va3 → no variant → merge → [va3]
Apply va4 → has variant → split → [va3, va4]

Result: va3, va4

5. One dimension splits into two values

A generation "F20" was split into "F20 Pre-facelift" and "F20 LCI".

Rules:

  • generation 1 (F20) → generation 2 (F20 Pre-facelift)
  • generation 1 (F20) → generation 3 (F20 LCI)
Input:  ma13gr100037ge1
        BMW, 1 Series, F20

Base:   ma13gr100037  (remove retired: ge1)
Patches: ge2 (priority=4), ge3 (priority=4)

Apply ge2 → no generation in base → merge → [ma13gr100037ge2]
Apply ge3 → has generation → split → [ma13gr100037ge2, ma13gr100037ge3]

Result: ma13gr100037ge2, ma13gr100037ge3
        BMW 1 Series F20 Pre-facelift, BMW 1 Series F20 LCI

6. Two independent splits → cartesian product

Generation "F20" split into 2, AND motor "M135i" split into 2 variants.

Rules:

  • generation 1 → generation 2 (F20 Pre-facelift)
  • generation 1 → generation 3 (F20 LCI)
  • motorType 4 → motorType 5 (M135i xDrive)
  • motorType 4 → motorType 6 (M135i sDrive)
Input:  ma13gr100037ge1mt4
        BMW, 1 Series, F20, M135i

Base:   ma13gr100037  (remove retired: ge1, mt4)
Patches (all size 1): ge2(sum=4), ge3(sum=4), mt5(sum=2), mt6(sum=2)
Sorted desc by sum: ge2, ge3, mt5, mt6

Apply ge2 → merge          → [ma13gr100037ge2]
Apply ge3 → split (has ge)  → [ma13gr100037ge2, ma13gr100037ge3]
Apply mt5 → merge (no mt)   → [ma13gr100037ge2mt5, ma13gr100037ge3mt5]
Apply mt6 → split (has mt)  → [ma13gr100037ge2mt5, ma13gr100037ge2mt6,
                                 ma13gr100037ge3mt5, ma13gr100037ge3mt6]

Result: 4 cats — all combinations of the two splits

7. Paired multi-dimension split

Model group "Prius Prime" is retired. Different trims map to different outputs, but variant+trim stay paired.

Rules:

  • variant 1 → variant 2, trim 3
  • variant 1 → variant 7, trim 6
Input:  ma1gr2va1
Base:   ma1gr2  (remove retired: va1)
Patches (both size 2): va2tr3 (sum=3+1=4), va7tr6 (sum=3+1=4)
Same dims → order doesn't matter

Apply va2tr3 → no variant or trim → merge → [ma1gr2va2tr3]
Apply va7tr6 → has variant AND trim → split → [ma1gr2va2tr3, ma1gr2va7tr6]

Result: ma1gr2va2tr3, ma1gr2va7tr6
        (values stay paired — NOT a cartesian product)

8. Variant deletion

A variant was retired with no replacement — users should see the broader model group.

Rule: variant 3314 (911 Carrera T Cabriolet) → (nothing)

Input:  ma65gr75292va3314
        Porsche, 911, 911 Carrera T Cabriolet

Base:   ma65gr75292  (remove retired: va3314)
Patch:  (empty — no "to" dimensions)

Nothing to apply.
Result: ma65gr75292
        Porsche, 911

9. Combined: rename + split on same input

An input has a generation split (1→2), a motor rename (1→1), and a variant+trim rename (1→1).

Rules:

  • trim 1 → motorType 2
  • generation 8 → generation 9
  • generation 8 → generation 10
  • variant 3 → variant 4, trim 5
Input:  ma6gr7tr1va3ge8

Base:   ma6gr7  (remove retired: tr1, va3, ge8)
Patches sorted by size ASC, then priority sum DESC:
  ge9       (size 1, priority=4)
  ge10      (size 1, priority=4)
  mt2       (size 1, priority=2)
  va4tr5    (size 2, priority=4)

Apply ge9    → merge          → [ma6gr7ge9]
Apply ge10   → split (has ge)  → [ma6gr7ge9, ma6gr7ge10]
Apply mt2    → merge (no mt)   → [ma6gr7ge9mt2, ma6gr7ge10mt2]
Apply va4tr5 → merge (no va/tr) → [ma6gr7ge9mt2va4tr5, ma6gr7ge10mt2va4tr5]

Result: ma6gr7ge9mt2va4tr5, ma6gr7ge10mt2va4tr5

10. Partial overlap → drop + warn

Two rules produce patches that partially overlap in dimensions. This is an edge case that shouldn't happen in well-defined rules, but is handled gracefully.

Rules:

  • variant 1 → variant 2, trim 3
  • motorType 4 → motorType 5, trim 6
Input:  va1mt4
Base:   (empty — both dims retired)
Patches (size 2): va2tr3 (sum=3+1=4), mt5tr6 (sum=2+1=3)
Sorted desc by sum: va2tr3, mt5tr6

Apply va2tr3 → no variant, no trim → merge → [va2tr3]
Apply mt5tr6 → has trim? YES, has motorType? NO → PARTIAL OVERLAP → drop + warn

Result: va2tr3 (with warning logged about mt5tr6 being dropped)

This case indicates the rules may need manual review — two independent changes both setting "trim" creates ambiguity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment