45 · Prefix suggestions, related queries, and session recommendation
Units: S16. Prerequisites: 38, 39, 43.
Sources: Wang Shusen’s pinned outline. This is a Lab-authored exercise. Wang's last four modules have a public outline only; this is not presented as the author's complete lecture material.
Evidence boundary: entirely constructed query logs, without real users or private data.
Learning method: predict each comparison, change one variable, run, and explain the difference.
English companion. All instructional Markdown is translated. Experiment code, Chinese language examples, execution counts, and saved outputs remain as in the source edition; historical output text may therefore be Chinese. The initial setup cell anchors the working directory and Python import path for this companion's deeper folder; it does not change the experiment. Saved outputs are historical evidence, not a new run. Run from the top after preparing the required data and models.
# English companions live one directory deeper; keep the original experiment code unchanged.
from pathlib import Path as _TranslationPath
import os as _translation_os
import sys as _translation_sys
_translation_root = next((p for p in [_TranslationPath.cwd(), *_TranslationPath.cwd().parents]
if (p / "reclab").is_dir()), None)
if _translation_root is None:
raise RuntimeError("Open this notebook from inside the Search Recommendation Ads Lab checkout.")
_translation_os.chdir(_translation_root)
if str(_translation_root) not in _translation_sys.path:
_translation_sys.path.insert(0, str(_translation_root))
import numpy as np
import pandas as pd
from IPython.display import display
from reclab.learning.search_curriculum import *Three tasks
Autocomplete must satisfy a prefix; related queries serve the current need; next-query prediction depends on session context. Define inputs/outputs before using frequency and transitions to generate candidates. Popular clicked terms do not establish relevance.
print('CONSTRUCTED sessions',SESSIONS)
print('prefix apple',suggestions('apple'))
print('related apple repair',related('apple repair'))
assert all(q.startswith('apple') for q in suggestions('apple'))Saved notebook output · not executed on this page
CONSTRUCTED sessions [('apple repair', 'phone battery repair'), ('apple repair', 'apple official repair'), ('apple fruit', 'apple pie'), ('apple repair', 'phone battery repair'), ('phone battery repair', 'battery price'), ('apple fruit', 'apple pie')]
prefix apple ['apple repair', 'apple fruit', 'apple pie', 'apple official repair']
related apple repair ['phone battery repair', 'apple official repair']
Fit and held-out sessions
Split at session boundaries. Repeated templates can leak; this example deliberately reveals template overlap and does not report generalization. Fix the first four sessions for fit and last two for mechanism evaluation, listing overlap instead of concealing it.
fit=SESSIONS[:4]; hold=SESSIONS[4:]
print('template overlap',set(fit)&set(hold))
rows=[]
for a,b in hold:
pred=related(a,fit); rank=pred.index(b)+1 if b in pred else None
rows.append({'query':a,'next':b,'pred':pred,'RR':1/rank if rank else 0})
display(pd.DataFrame(rows))Saved notebook output · not executed on this page
template overlap {('apple fruit', 'apple pie')}
| query | next | pred | RR | |
|---|---|---|---|---|
| 0 | phone battery repair | battery price | [] | 0.0 |
| 1 | apple fruit | apple pie | [apple pie] | 1.0 |
Prefix ranking and relevance constraints
Retrieve prefix-matching candidates, then rank by frequency. Explicitly return empty if none match, instead of silently changing the prefix. Change only prefix.
for prefix in ['apple','apple r','unknown']:
pred=suggestions(prefix,fit); print(prefix,pred)
assert all(q.startswith(prefix) for q in pred)
assert suggestions('unknown',fit)==[]
# 人工前缀判断:相关集合只对当前补全任务有效。
gold={'apple repair','apple official repair'}
ranked=suggestions('apple',fit)
for k in [1,3]:
head=ranked[:k]
print('prefix k',k,'precision',len(set(head)&gold)/max(len(head),1),'recall',len(set(head)&gold)/len(gold))
Saved notebook output · not executed on this page
apple ['apple repair', 'apple fruit', 'apple official repair', 'apple pie'] apple r ['apple repair'] unknown [] prefix k 1 precision 1.0 recall 0.5 prefix k 3 precision 0.6666666666666666 recall 1.0
Drift and fallback
A session may move from repair to price. Restricting suggestions to the same anchor term is conservative and may miss reasonable transitions; inspect coverage loss. Real evaluation needs human relevance, coverage, freshness, and online rejection rates.
for q in ['apple repair','phone battery repair','unknown']:
raw=related(q); safe=[x for x in raw if set(terms(q))&set(terms(x))]
print(q,'raw',raw,'guarded',safe,'fallback prefix',suggestions(q) if not safe else [])Saved notebook output · not executed on this page
apple repair raw ['phone battery repair', 'apple official repair'] guarded ['phone battery repair', 'apple official repair'] fallback prefix [] phone battery repair raw ['battery price'] guarded ['battery price'] fallback prefix [] unknown raw [] guarded [] fallback prefix []
Interpreting the saved run
One held-out transition has no candidate (RR=0); the other hits (RR=1) but repeats a fit template, so reliable generalization is not established. Artificial prefix judgments give precision=1 and recall=0.5 at k=1, versus about 0.667 and 1 at k=3, demonstrating the tradeoff. unknown explicitly returns no results.
After changing parameters, interpret the new outputs. This fixed commentary is not a new measurement.
Review and exercise
Write down inputs, outputs, what stayed fixed, and conclusions this chapter cannot support. Predict and rerun one single-variable comparison above; retain failures. Return to the search learning path for the next semantic unit.