Show the steps for

Synonyms

Tell OrbSearch which words mean the same, so a shopper who types "couch" finds the sofas.

Shoppers say "couch" where the shop says "sofa". A synonym tells search that the words mean the same, so either one finds the sofas. Here are three entries of the home store's German dictionary, one of each kind:

Terminal
curl -s -H "Authorization: Bearer $key" $api/synonyms \
  | jq -r '.dictionaries[] | select(.locale == "de") | .entries[]
      | select(.id | IN("de/groups/0", "de/one_way/2", "de/never/0")) | "\(.id)  \(.summary)"'
200 · 6.7 ms
de/groups/0  sofa and couch find each other.
de/one_way/2  läufer finds teppich, not the other way round.
de/never/0  sessel and sofa are never merged.
  • A group holds words that find each other.
  • A one-way entry leads its first word to the others only: "Läufer" (runner) finds the rugs, but "Teppich" (rug) finds no runners.
  • A never entry keeps look-alike words apart, such as "Sessel" (armchair) and "Sofa". It changes no search.

Each entry's id is its place in synonyms.json, which a change names. Synonyms are always on, with no condition and no schedule.

Reference: groups · one_way · never · GET /api/v1/synonyms

A synonym names what its partner names

A word with a synonym also names what its partner names. "Sofa" is the title of the category Sofas, so "couch" names it too, and so does a compound that ends in a synonym:

Terminal
for q in couch tischlampe; do
  curl -s "http://127.0.0.1:7800/v1/search?query=$q&debug=1" \
    | jq -r '.trace.steps[] | select(.step == "resolve") | .detections[].entry'
done
200 · 6.5 ms · release b25a6aaa
"couch", a synonym of "sofa", and "sofa" is the title "Sofas" of the category wohnen/sofas
"tischlampe" ends in "lampe", a synonym of "leuchte", and "leuchte" is the title "Leuchten" of the category leuchten

"Couch" leads to the sofa page wohnen/sofas. "Tischlampe" (table lamp) is in no entry, but its last part "lampe" is grouped with "leuchte" (light), which names the category Leuchten. The detection names its entry in synonym, such as de/groups/0, so the trace shows which entry decided.

Reference: resolve · Detection

Add a synonym

A shopper searched "Kanapee", an old word for sofa, and found nothing. Add it in a draft, which shoppers see once you publish it.

Show the steps for

Search → Synonyms lists one language's entries, and your first change starts the draft. Type kanapee, sofa on the line on top, and it shows what each word finds now and what the line clashes with:

The line on top holds “kanapee, sofa”: kanapee finds nothing, sofa finds 4 results, and sofa is in the group sofa, couch already.
Panel · Search → Synonyms

A word is in one group at most, so the line offers Add “kanapee” there, which joins the group of sofa and couch. A line without a clash goes in with Enter; One way makes its first word find the others only, and words a never entry keeps apart go in only with Add anyway.

The publish bar above the list says how the draft goes live, here within moments and without a rebuild, beside Publish and Discard. A search that finds nothing in the Playground or Insights offers Add a synonym with its words on this line.

Show the steps for

Start a draft with the store's export, then add the entry. "sofa" is in a group already, so the add is refused with the entry that holds it:

Terminal
draft=$(curl -s -X POST -H "Authorization: Bearer $key" -H 'Content-Type: application/x-ndjson' \
  --data-binary @tests/fixtures/home/catalog.jsonl "$api/imports?name=catalog.jsonl" | jq -r .import.id)
version=$(curl -s -H "Authorization: Bearer $key" $api/imports/$draft | jq -r .version)
jq -n --arg version "$version" '{version: $version, locale: "de", entries: [{kind: "group", words: ["kanapee", "sofa"]}]}' \
  | curl -s -H "Authorization: Bearer $key" -H 'Content-Type: application/json' -d @- $api/imports/$draft/synonyms \
  | jq -c '.refused[].conflicts[]'
422 · 15 ms
{"id":"taken","word":"sofa","entry":"de/groups/0","words":["sofa","couch"],"sentence":"“sofa” is in the group sofa, couch already."}

Add the word to that group instead. A PATCH replaces the entry's words:

Terminal
jq -n --arg version "$version" '{version: $version, entry: {kind: "group", words: ["sofa", "couch", "kanapee"]}}' \
  | curl -s -X PATCH -H "Authorization: Bearer $key" -H 'Content-Type: application/json' -d @- \
    $api/imports/$draft/synonyms/de/groups/0 \
  | jq -r '.synonyms.dictionaries[] | select(.locale == "de") | .entries[0].summary'
200 · 41 ms
sofa, couch and kanapee find each other.

Open the search page for "kanapee" with the draft's files in place of the live ones:

Terminal
body=$(curl -s -H "Authorization: Bearer $key" $api/imports/$draft | jq '{url: "/suche?q=kanapee", files}')
curl -s -H "Authorization: Bearer $key" -H 'Content-Type: application/json' -d "$body" $api/preview/page \
  | jq -c '.location, [.results.sections[] | select(.type == "product") | .hits[].entity]'
200 · 32 ms · release 380e9fcc
"/wohnen/sofas?from=kanapee"
["product:SOFA-ASKA-2","product:SOFA-LUND-3","product:SOFA-NIKO-SCHLAF","product:SOFA-VIDAR-ECK"]

The search page /suche (search) sends "kanapee" to the sofa page with all four sofas. Ask how the draft goes live, then publish it with POST $api/imports/$draft/publish, or discard it:

Terminal
curl -s -H "Authorization: Bearer $key" $api/imports/$draft/publication | jq -r .course.sentence
curl -s -X DELETE -H "Authorization: Bearer $key" $api/imports/$draft | jq -r .state
200 · 16 ms
Goes live within moments: synonyms.json changed only settings the engine applies without reindexing.
discarded

A write on a draft that changed since its version is refused with 409. POST .../synonyms/check answers what the panel's line shows, without writing.

Reference: POST .../synonyms · PATCH .../synonyms/{synonym} · POST .../synonyms/check · POST /api/v1/preview/page

A draft that changes only synonyms goes live as settings, within moments and without a rebuild (Releases).

Traps and limits

  • Words are folded. Entries are lowercased, and "Weiß" and "weiss" (white) are one word, in an entry as in a search.
  • never guards edits only. It refuses an added or changed entry that merges its words, unless the write says despite_never. A synonyms.json written whole keeps such a group, and the list names the clash in its conflicts.
  • Each language has its own dictionary. A locale reads its own, else that of its shorter tag: de-CH reads de, as the list's reads says.
  • A compound counts by its last part. An entry for "lampe" reaches "Tischlampe" too.
  • A preview shows what a synonym names, not what it finds in text. The engine keeps the live synonyms until you publish, so "kanapee" previews through the sofa category, while a synonym for a word in product texts shows once live.

Reference: despite_never · SynonymList

Next

On this page