Search Evolution Explorer

Level 1 · Recency search

src/domain/levels/level-1-recency.ts · 68 lines
Back to 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

sofavs the introduction

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.

Prerequisites

Foundation · Inverted indexbuilt at start
Declared artifactsready
src/domain/levels/level-1-recency.ts68 linessame module the pipeline ran

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 }]),
};
}
a numbered note, explained on the righta function you can open heredefined further down in this filewhere level 0 joins