You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Speed up Find Similar with precompute and inbox cache
POST /api/similar previously took many seconds because it re-fetched
1000 emails from JMAP on every call and ran O(N²) Levenshtein over
email bodies that could be tens of thousands of characters.
- Precompute normalized subject, sender, and body tokens once per
email so the inner pairwise compare avoids re-normalizing and
re-tokenizing the same strings.
- Replace Levenshtein on bodies with Jaccard overlap of word tokens
(length >= 3). O(L) per pair instead of O(L1*L2).
- Short-circuit each weighted stage as soon as the partial score plus
the maximum remaining contribution falls below the threshold.
- Cache the 1000-email inbox fetch server-side for 60 seconds, with
invalidation on archive/unarchive, so successive "Find Similar" and
rapid "Archive & Find Next" calls don't re-pull from JMAP.
BenchmarkFindSimilarEmails over a synthetic 1000-email corpus runs
in ~4.3 ms. The public similarity API is unchanged and all existing
tests pass; new tests cover Jaccard, tokenizeBody, cache hit, cache
invalidation, TTL expiration, and the no-cache-on-error path.
-**Content Similarity (20% weight):**Body/preview text analysis
87
+
-**Subject Similarity (40% weight):** Levenshtein distance over pre-normalized strings
88
+
-**Sender Similarity (40% weight):**Levenshtein distance over pre-normalized sender email address
89
+
-**Content Similarity (20% weight):**Jaccard similarity over normalized word tokens (length ≥ 3) extracted from the preview/body
90
90
-**Features:**
91
+
- Per-email features (`subjectNorm`, `senderNorm`, `bodyTokens`) precomputed once per call so the inner pairwise compare avoids re-normalizing or re-tokenizing the same strings
92
+
- Threshold-aware short-circuit: each weighted stage bails out as soon as the partial score plus the maximum remaining contribution falls below `threshold`
- Inbox cache for `/api/similar`: the 1000-email JMAP fetch is cached in-process for 60 seconds (`inboxCacheTTL`) and invalidated at the end of `handleArchive`/`handleUnarchive`, so successive "Find Similar" / "Archive & Find Next" calls don't re-pull from JMAP
0 commit comments