Skip to content

Embeddings API

Semantische helpers voor zoeken, opschonen, matching tussen datasets, en gelijkenis over tekst - standaard modelvrij (een hashing-embedder), met een opt-in transformers-backend (MiniLM via WebGPU) voor echte synoniemherkenning. Voor het verhaal en de labs, zie de Insights-gids.

Import

ts
import {
  findSimilar, matchLabels, reconcileLabels, createEmbedder,
  cosineSimilarity, hashEmbed,
} from "@michi-vz/insights/embeddings";
// also re-exported from the package root: import { findSimilar } from "@michi-vz/insights";

findSimilar - rangschik items op betekenis

Probeer het - typ een term en de labels worden gerangschikt op betekenis (standaard modelvrij):

A dashboard with 8 KPIs. Don't remember the exact name? Ask in plain English - embeddings rank every series by what your words mean, then highlight the best match.

Model-free ranks by shared letters, so customer finds the customer KPIs - but money coming in can't reach Revenue (no letters in common). Load a model (top-right) to search by meaning.

ts
const ranked = await findSimilar("revenue", labels, (s) => s, { backend: "hash" });
// → [{ item, score }, ...] sorted by descending cosine similarity
ParameterTypeWat het doet
querystringDe tekst om tegen te matchen.
itemsT[]Kandidaten om te rangschikken.
text(item: T) => stringHaalt de vergelijkbare string uit elk item.
optionsEmbedOptions{ backend?, model?, dim? } - zie hieronder.

reconcileLabels - voeg rommelige labels samen die hetzelfde betekenen

Probeer het - rommelige, verschillend gespelde labels vallen samen in schone groepen:

Three countries reported sales, but three data sources spelled them 10 different ways. Reconcile merges by similarity (the embedding model); Certify adds a second specialist - a small LLM that confirms each merge and names it. The result below is shown instantly; switch to Real model to download the model and run it yourself.

10 raw labels - messy, duplicated, wrong totals

Charted raw, each spelling is its own bar - the totals are wrong and split. Step through Reconcile and Certify to fix them.

Dezelfde entiteit wordt vaak op veel verschillende manieren gespeld ("United States" / "usa" / "United States"); groeperen op exacte overeenkomst splitst dit op in aparte buckets met foutieve totalen. Dit embedt elk label en clustert gulzig op cosinusgelijkenis (single-linkage) met een betrouwbaarheidsdrempel, zodat verschillende entiteiten nooit samenvallen alleen omdat ze dicht bij elkaar liggen. Tel je series op per name van elke groep (de cluster-medoid) voor schone totalen.

ts
const groups = await reconcileLabels(labels, { threshold: 0.7, margin: 0.05 });
// → [{ name, members: [...] }, ...]
OptieTypeStandaardWat het doet
thresholdnumber0.7 (transformers) / 0.6 (hash)Minimale cosinuswaarde om samen te voegen in een groep.
marginnumber0.05Betrouwbaarheidsdrempel: een label wordt alleen samengevoegd als het minstens dit veel dichter bij zijn beste groep ligt dan bij de op-een-na-beste. 0 schakelt dit uit.
embedderEmbedderoptioneelHergebruik een vooraf gebouwde embedder in plaats van er een nieuwe te maken.
backend / model / dimEmbedOptionshashOvergeërfde embedder-opties.

De modelvrije standaard voegt spelling/hoofdlettergebruik/typfouten offline samen; { backend: "transformers" } voegt ook synoniemen, afkortingen en vertalingen samen. Voor gezaghebbende canonieke namen (USA -> United States), combineer dit met een aliaslijst of een LLM (zie het "Certify"-recept in de gids).

matchLabels - koppel dezelfde entiteiten tussen twee lijsten

Probeer het - twee niet-overeenkomende exports worden betrouwbare paren plus eerlijk-ongematchte resten, en de samengevoegde rijen worden getekend als één grafiek:

A CRM export and an ERP export list the same four countries - spelled differently, each with one country the other side lacks. matchLabels links each CRM row to its ERP row by meaning, and honestly reports anything it cannot confidently pair, so two different countries are never silently merged. The result below is shown instantly; switch to Real model to download the model and run it yourself.

4 CRM rows, 4 ERP rows - two systems, two spellings each, not yet linked

Charted raw, all 8 rows sit as unrelated bars from two systems that know nothing about each other. Step to Match to link them.

Waar reconcileLabels duplicaten opschoont binnen één lijst, koppelt matchLabels een bronlijst aan een doellijst (een CRM-export vs een ERP-export). Een paar is alleen een betrouwbare match wanneer het de gelijkenisdrempel haalt, de betrouwbaarheidsdrempel (op de keuze van de bron tussen doelen), en - standaard - een wederzijdse beste match: elke kant kiest de andere als eerste, zodat twee bronrijen nooit stilzwijgend samenvallen op één doel. Al het andere wordt teruggerapporteerd met de dichtstbijzijnde bijna-match, nooit weggegooid of geforceerd gekoppeld.

ts
const { matches, unmatchedSource, unmatchedTarget } = await matchLabels(crmLabels, erpLabels);
// matches          → [{ source, target, similarity }, ...] (source order)
// unmatchedSource  → [{ label, closest, similarity }, ...] ("did you mean" hints)
// unmatchedTarget  → [{ label, closest, similarity }, ...]
OptieTypeStandaardWat het doet
thresholdnumber0.7 (transformers) / 0.6 (hash)Minimale cosinuswaarde om een kandidaat überhaupt in aanmerking te nemen.
marginnumber0.05Betrouwbaarheidsdrempel op de keuze van de bron: het beste doel moet het op-een-na-beste met dit veel verslaan. 0 schakelt dit uit.
mutualbooleantrueVereist een wederzijdse beste match. false staat many-to-one toe op een doel (of beter: pas reconcileLabels eerst toe op de rommelige kant, en match daarna).
embedderEmbedderoptioneelHergebruik een vooraf gebouwde embedder in plaats van er een nieuwe te maken.
backend / model / dimEmbedOptionshashOvergeërfde embedder-opties.

Dubbele bronlabels worden onder mutual: true opgelost tot één winnaar; de verliezer wordt gerapporteerd als ongematcht met zijn bijna-match, wat je signaal is om die kant eerst op te schonen.

createEmbedder / cosineSimilarity / hashEmbed - de bouwstenen

ts
const embedder = await createEmbedder({ backend: "transformers" }); // falls back to hash if unavailable
const [a, b] = await embedder.embed(["customer", "customers"]);
cosineSimilarity(a, b); // 0..1
hashEmbed("customer", 128); // deterministic char-ngram vector, no model
FunctieSignatuurNotities
createEmbedder(options?: EmbedOptions) => Promise<Embedder>Embedder is { backend, embed(texts) }. backend: "transformers" laadt MiniLM lazy en valt terug op hash als de dependency/het model ontbreekt.
cosineSimilarity(a: number[], b: number[]) => numberStandaard cosinuswaarde; 0 voor een nulvector.
hashEmbed(text: string, dim?: number) => number[]Modelvrije fuzzy char-ngram embedding (standaard dim 128); maakt customer ~ customers mogelijk zonder enig model.

EmbedOptions = { backend?: "hash" | "transformers"; model?: string; dim?: number }.

Insights-gids