The simplest search keeps the listings that write the query word and orders them newest first. This loveseat enters the top 10 because its text contains 'sofa' and it is recent; relevance does not enter the order.
Level 1 · Recency search
Show the newest listings first
Build a word table once, ahead of time: for every word, the listings that contain it. Look the query words up exactly as typed: keep only listings that contain every query word, then order them newest first.
Where to look: match looks the query words up in the inverted indexA table built once, ahead of time: for every word, the list of listings that contain it. Like the index at the back of a book. A query then looks up its words instead of scanning every listing. with AND semantics, exactly as typed. score returns only the recency value.
Guided example
Prerequisites
The first runnable chapter: strict word matchingThe step that decides which listings are candidates at all., then newest first. Matching and scoringThe step that decides the order of the candidates. are two separate functions.
import { levelRecencyContent } from "../../content/levels/level-recency.ts";import { } from "../query-understanding/understand.ts";import { } from "../signals/build-signals.ts";import { } from "../signals/frozen-clock.ts";import { } from "../signals/recency.ts";import type { EvolutionLevel, LevelDeps, LevelRanker } from "../types/level.ts";import { as } from "./level-0-evaluation.ts";/** Strict matching with newest-first order, kept readable on its own. */export function createRanker(deps: LevelDeps): LevelRanker { const previous = (deps); // One query reads the clock once, so two listings posted at the same moment score exactly // the same and a millisecond tick cannot change their order between calls. const clock = (deps.clock); return { match: (understanding) => (deps, previous, understanding), score: (understanding, candidate) => (previous, clock, understanding, candidate), };}function strictCandidates( deps: LevelDeps, previous: LevelRanker, understanding: Parameters<LevelRanker["match"]>[0],): ReturnType<LevelRanker["match"]> { previous.match(understanding); const matching = (understanding); return deps.index.match(matching.tokens);}function newestFirst( previous: LevelRanker, clock: ReturnType<typeof >, understanding: Parameters<LevelRanker["match"]>[0], candidate: Parameters<LevelRanker["score"]>[1],): ReturnType<LevelRanker["score"]> { const base = previous.score(understanding, candidate); const value = (candidate.postedAt, clock.now().getTime()); return { item: candidate, score: base.score + value, signals: (understanding, candidate, [{ name: "recency", value }]), };}