<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dmitrii Kuznetsov</title>
    <description>The latest articles on DEV Community by Dmitrii Kuznetsov (@dmitrii-kuznetsov).</description>
    <link>https://dev.to/dmitrii-kuznetsov</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4191369%2Feb50fd45-4afc-47dd-882b-7f7dbabab031.jpg</url>
      <title>DEV Community: Dmitrii Kuznetsov</title>
      <link>https://dev.to/dmitrii-kuznetsov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dmitrii-kuznetsov"/>
    <language>en</language>
    <item>
      <title>The painful reality of geocoding real estate data where street addresses don't exist</title>
      <dc:creator>Dmitrii Kuznetsov</dc:creator>
      <pubDate>Mon, 19 Oct 2026 10:07:17 +0000</pubDate>
      <link>https://dev.to/dmitrii-kuznetsov/the-painful-reality-of-geocoding-real-estate-data-where-street-addresses-dont-exist-1nkn</link>
      <guid>https://dev.to/dmitrii-kuznetsov/the-painful-reality-of-geocoding-real-estate-data-where-street-addresses-dont-exist-1nkn</guid>
      <description>&lt;p&gt;When we started mapping property developments across Cambodia, Thailand, and Bali for &lt;a href="https://novasia.estate/en/" rel="noopener noreferrer"&gt;NovAsia&lt;/a&gt;, I assumed the location pipeline would be the easiest part of our stack.&lt;/p&gt;

&lt;p&gt;The mental model was simple:&lt;/p&gt;

&lt;p&gt;Extract the address string from the developer sheet.&lt;/p&gt;

&lt;p&gt;Send it to Google Maps Geocoding API or Nominatim.&lt;/p&gt;

&lt;p&gt;Save (lat, lng) into a PostGIS column.&lt;/p&gt;

&lt;p&gt;Render pretty map pins on the frontend.&lt;/p&gt;

&lt;p&gt;If you’ve only built location features for cities like London, New York, or Berlin, this works out of the box.&lt;/p&gt;

&lt;p&gt;If you try running that same pipeline on emerging Southeast Asian markets, it fails instantly. Here is what broke, and how we had to rebuild our spatial data ingestion from scratch.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The address structure doesn't follow Western logic
In Western markets, an address is a neat hierarchy: Number → Street → City → Zip Code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Cambodia and Thailand, addresses are often descriptive, administrative, or relational:&lt;/p&gt;

&lt;p&gt;District-level fallback: An address like "Street 288, Sangkat Boeng Keng Kang 1, Khan Boeng Keng Kang, Phnom Penh" often causes standard geocoding APIs to shrug and drop the pin directly in the geographic center of the district (sometimes 2 km away from where the actual tower is being built).&lt;/p&gt;

&lt;p&gt;The "Moo" system in Thailand: In coastal markets like Phuket or Pattaya, rural administrative divisions (Moo 5, Tambon Choeng Thale) cover huge geographic areas. A geocoder will happily drop a beachfront condominium pin in the middle of an inland rubber plantation 5 miles away.&lt;/p&gt;

&lt;p&gt;Landmark-based directions: Many legal documents literally identify a plot as "200m south of the pagoda, opposite the market."&lt;/p&gt;

&lt;p&gt;Off-plan projects have no street address yet: When a developer breaks ground on a 40-story residential tower, the municipal street number often doesn't exist yet. The project exists only as a plot boundary on a master development plan.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Transliteration phonetic traps
The same district or road name is routinely spelled three different ways depending on who translated the Khmer or Thai script into the Latin alphabet:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Boeng Keng Kang vs. BKK vs. Beng Keng Kang&lt;/p&gt;

&lt;p&gt;Na Kluea vs. Naklua&lt;/p&gt;

&lt;p&gt;Rawai vs. Rawei&lt;/p&gt;

&lt;p&gt;If you do naive string matching against address catalogs, you get duplicate entries, fragmented databases, and orphan records.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What we actually built to fix it
Throwing expensive API calls at bad strings didn't work. We had to redesign our spatial ingestion into a three-step pipeline:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step A: Hierarchical fuzzy matching with local aliases&lt;br&gt;
Before geocoding, we pass raw location strings through a normalization step in Python. We maintain an open dictionary of administrative units (Provinces → Districts/Khans → Communes/Sangkats) mapped to their common phonetic variations and common acronyms. We use Levenshtein distance thresholds to lock down the exact administrative boundary first.&lt;/p&gt;

&lt;p&gt;Step B: Polygon boundaries over single coordinate points&lt;br&gt;
Instead of relying on single (lat, lng) points, we store development parcels as spatial polygons in PostGIS. For off-plan developments, our pipeline pulls the cadastral plot coordinates directly from planning permission filings and developer master plans. A polygon gives us verifiable bounds; a single geocoded point is almost always slightly wrong.&lt;/p&gt;

&lt;p&gt;Step C: Heuristic sanity checks&lt;br&gt;
We wrote automated spatial validation rules to catch geocoder hallucinations before data hits production. For example:&lt;/p&gt;

&lt;p&gt;If a condominium is tagged as "beachfront" in Pattaya or Phuket, but the PostGIS query calculates the distance to the coastline polygon as &amp;gt; 400 meters, the record is automatically flagged for manual review.&lt;/p&gt;

&lt;p&gt;If a project in Phnom Penh has coordinates outside the municipal city boundary polygon, the ingestion job fails loudly instead of silently committing bad coordinates.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;br&gt;
If you're building location-heavy products in non-standardized regions, don't treat geocoding APIs as a silver bullet.&lt;/p&gt;

&lt;p&gt;High-accuracy spatial search rarely comes from the API itself—it comes from building your own phonetic normalization layers and treating geographic validation with the same strictness you would apply to financial transactions.&lt;/p&gt;

&lt;p&gt;Curious how other folks handle messy spatial data and non-standard addresses in emerging markets—what does your pipeline look like?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>database</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Why parsing real estate contracts with LLMs is ten times harder than tutorials claim</title>
      <dc:creator>Dmitrii Kuznetsov</dc:creator>
      <pubDate>Sun, 18 Oct 2026 04:52:15 +0000</pubDate>
      <link>https://dev.to/novasiaestate/why-parsing-real-estate-contracts-with-llms-is-ten-times-harder-than-tutorials-claim-4pak</link>
      <guid>https://dev.to/novasiaestate/why-parsing-real-estate-contracts-with-llms-is-ten-times-harder-than-tutorials-claim-4pak</guid>
      <description>&lt;p&gt;When we started building the data pipeline for &lt;a href="https://novasia.estate/en/" rel="noopener noreferrer"&gt;NovAsia&lt;/a&gt; (a property catalog and market tool for Southeast Asia), the plan looked embarrassingly simple on paper:&lt;/p&gt;

&lt;p&gt;Grab property PDFs and developer contracts (SPAs).&lt;/p&gt;

&lt;p&gt;Run them through a modern vision LLM.&lt;/p&gt;

&lt;p&gt;Dump structured JSON into PostgreSQL.&lt;/p&gt;

&lt;p&gt;Call it a day.&lt;/p&gt;

&lt;p&gt;Two weeks in, the pipeline was completely broken. Here is why standard tutorial advice fell apart in production, and what we had to change to get reliable data out of scanned documents.&lt;/p&gt;

&lt;p&gt;The stuff tutorials don't warn you about&lt;br&gt;
Most LLM document parsing demos use crisp, born-digital PDFs with clean typography. In emerging markets like Cambodia and Thailand, reality looks very different:&lt;/p&gt;

&lt;p&gt;Phone scans: Half the documents are multi-generation scans or photos taken with a phone camera under uneven lighting.&lt;/p&gt;

&lt;p&gt;Dual-language layout: Khmer or Thai text mixed with English, often in adjacent table columns where line baselines don't match.&lt;/p&gt;

&lt;p&gt;Physical stamps: Red rubber stamps, signatures, and notary seals placed directly over critical numbers (payment milestone dates, sinking fund fees, transfer taxes).&lt;/p&gt;

&lt;p&gt;The 40-page prompt trap: If you shove a 35-page PDF into a long-context model and ask for "all fees and payment dates", it will extract 80% correctly and quietly hallucinate the rest with total confidence.&lt;/p&gt;

&lt;p&gt;Three practical changes that fixed it&lt;br&gt;
Instead of trying to find one magic model that does everything, we broke the pipeline down into smaller, boring steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Aggressive image cleanup before text extraction&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before any model sees the page, we run basic OpenCV passes: deskewing, binarization, and contrast normalization. Removing phone-scan shadows did more for extraction accuracy than upgrading to a larger model tier.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Section-level chunking with rigid schema validation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We stopped asking the model to parse whole documents at once. We chunk by specific section (e.g., "Schedule of Payments", "Maintenance Obligations") and enforce strict Pydantic schemas. If a field fails validation or falls outside expected bounds, the pipeline flags it for manual check rather than guessing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Treating tables and narrative text as separate problems&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vision models are great at answering qualitative questions ("under what conditions is the deposit refundable?"), but notoriously sloppy with columns in financial tables. We split table extraction into dedicated passes with explicit row-by-row checks.&lt;/p&gt;

&lt;p&gt;The takeaway&lt;br&gt;
If you're building with LLMs on messy, physical-world paperwork, raw context window size won't save you. Most of the reliability comes from image hygiene and strict schema boundaries.&lt;/p&gt;

&lt;p&gt;Happy to trade notes if anyone else here is wrestling with noisy scans and table extraction.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>webscraping</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
