Classical language processing
Tokenising, lemmas, TF-IDF, BM25 and entity recognition: methods that predate language models and remain the better choice in many cases.
The idea
Long before language models existed, text was processed by machine: split into words, reduced to base forms, counted and weighted. Those methods are not obsolete; they do part of the work better.
What they are good at
| Task | Classical | Language model |
|---|---|---|
| Finding a case number | very good, exact | unreliable |
| Validating an IBAN | perfect, with a checksum | unnecessary |
| Counting frequencies | perfect | unsuitable |
| Searching by keyword | very good | redundant |
| Grasping meaning | weak | very good |
| Rephrasing | unsuitable | very good |
The processing chain
- 01
Normalise
Lower case, unify Unicode, handle diacritics. For German this is also where compound handling is decided.
- 02
Tokenise
Into words and sentences. Abbreviations ending in a full stop need an exception list, or sentences break at "e.g." and "para.".
- 03
Reduce to base forms
For German, lemmatisation clearly beats stemming, because inflection is richer.
- 04
Weight
TF-IDF or BM25, depending on whether you are comparing or searching.
import re
# Patterns a language model does not recognise more reliably than a rule:
PATTERNS = {
"IBAN": r"\b[A-Z]{2}\d{2}(?:[ ]?[A-Za-z0-9]{4}){2,7}\b",
"VAT number": r"\b(?:ATU\d{8}|DE\d{9})\b",
"date": r"\b\d{1,2}\.\s?\d{1,2}\.\s?\d{2,4}\b",
"case ref": r"\b\d+\s?[A-Za-z]{1,3}\s?\d+/\d{2}\b",
}
def extract(text):
return {name: re.findall(p, text) for name, p in PATTERNS.items()}TF-IDF and BM25
Saturation is the decisive difference: under TF-IDF a document with twenty occurrences is twice as relevant as one with ten. Under BM25 the contribution approaches a ceiling: which matches reality, because the twentieth occurrence carries little new information.
German peculiarities
- Compounds. "Rechnungsprüfungsverfahren" is not found by a full-text search for "Prüfung". A compound splitter lifts recall considerably.
- Inflection. "Vertrages", "Verträge", "Vertrag" belong together. Without lemmatisation recall drops noticeably.
- Umlauts. Both "Prüfung" and "Pruefung" must be found. Normalisation in both directions is needed.
- Linking-s. Rule-based splitting fails on it routinely; a dictionary approach is more reliable.
The combination
In practice hybrid search almost always wins: BM25 for exact terms, vector search for meaning, fused over the ranks. Measured recall@10 regularly sits 5 to 15 points above either method alone. See Vector databases.
Related courses and sources
Hugging Face NLP course
Tokenisation, transformers, fine-tuning and deployment, with code throughout. Assumes Python, and in exchange you end up working with real models.
For development with language models once it has to go beyond calling an interface.
spaCy
A library for classical language processing. For recognising names, parts of speech and structure it is often faster, cheaper and more checkable than a language model.
When names, parts of speech or structure are needed: often faster, cheaper and more checkable than a language model.
Speech and Language Processing
Jurafsky and Martin, the standard work on language processing, free chapter by chapter. Covers classical methods and language models in one arc.
For anyone learning language processing systematically, classical and modern in one arc.