Machine Learning
Detect names of people, places, and organizations with an optional machine-learning (NER) model
The regex/checksum recognisers cannot catch free-form person names, place names, organizations, nationality/religious/political groups, or facilities — those have no fixed pattern. An optional machine-learning Named Entity Recognition (NER) pass adds PERSON, LOCATION, ORGANIZATION, NATIONALITY_RELIGION_POLITICS, and FACILITY detection on top of the regex layer. Which entities a given model can produce depends on its label set: a CoNLL model (e.g. dslim/bert-base-NER) yields person/location/organization, while an OntoNotes-class model additionally yields NRP and facility.
It is opt-in at runtime: the ML/NER code is always built into the binary, but stays inactive until both pii.enabled and pii.ner_enabled are true and a model directory is supplied.
Inference uses ONNX Runtime — there is no external runtime library to install: you need only the dbmcp binary and a model directory. The directory must contain:
config.json(with anid2labelmap exposing at least one supported NER label:PER/PERSON,LOC/GPE,ORG/ORGANIZATION,NORP/NRP, orFAC)tokenizer.jsonmodel.onnx
Any other files in the directory are ignored — dbmcp reads only these three.
Set up a model locally
The quickest path is to download a model that has already been exported to ONNX. The steps below use the recommended English model, optimum/bert-base-NER — an ONNX export of dslim/bert-base-NER (MIT licensed). It uses CoNLL labels, so it detects PERSON, LOCATION, and ORGANIZATION; protectai/bert-base-NER-onnx is an equivalent alternative. NRP and facility detection require an OntoNotes-class model. The pipeline is model-agnostic — any directory with the three files above works, including multilingual models (see Multilingual and int8 models).
Note: These pre-exported models are full-precision (fp32, ~430 MB). They need no Python toolchain to obtain, but an int8-quantized export is smaller and faster at inference (see Multilingual and int8 models).
1. Download the model into a local directory — either with the Hugging Face CLI (pip install huggingface_hub):
hf download optimum/bert-base-NER \
--include config.json tokenizer.json model.onnx \
--local-dir ./models/bert-ner--include fetches only the three required files and skips the rest.
or with git + Git LFS (the model.onnx weights are LFS-tracked):
git lfs install
git clone https://huggingface.co/optimum/bert-base-NER ./models/bert-neror manually from the browser — open the model's Files and versions tab on Hugging Face and download config.json, tokenizer.json, and model.onnx with the download icon next to each, saving all three into one directory (e.g. ./models/bert-ner).
2. Confirm the required files are present:
ls ./models/bert-ner
# config.json model.onnx tokenizer.json (plus vocab.txt, tokenizer_config.json, … — ignored)3. Start dbmcp with the NER pass enabled, pointing at the directory:
DBMCP_DB_BACKEND=sqlite DBMCP_DB_NAME=app.db \
DBMCP_PII_ENABLE=true DBMCP_PII_NER_ENABLE=true DBMCP_PII_NER_MODEL=./models/bert-ner \
dbmcpor, in a config file (relative paths resolve against the file's directory):
database:
backend: sqlite
name: app.db
pii:
enabled: true
ner_enabled: true
ner_model: ./models/bert-ner4. Verify it loaded. Loading is fail-closed: a missing file or an unusable model makes the server refuse to start, so a clean startup means the model loaded. To confirm the pass is rewriting output, run a readQuery over a column holding a person or place name and check the value comes back as <PERSON> / <LOCATION> (with the default replace operator).
Behaviour notes:
- Fail-closed. If
pii.ner_enabledis true but the model cannot be loaded, the server refuses to start. If inference fails mid-request, that request errors — it never silently falls back to regex-only. - Category-aware. The NER pass respects
pii.categories:PERSON,ORGANIZATION, andNATIONALITY_RELIGION_POLITICSare emitted only whenpersonalis selected;LOCATIONandFACILITYonly whencontactis. With no subset (the default), all apply. When the subset selects neither category, the model is not loaded at all.
Multilingual and int8 models
Any token-classification model exported to ONNX works, in any language. For non-English data, a multilingual model such as Davlan/bert-base-multilingual-cased-ner-hrl (ten languages, CoNLL-style PER / LOC / ORG labels) detects PERSON, LOCATION, and ORGANIZATION. It has no pre-exported ONNX build, so export it with Hugging Face Optimum (pip install "optimum[onnxruntime]"):
optimum-cli export onnx \
--model Davlan/bert-base-multilingual-cased-ner-hrl \
--task token-classification \
./models/bert-ner-multiThe output directory holds config.json, tokenizer.json, and model.onnx, ready for pii.ner_model.
An int8-quantized export runs much faster on CPU: about 3.5× in our test (12 s vs 42 s for ~2k cells). Quantize an exported directory, then rename the result to model.onnx and copy the tokenizer across:
optimum-cli onnxruntime quantize --onnx_model ./models/bert-ner-multi --avx2 -o ./models/bert-ner-multi-int8
mv ./models/bert-ner-multi-int8/model_quantized.onnx ./models/bert-ner-multi-int8/model.onnx
cp ./models/bert-ner-multi/config.json ./models/bert-ner-multi/tokenizer.json ./models/bert-ner-multi-int8/Use --arm64 instead of --avx2 on ARM CPUs. Quantization can cost a little accuracy; check a sample of your data before relying on it.