Dev.to · 2 min read

Two questions that ask the same thing: how we catch near-twins before they reach a practice exam

Two questions that ask the same thing: how we catch near-twins before they reach a practice exam

Our question bank is written by AI models, in batches, one exam slot at a time. A slot is a topic with a set number of points in an exam. If you ask a model for ten questions on the same rule, you get ten questions on the same rule. Some of them are the same question in different clothes. For a practice exam that's a real problem. A candidate who sees two near-twins in one sitting gets the second one for free, and the form teaches less than it looks like. This post is about the three places we catch them (import, form assembly and a leak test for free questions), and the one place we deliberately don't look. 1. At import: trigram similarity per slot When a draft has passed its checks, the importer writes it to the database. Before the insert, it asks Postgres whether the same slot already holds a question with a very similar stem: select q.code, extensions.similarity(v.stem_text, $1)::float8 as similarity from questions q join question_versions v on v.question_id = q.id where q.exam_id = $2 and q.slot is not distinct from $3 and q.status 'retired' and extensions.similarity(v.stem_text, $1) >= $4 order by similarity desc limit 1 The threshold is 0.8. similarity is pg_trgm's: lower-case the stem, split it into words of letters and digits, pad each word with two spaces in front and one behind, cut it into three-character pieces, and compare the two sets as shared / all. We also have the same function in TypeScript, so tests can use it without a database: export function trigrams(text: string): Set { const out = new Set(); for (const word of text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? []) { const padded = ` ${word} `; for (let i = 0; i + 3

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More Programming & Dev News