MAP
← Blog
Technical2026-05-17 · 8 min read

How bdnlp parses Banglish addresses

Bangla addresses are weird. Not because Bangla is weird — because the systems we get from international vendors don't understand any of the conventions a Bangladeshi will type into a search box. Gulshon is Gulshan with a phonetic vowel swap. House 23, Road 11, Banani is structured information, not free text. সড়ক ১১, ধানমন্ডি uses Bangla numerals. hospital near Banani is a POI category query, not a street.

On our benchmark of 30 curated BD queries, plain Nominatim gets 77% Hit@5. Banglish queries: 0%. Landmark phrases: 33%. We get 100% / 75% / 100% by running every query through a normalisation pipeline called bdnlp before it hits Nominatim. Here's how it works.

The pipeline

Six steps. The whole thing is <500 LOC of Go + two YAML data files.

  1. Bangla → ASCII numerals. ১২ → 12. Pre-built map; one pass over the string.
  2. Holding-number parser. Regex matches over House X, Road Y, Block Z, Sector N and the BN equivalents (বাড়ি, সড়ক, ব্লক, সেক্টর).
  3. Landmark detector. Catches preposition tokens (near, কাছে, beside, পাশে) followed by a category (hospital, school, মসজিদ, মাদ্রাসা). Translates Bangla categories to English so Nominatim can match POIs.
  4. Locality matcher. Lowercase + match against 1,400+ curated BD place spellings — Banglish, Bangla, abbreviations. Gulshon → canonical Gulshan.
  5. Variant generation. Build 1–3 alternative queries to fan out to Nominatim. E.g. for "House 23, Road 11, Banani": try the locality alone, the full address, and a variant with the parsed components reordered.
  6. Re-rank. Merge the per-variant results by (osm_type, osm_id). Score each result by how many parsed components match the returned address dict. Sort.

The data

Two embedded YAML files do most of the heavy lifting:

  • places.yaml — 1,407 BD places with their canonical name, Bangla spelling, and known variants. Harvested from OSM + manually curated for the top 200 by population.
  • landmarks.yaml — the preposition + category vocabulary, in both languages, plus a BN→EN translation table for landmark categories.

A typical row:

- canonical: Gulshan
  bangla:    গুলশান
  variants:  [Gulshon, Gulshan-1, Gulshan-2, গুলশন]
- canonical: Dhanmondi
  bangla:    ধানমন্ডি
  variants:  [Dhanmondi R/A, Dhanmondi residential, ধানমণ্ডি]

The benchmark

We test against 30 hand-picked queries spanning Banglish, Bangla, landmark, and holding-number cases. The benchmark is checked into the repo at tools/benchmark/. CI runs it on every PR to internal/bdnlp.

CategoryMAPNominatim rawGoogle
All 30 queries100%77%87%
Banglish phonetics75%0%50%
Bangla script100%83%100%
Landmark phrases67%33%50%
Holding numbers100%100%100%

What we're still bad at

  • Mixed-script abbreviations. Things like "DOHS 4/A রোড 12" — we get the locality right but lose the numbers.
  • Misspelled landmarks. "hospitle" vs "hospital". We don't do fuzzy POI matching yet.
  • Long form addresses with multiple ambiguous tokens. Anything with three or more candidate localities is a coin-flip.

Why we built it ourselves

The honest answer: there's no off-the-shelf normaliser for Bangla addresses. libpostal does international address parsing brilliantly but doesn't know Bangla place names. Indic NLP toolkits target Hindi/Tamil/Telugu, not Bangla addresses. We could have trained a model — but for 30 query categories and ~1,400 places, regex + a lookup table runs in microseconds and is debuggable. The dataset is the moat. The code is straightforward.

The whole pipeline is in the public repo: services/gateway/internal/bdnlp/. PRs welcome — especially for places we missed.