Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 85 additions & 41 deletions api/routers/insights.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import logging
import random
from collections import Counter, defaultdict
from dataclasses import dataclass
from datetime import date, datetime, timedelta, timezone

import httpx
Expand Down Expand Up @@ -553,58 +554,91 @@ async def _fetch() -> PlotOfTheDayResponse | None:
# =============================================================================


def _collect_impl_tags(spec: Spec, library: str | None = None) -> set[str]:
"""Collect spec-level tags + impl-level tags for a spec.
@dataclass(frozen=True, eq=False)
class _RelatedEntry:
"""One spec as the related-plots ranking reads it: plain values, no ORM objects.

If library is specified, only include that library's impl_tags.
Otherwise, collect impl_tags from all implementations.
`preview` is the best-scored implementation that has a preview, as
`(preview_url, preview_url_light, preview_url_dark, library_id, language)`.
"""
tags = _flatten_tags(spec.tags)

id: str
title: str
spec_tags: frozenset[str]
impl_tags: dict[str, frozenset[str]]
all_tags: frozenset[str]
preview: tuple[str | None, str | None, str | None, str, str | None] | None

def tags(self, mode: str, library: str | None) -> frozenset[str]:
"""The tags to compare: spec tags, plus impl tags in full mode (one library's, or all)."""
if mode != "full":
return self.spec_tags
if library:
return self.spec_tags | self.impl_tags.get(library, frozenset())
return self.all_tags


def _related_entry(spec: Spec) -> _RelatedEntry:
spec_tags = frozenset(_flatten_tags(spec.tags))
# Union per library: the unique key is (spec, language, library), so one library may appear twice.
impl_tags: dict[str, frozenset[str]] = {}
for impl in spec.impls:
if library and impl.library_id != library:
continue
if impl.impl_tags and isinstance(impl.impl_tags, dict):
tags |= _flatten_tags(impl.impl_tags)
return tags
impl_tags[impl.library_id] = impl_tags.get(impl.library_id, frozenset()) | _flatten_tags(impl.impl_tags)
impls_with_preview = [i for i in spec.impls if i.preview_url]
best = max(impls_with_preview, key=lambda i: i.quality_score or 0) if impls_with_preview else None
return _RelatedEntry(
id=spec.id,
title=spec.title,
spec_tags=spec_tags,
impl_tags=impl_tags,
all_tags=spec_tags.union(*impl_tags.values()),
preview=(
(
best.preview_url,
best.preview_url_light,
best.preview_url_dark,
best.library_id,
best.library.language if best.library else None,
)
if best
else None
),
)


async def _load_related_index(repo: SpecRepository) -> list[_RelatedEntry]:
return [_related_entry(spec) for spec in await repo.get_all()]

async def _build_related(
repo: SpecRepository, spec_id: str, limit: int, mode: str, library: str | None = None

async def _refresh_related_index() -> list[_RelatedEntry]:
"""Standalone factory for background refresh."""
async with get_db_context() as db:
return await _load_related_index(SpecRepository(db))


def _build_related(
index: list[_RelatedEntry], spec_id: str, limit: int, mode: str, library: str | None = None
) -> RelatedSpecsResponse:
"""Find related specs using Jaccard similarity on tags.

mode="spec": only spec-level tags (for overview page)
mode="full": spec + impl tags for the given library (for impl detail page)
"""
all_specs = await repo.get_all()

# Find target spec
target = None
for s in all_specs:
if s.id == spec_id:
target = s
break
target = next((entry for entry in index if entry.id == spec_id), None)
if target is None:
return RelatedSpecsResponse(related=[])

# Build target tags based on mode
if mode == "full":
target_tags = _collect_impl_tags(target, library)
else:
target_tags = _flatten_tags(target.tags)
target_tags = target.tags(mode, library)
if not target_tags:
return RelatedSpecsResponse(related=[])

# Compute similarity for all other specs
scored: list[tuple[float, list[str], Spec]] = []
for spec in all_specs:
scored: list[tuple[float, list[str], _RelatedEntry]] = []
for spec in index:
if spec.id == spec_id:
continue
# For other specs: use same library's impl_tags if available, else best match
if mode == "full":
other_tags = _collect_impl_tags(spec, library)
else:
other_tags = _flatten_tags(spec.tags)
other_tags = spec.tags(mode, library)
if not other_tags:
continue
intersection = target_tags & other_tags
Expand All @@ -629,17 +663,16 @@ async def _build_related(
# Build response with best-quality preview per spec
related: list[RelatedSpecItem] = []
for similarity, shared_tags, spec in top_pool[:limit]:
impls_with_preview = [i for i in spec.impls if i.preview_url]
best_impl = max(impls_with_preview, key=lambda i: i.quality_score or 0) if impls_with_preview else None
preview_url, preview_url_light, preview_url_dark, library_id, language = spec.preview or (None,) * 5
related.append(
RelatedSpecItem(
id=spec.id,
title=spec.title,
preview_url=best_impl.preview_url if best_impl else None,
preview_url_light=best_impl.preview_url_light if best_impl else None,
preview_url_dark=best_impl.preview_url_dark if best_impl else None,
library_id=best_impl.library_id if best_impl else None,
language=(best_impl.library.language if best_impl and best_impl.library else None),
preview_url=preview_url,
preview_url_light=preview_url_light,
preview_url_dark=preview_url_dark,
library_id=library_id,
language=language,
similarity=round(similarity, 3),
shared_tags=shared_tags,
)
Expand All @@ -662,13 +695,24 @@ async def get_related_specs(
mode=spec: only spec-level tags (plot_type, domain, etc.)
mode=full: spec tags + impl tags for the given library
library: in full mode, use this library's impl_tags (required for accurate tag matching)

The catalogue is cached once as a plain-value index under a single key and every
request ranks against it in memory. A response cache keyed per spec, library, mode
and limit had thousands of keys, which evicted each other from the shared cache, so
nearly every call reloaded all specs from the database.
"""
repo = SpecRepository(db)

async def _fetch() -> RelatedSpecsResponse:
return await _build_related(repo, spec_id, limit, mode, library)
async def _fetch_index() -> list[_RelatedEntry]:
return await _load_related_index(repo)

return await get_or_set_cache(cache_key("insights", "related", spec_id, str(limit), mode, library or ""), _fetch)
index = await get_or_set_cache(
cache_key("insights", "related_index"),
_fetch_index,
refresh_after=settings.cache_refresh_after,
refresh_factory=_refresh_related_index,
)
return _build_related(index, spec_id, limit, mode, library)


# =============================================================================
Expand Down
11 changes: 11 additions & 0 deletions changelog.d/related-shared-index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Fixed

- **Related plots load in about a millisecond instead of about 750 ms.** The
related-plots block on every spec and implementation page was cached per spec,
library, mode and limit. Those thousands of keys evicted each other from the
shared 1,000-entry cache, so nearly every call reloaded all specs from the
database (p50 755 ms, p99 1.6 s in the LinkedIn traffic of 2026-10-18/19).
`/insights/related` now caches the catalogue once as a plain-value index under
a single key and ranks against it in memory. The results are identical: 1,266
spec, library, mode and limit combinations on the live catalogue gave
byte-equal responses. (#12214)
4 changes: 2 additions & 2 deletions docs/reference/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,11 @@ Deterministically selects an implementation based on today's date. It prefers th

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `limit` | int | 6 | Number of results (1-12) |
| `limit` | int | 6 | Number of results (1-24) |
| `mode` | string | `spec` | `spec` = spec tags only, `full` = spec + impl tags |
| `library` | string | null | In `full` mode, match against this library's impl_tags |

Returns related specs sorted by Jaccard similarity with preview thumbnails and shared tags.
Returns related specs sorted by Jaccard similarity with preview thumbnails and shared tags. The catalogue is cached once as an in-memory index under a single key. The index is refreshed in the background once it is an hour old, and it is cleared with the rest of the cache after a database sync. Each request ranks against that index in about a millisecond.

### GET `/specs/{spec_id}/{library}/code`

Expand Down
125 changes: 63 additions & 62 deletions tests/unit/api/test_insights_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"""

from datetime import timezone
from unittest.mock import MagicMock

from api.routers.insights import _collect_impl_tags, _flatten_tags, _parse_iso, _score_bucket
from api.routers.insights import _flatten_tags, _parse_iso, _related_entry, _score_bucket


class TestScoreBucket:
Expand Down Expand Up @@ -105,76 +106,76 @@ def test_date_only(self) -> None:
assert result.year == 2025


class TestCollectImplTags:
"""Tests for _collect_impl_tags."""
def _impl(library_id: str, impl_tags: object, score: float | None = None, preview: str | None = None) -> MagicMock:
impl = MagicMock()
impl.library_id = library_id
impl.impl_tags = impl_tags
impl.quality_score = score
impl.preview_url = preview
impl.preview_url_light = preview
impl.preview_url_dark = None
impl.library.language = "python"
return impl

def test_spec_with_no_tags(self) -> None:
from unittest.mock import MagicMock

spec = MagicMock()
spec.tags = None
spec.impls = []
result = _collect_impl_tags(spec)
assert result == set()

def test_spec_with_tags_and_impl_tags(self) -> None:
from unittest.mock import MagicMock

impl = MagicMock()
impl.library_id = "matplotlib"
impl.impl_tags = {"techniques": ["annotations"]}

spec = MagicMock()
spec.tags = {"plot_type": ["scatter"]}
spec.impls = [impl]

result = _collect_impl_tags(spec)
assert "plot_type:scatter" in result
assert "techniques:annotations" in result

def test_filter_by_library(self) -> None:
from unittest.mock import MagicMock

impl1 = MagicMock()
impl1.library_id = "matplotlib"
impl1.impl_tags = {"techniques": ["annotations"]}
def _spec(tags: dict | None, impls: list[MagicMock]) -> MagicMock:
spec = MagicMock()
spec.id = "scatter-basic"
spec.title = "Basic Scatter"
spec.tags = tags
spec.impls = impls
return spec

impl2 = MagicMock()
impl2.library_id = "seaborn"
impl2.impl_tags = {"techniques": ["regression"]}

spec = MagicMock()
spec.tags = {"plot_type": ["scatter"]}
spec.impls = [impl1, impl2]
class TestRelatedEntryTags:
"""Tests for the tag sets of _related_entry."""

result = _collect_impl_tags(spec, library="matplotlib")
assert "techniques:annotations" in result
assert "techniques:regression" not in result
def test_spec_with_no_tags(self) -> None:
entry = _related_entry(_spec(None, []))
assert entry.tags("spec", None) == set()
assert entry.tags("full", None) == set()

def test_spec_mode_ignores_impl_tags(self) -> None:
entry = _related_entry(
_spec({"plot_type": ["scatter"]}, [_impl("matplotlib", {"techniques": ["annotations"]})])
)
assert entry.tags("spec", "matplotlib") == {"plot_type:scatter"}

def test_full_mode_without_library_collects_every_impl(self) -> None:
impls = [_impl("matplotlib", {"techniques": ["annotations"]}), _impl("seaborn", {"techniques": ["regression"]})]
entry = _related_entry(_spec({"plot_type": ["scatter"]}, impls))
assert entry.tags("full", None) == {"plot_type:scatter", "techniques:annotations", "techniques:regression"}

def test_full_mode_filters_by_library(self) -> None:
impls = [_impl("matplotlib", {"techniques": ["annotations"]}), _impl("seaborn", {"techniques": ["regression"]})]
entry = _related_entry(_spec({"plot_type": ["scatter"]}, impls))
assert entry.tags("full", "matplotlib") == {"plot_type:scatter", "techniques:annotations"}
assert entry.tags("full", "plotly") == {"plot_type:scatter"}

def test_one_library_in_two_languages_unions_its_tags(self) -> None:
impls = [_impl("plotly", {"techniques": ["hover"]}), _impl("plotly", {"techniques": ["animation"]})]
entry = _related_entry(_spec({}, impls))
assert entry.tags("full", "plotly") == {"techniques:hover", "techniques:animation"}

def test_impl_tags_none(self) -> None:
from unittest.mock import MagicMock

impl = MagicMock()
impl.library_id = "matplotlib"
impl.impl_tags = None

spec = MagicMock()
spec.tags = {"plot_type": ["scatter"]}
spec.impls = [impl]

result = _collect_impl_tags(spec)
assert result == {"plot_type:scatter"}
entry = _related_entry(_spec({"plot_type": ["scatter"]}, [_impl("matplotlib", None)]))
assert entry.tags("full", None) == {"plot_type:scatter"}

def test_impl_tags_not_dict(self) -> None:
from unittest.mock import MagicMock
entry = _related_entry(_spec({}, [_impl("matplotlib", "not-a-dict")]))
assert entry.tags("full", None) == set()


impl = MagicMock()
impl.library_id = "matplotlib"
impl.impl_tags = "not-a-dict"
class TestRelatedEntryPreview:
"""Tests for the preview _related_entry picks."""

spec = MagicMock()
spec.tags = {}
spec.impls = [impl]
def test_best_scored_impl_with_a_preview(self) -> None:
impls = [
_impl("matplotlib", None, score=88.0, preview="m.png"),
_impl("seaborn", None, score=95.0, preview="s.png"),
_impl("plotly", None, score=99.0, preview=None),
]
assert _related_entry(_spec(None, impls)).preview == ("s.png", "s.png", None, "seaborn", "python")

result = _collect_impl_tags(spec)
assert result == set()
def test_no_preview(self) -> None:
assert _related_entry(_spec(None, [_impl("matplotlib", None, score=90.0)])).preview is None
Loading
Loading