Semantic Cache Hit Rate at a Similarity Threshold
Problem Statement
An exact-match cache is useless in front of an agent - no two users phrase a question identically. A semantic cache embeds the query and serves a stored answer when the nearest cached query is close enough. The threshold is the whole design: too high and you never hit, too low and you confidently serve the wrong answer. Measuring the trade-off means replaying a query log and counting.
Background
Queries arrive in order. For each one:
- Compute the cosine similarity against every entry currently in the cache.
- Round each similarity to 6 decimal places before comparing - this keeps the boundary case reproducible.
- Take the highest similarity; ties go to the earliest inserted entry.
- If that best similarity is >= threshold, it is a hit - record which entry served it, and do not insert the query (the cache stores one representative per cluster).
- Otherwise it is a miss - insert this query into the cache and move on.
Cosine similarity of and is ; if either vector is all zeros, define the similarity as 0.0.
Your Task
Implement:
def semantic_cache(queries, threshold):
- queries: list of {"id": str, "vec": list[float]}, in arrival order. All vectors have the same length.
Return:
- hits, misses: ints
- hit_rate: hits / len(queries) rounded to 4 decimal places (0.0 for an empty log)
- hit_map: list of [query_id, serving_entry_id] pairs, in arrival order
- cache_size: number of entries in the cache at the end
Input/Output Format
Returns the five-key dict. Do not use numpy-specific printing anywhere; every float in the output is rounded.
Sample
qs = [{"id": "q1", "vec": [1.0, 0.0]},
{"id": "q2", "vec": [2.0, 0.0]},
{"id": "q3", "vec": [0.0, 1.0]}]
out = semantic_cache(qs, 0.9)
print(out["hits"], out["misses"], out["hit_rate"]) # 1 2 0.3333
print(out["hit_map"]) # [['q2', 'q1']]
q2 points the same way as q1 (similarity 1.0) so it hits; q3 is orthogonal (0.0) and misses.
Example
qs = [{'id':'q1','vec':[1.0,0.0]},{'id':'q2','vec':[2.0,0.0]},{'id':'q3','vec':[0.0,1.0]}]
out = semantic_cache(qs, 0.9)
print(out['hits'], out['misses'], out['hit_rate'])
print(out['hit_map'])1 2 0.3333 [['q2', 'q1']]
queriesholds three 2-D vectors in arrival order;thresholdis , the smallest rounded cosine similarity that counts as a hit.q1meets an empty cache. There is nothing to compare against, so it is a miss and becomes the first cached entry.q2: , a hit served byq1. A hit is not stored, so the cache still holds onlyq1.q3: , a miss, so it is inserted and the cache ends with 2 entries.- Totals: 1 hit and 2 misses, so the hit rate is to 4 decimal places;
hit_mapis[['q2', 'q1']], one pair per hit. - Notice that cosine ignores length:
q2is twice as long asq1but points the same way. With a threshold of ,q3would also hit, because .
Constraints
0 <= len(queries) <= 500; vectors are 1 to 64 dimensions- Similarities are rounded to 6 dp before the threshold comparison
- The comparison is
>=, so a similarity exactly equal to the threshold is a hit - Ties on the best similarity resolve to the earliest inserted cache entry
- A hit never inserts into the cache; a miss always does
hit_rateis rounded to 4 dp and is0.0for an empty log- A zero vector has similarity
0.0with everything