Skip to content

feat: search the catalog by meaning - #640

Draft
jaspermayone wants to merge 1 commit into
feature/embeddings-foundationfrom
feature/semantic-catalog-search
Draft

jaspermayone wants to merge 1 commit into
feature/embeddings-foundationfrom
feature/semantic-catalog-search

Conversation

@jaspermayone

@jaspermayone jaspermayone commented Sep 19, 2026

Copy link
Copy Markdown
Member

Part of #453. Stacked on #639.

q matches the literal words. semantic=true ranks by meaning instead, so
"intro to programming" reaches "Computer Science I". It works on sections and
on instructors, on REST and on GraphQL.

curl "…/api/v1/catalog/sections?q=learn+to+program&semantic=true&term_uid=202710"
{ sections(filter: { q: "learn to program", semantic: true }, first: 10) { nodes { crn title } } }

How a request runs

flowchart TD
    A["q + semantic=true"] --> B{Flag on and<br/>OPENAI_API_KEY set?}
    B -->|no| K[Keyword search]
    B -->|yes| C{Query in the cache?}
    C -->|yes| E[Rank the filtered rows<br/>by cosine distance]
    C -->|no| D[Embed the query]
    D -->|API failed| K
    D -->|vector| E
    E --> F[One page, nearest first]
Loading

Points worth reviewing:

  • The other filters run before the vector cut, so a term filter never
    leaves the page short.
  • The query vector is cached by the text itself, lower-cased. Students ask the
    same few things during registration week.
  • Every failure path falls back to the keyword search. A semantic request never
    returns an error because the API was down.
  • semantic_search is a global Flipper flag. Turning it off stops every
    embedding call at once.
  • A new Rack::Attack throttle limits semantic REST requests to 30/min/IP. The
    keyword search keeps its 300/min.

Docs and the OpenAPI document are updated.

Tests

bundle exec rspec is green locally (1531 examples), including the fallback
paths, the cache, and both API surfaces.

Stack created with GitHub Stacks CLIGive Feedback 💬

Adds semantic=true to the sections and instructors endpoints, on REST
and on GraphQL. The query is embedded once and cached, the vectors rank
whatever the other filters left, and a failure falls back to the keyword
search rather than erroring.

The semantic_search flag gates the cost. Without it, or without
OPENAI_API_KEY, the catalog answers exactly as it does today.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant