Agent Wranglers

SRH-14Recommended

Split compound words in languages that join them

For Swedish, German, Dutch, Finnish, Norwegian and Danish fields, split compound words into their parts at index and query time. A search for one part then finds the whole word.

How to do it

These languages write compounds as one word. A Swedish shop sells "vinterjacka", and a search for "jacka" finds nothing with a plain stemmer. A dictionary decompounder splits a word into known words from a list, and keeps the whole word too. Elasticsearch and OpenSearch offer dictionary_decompounder and hyphenation_decompounder token filters. PostgreSQL splits compounds with an Ispell or Hunspell dictionary whose affix file allows compounds. Build the word list from your own catalogue and a public dictionary. Set a minimum part length, such as 3 letters, so short parts do not match everything. Sorting and comparing text follow Sort and compare text by locale.

Examples

JSON example

{
  "settings": {
    "analysis": {
      "filter": {
        "sv_parts": { "type": "dictionary_decompounder", "word_list_path": "analysis/sv-words.txt", "min_subword_size": 3 },
        "sv_stem": { "type": "stemmer", "language": "swedish" }
      },
      "analyzer": {
        "swedish_compound": { "tokenizer": "standard", "filter": ["lowercase", "sv_parts", "sv_stem"] }
      }
    }
  }
}

Python example

def split_compound(word: str, known: set[str], min_part: int = 3) -> list[str]:
    word = word.lower()
    for cut in range(min_part, len(word) - min_part + 1):
        head, tail = word[:cut], word[cut:]
        if head in known and tail in known:
            return [word, head, tail]
    return [word]

JavaScript example

export function splitCompound(word, known, minPart = 3) {
  const lower = word.toLowerCase();
  for (let cut = minPart; cut <= lower.length - minPart; cut++) {
    const [head, tail] = [lower.slice(0, cut), lower.slice(cut)];
    if (known.has(head) && known.has(tail)) return [lower, head, tail];
  }
  return [lower];
}

How to check

A test holds at least 20 compound pairs per supported language, such as "vinterjacka" and "jacka", or "Kinderwagen" and "Wagen". A search for each part returns the record holding the compound in the top 10.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/search/language-and-matching/compound-words">Agent Wranglers search playbook</a>. In code you write, add a comment next to it with the same link.