Word and vector similarity put an odd 'dirt bike' fabric empire shade at the top for 'lamp shade'. Joint reranking reads the two texts together and drops it out of the top 10.
Level 10 · Cross-encoder reranking
Read the query and the listing together
Take chapter 9's first 50 candidatesAll listings that matched the query at all, before they are ordered. Scoring can only reorder this set. It cannot add to it.. Feed the query and each listing into a pretrainedAlready trained on another dataset. This app downloads fixed model weights and runs them locally instead of training a new neural network. neural networkA model with many adjustable numbers that learns patterns from examples instead of being told the rules. The encoder that turns text into a vector is one. together. Its attention layersParts of a neural network that let each token use information from other tokens. In a cross-encoder, tokens in the query can use information from the listing before the model produces a score. can compare words across both texts before producing a relevance score. Sort the short list by that score.
Where to look: match takes chapter 9's first 50 and awaits one batch of joint scores. score returns each stored model score and the earlier rank for comparison.
Guided example
Prerequisites
npm run data:embeddingsChapter 9 retrieves the candidatesAll listings that matched the query at all, before they are ordered. Scoring can only reorder this set. It cannot add to it.. A pretrainedAlready trained on another dataset. This app downloads fixed model weights and runs them locally instead of training a new neural network. cross-encoderA model that reads the query and one listing together and outputs one relevance score. It can compare wording across both texts, but it must run for each pair. A listing's relevance score cannot be prepared before the query arrives, so this app reranks only a short list. reads each query-listing pair and replaces the order of the first 50 with its joint relevance scores.
import { level5Content } from "../../content/levels/level-5.ts";import { } from "../cross-encoder/model-spec.ts";import { } from "../query-understanding/understand.ts";import { } from "../signals/build-signals.ts";import { } from "../sort-score.ts";import { } from "../text/item-text.ts";import type { AsyncLevelRanker, CrossEncoderDeps, EvolutionLevel } from "../types/level.ts";import type { QueryUnderstanding } from "../types/query.ts";import type { ScoredCandidate } from "../types/ranking.ts";import { as } from "./level-4-hybrid.ts";const RERANK_WIDTH = 50;/** Chapter 9 retrieves; this chapter spends neural inference only on its first 50. */export function createRanker(deps: CrossEncoderDeps): AsyncLevelRanker { const previous = (deps); const scoredByQuery = new WeakMap<QueryUnderstanding, ReadonlyMap<string, ScoredCandidate>>(); return { async match(understanding) { const shortlist = previous .match(understanding) .items.map((item) => previous.score(understanding, item)) .sort((left, right) => ([left.item.id, left.score], [right.item.id, right.score]), ) .slice(0, ); const jointScores = await deps.crossEncoder.scorePairs( (understanding.rawText), shortlist.map(({ item }) => (item)), ); if (jointScores.length !== shortlist.length || !jointScores.every(Number.isFinite)) { throw new Error( `Cross-encoder returned ${jointScores.length} scores for ${shortlist.length} candidates; all scores must be finite.`, ); } const scored = new Map<string, ScoredCandidate>(); for (const [index, baseline] of shortlist.entries()) { const score = jointScores[index] as number; scored.set(baseline.item.id, { item: baseline.item, score, signals: (understanding, baseline.item, [ { name: "crossEncoder", value: score }, { name: "previousRank", value: index + 1 }, ...baseline.signals.filter( (signal) => signal.name === "rrf" || signal.name === "vectorSimilarity", ), ]), }); } scoredByQuery.set(understanding, scored); return { items: shortlist.map(({ item }) => item) }; }, score(understanding, candidate) { const scored = scoredByQuery.get(understanding)?.get(candidate.id); if (scored === undefined) { throw new Error( "Cross-encoder scoring requires an awaited match for this query and candidate.", ); } return scored; }, };}