accesspatterns.dev
← All models

commerce

Catalogue Semantic Search

A vector index and a GSI on one table, answering different questions.

These are complements, not competitors. 'Something warm for winter camping' is a similarity question and only the vector index can answer it. 'Everything under fifty pounds, cheapest first' is a key condition, and the GSI answers it exactly, completely, in order, and for a fraction of the cost. Most features need both, and the tell is whether you could write the question down as a rule.

The model

Product

One product, searchable by meaning and queryable by price.

pk
CATEGORY#<category>
sk
PRODUCT#<productId>

Attributes: category (S), price (N), inStock (S), name (S), embedding (L)

Access patterns

  • SearchVectors · by-catalogueSomething like this, in stock

    A similarity question, narrowed to what you can actually sell.

  • Query · GSI1Everything in a price band

    A key condition, answered exactly and in order by the GSI.

Design notes

Top-K is a ceiling, not a page sizecost

TopK caps at 100 and there is no LastEvaluatedKey behind it. Filter a Query's results in your application and you can always go back for more rows; filter a search's results and you are spending from a fixed budget with no way to top it up. Anything expressible as a key condition belongs in one.

inStock is a string because the index requires itmodelling

A SearchSchema attribute must appear in AttributeDefinitions, and DynamoDB attribute definitions only accept S, N or B. A BOOL cannot be an inline filter, so the flag is stored as 'yes' and 'no'. This is the sort of constraint that only surfaces at CreateTable.

Exact where AWS is approximateoperations

The engine here compares against every entry and returns the true nearest. AWS builds an approximate index and trades a little recall for speed at scale. The API, the costs and the refusals are identical; the completeness guarantee is not, so do not use a vector index where you need full recall.

Taught in the course

product-vector-search

These rows are real and already here. Running an operation against them downloads a DynamoDB-compatible engine, about 850 KB, and executes it in this tab.

Try an example

A similarity question, narrowed to what you can actually sell.

PK(pk)
SK(sk)
category
embedding
inStock
name
price
CATEGORY#outdoor
PRODUCT#p-101S
outdoorS
[0.94, 0.08, 0.04, 0.02]L
yesS
Winter sleeping bagS
240N
CATEGORY#outdoor
PRODUCT#p-102S
outdoorS
[0.88, 0.15, 0.06, 0.03]L
yesS
Insulated sleeping matS
38N
CATEGORY#outdoor
PRODUCT#p-103S
outdoorS
[0.85, 0.19, 0.08, 0.04]L
noS
Thermal linerS
22N
CATEGORY#outdoor
PRODUCT#p-104S
outdoorS
[0.12, 0.92, 0.07, 0.03]L
yesS
Folding camp cupS
15N
CATEGORY#outdoor
PRODUCT#p-105S
outdoorS
[0.09, 0.14, 0.93, 0.05]L
yesS
Head torchS
46N
CATEGORY#cycling
PRODUCT#p-201S
cyclingS
[0.07, 0.10, 0.06, 0.95]L
yesS
Road helmetS
89N

Run an operation to see the raw engine response.

table product-vector-searchkeys PK / SKitems 6

Transactions, streams, tags and TTL are among the operations the in-browser engine doesn't implement yet.