Action 1/3

Designing a Unified Vector Space (v1)

To find products similar to the one a user clicked, I designed a hybrid embedding structure that unifies 4 product attributes — product name, category/brand, price, and size — into a single 484-dimensional vector. Product name, which carries the largest share, is converted into a 256-dimensional vector using a RoBERTa-based encoder pretrained directly on Bungaejangter product text. I'll cover why we chose a custom pretrained text encoder, and the training details, on the next page (v2).

Encoding Composition

We concatenated 4 embeddings built from product attributes, in order, into a 484-dimensional embedding.

AttributeDimsEncoding method
Product name256Custom pretrained text encoder
Category/brand pair100Collaborative-filtering embedding from user-item interaction
Price64Sinusoidal positional encoding
Size64Sinusoidal positional encoding

1. Category/Brand Pair Embedding — Capturing Domain Signal

We collected the category/brand embedding by applying a collaborative-filtering algorithm to user-item interaction data. Specifically, we substituted each item in the interaction data with its (category, brand) pair, then trained the collaborative-filtering algorithm to map user embeddings and pair embeddings into the same space. Brand was nullable when forming a pair, since we separately trained a category-only embedding to use as a fallback for products without a brand — keeping the embedding as populated as possible. After training, we discarded the user embeddings and kept only the (category, brand) pair embeddings. At inference time, we used the pair embedding if the product had a brand, and the category-only embedding otherwise.

We modeled at the (category, brand) pair level because similarity between the same brand can vary by category. For example, it's natural for 'Gucci' to sit close to 'Balenciaga' in the sneakers category, but closer to 'Louis Vuitton' in the bags category. Since Bungaejangter sees far more interaction data in the sneakers category, training the two embeddings independently would have biased the result toward the category with more data — failing to capture this category-specific nuance.

2. Price/Size Embedding — Deterministic Encoding, No Training

Price and size are ordinal attributes, so instead of a learned embedding, we represented them deterministically using the positional encoding described in the attention paper. We assigned each attribute value a unique index and implemented the paper's formula to map it to a vector. This let us vectorize both attributes while preserving their ordinal information, with no training cost and no data dependency.

Increasing the vector dimension strengthens the property that similarity decreases monotonically with index distance, but it also increases compute and storage cost. So we fixed the dimension at 64 and tuned the period parameters of the sine and cosine functions to shape a similarity distribution appropriate to each attribute's domain characteristics.

  • Price: similarity to nearby price points should decay gently → set high
  • Size: only adjacent sizes should stay strongly similar, decaying quickly → set low
Neighbor similarity for the price embedding
Neighbor similarity for the price embedding (brighter = higher)
Neighbor similarity for the size embedding
Neighbor similarity for the size embedding (brighter = higher)

3. Differentiating Embedding Weights

flowchart LR
    A[Product] --> B1[Product name]
    A --> B2[Category · brand]
    A --> B3[Price]
    A --> B4[Size]

    B1 --> C1[Custom pretrained<br/>text encoder]
    B2 --> C2[Collaborative filtering<br/>embedding]
    B3 --> C3[Sinusoidal PE]
    B4 --> C4[Sinusoidal PE]

    C1 --> D1["256 dims<br/>× w1"]
    C2 --> D2["100 dims<br/>× w2"]
    C3 --> D3["64 dims<br/>× w3"]
    C4 --> D4["64 dims<br/>× w4"]

    D1 --> E
    D2 --> E
    D3 --> E
    D4 --> E

    E["484-dim unified vector<br/>(concatenated in order)"]
          

Normalizing and concatenating the vectors for these 4 attributes lets the dot product between two product vectors express their similarity. Rather than concatenating the 4 attributes as-is, we applied weights based on domain intuition. For example, two products with the exact same price don't feel similar if their categories differ — but two products with a slightly different price can still feel similar if their category matches.

  • "$30 jacket vs. $30 jeans" — feels like different products
  • "$25 jeans vs. $30 jeans" — feels reasonably similar (i.e. price is a lower-weight signal)

To reflect these differences in how much each attribute drives similarity, we assigned a per-feature weight to each of the 4 normalized embeddings. Guided by domain intuition, we set the weight ordering as category/brand (w2) > product name (w1) > price (w3) > size (w4), and represented every recommendable product as a 484-dimensional vector: each of the 4 attribute vectors normalized, multiplied by its weight, and concatenated.