<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged language-models</title>
<link>https://coderlegion.com/tag/language-models</link>
<description>Powered by Question2Answer</description>
<item>
<title>Building NLP Systems for 96 Low-Resource Languages: A Web Scraping War Story</title>
<link>https://coderlegion.com/22837/building-nlp-systems-for-96-low-resource-languages-a-web-scraping-war-story</link>
<description>&lt;h4 id=&quot;or-why-language-vitality-online-has-nothing-to-do-with-speaker-counts-and-everything-to-do-with-data-engineering&quot;&gt;Or why language vitality online has nothing to do with speaker counts — and everything to do with data engineering&lt;/h4&gt;
&lt;p&gt;Russia speaks dozens of minority languages — Tatar, Bashkir, Udmurt, and even tiny ones like South Yukaghir (fewer than 50 speakers). Some have no Wikipedia, no standard corpus, and almost no digital footprint.&lt;/p&gt;
&lt;p&gt;But they &lt;em&gt;do&lt;/em&gt; exist online — scattered across forums, blogs, and VK communities.&lt;/p&gt;
&lt;p&gt;We wanted to measure their online presence. As NLP engineers, we quickly realized: &lt;strong&gt;no global corpus, no labelled dataset, no pre-trained embeddings, and no simple way to ask a search engine &quot;give me all pages in Chechen&quot;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So we built our own pipeline. Here's what every developer building NLP systems for low-resource languages needs to know.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-core-problem-low-resource-nlp-without-a-dictionary&quot;&gt;The Core Problem: Low-Resource NLP Without a Dictionary&lt;/h3&gt;
&lt;p&gt;In mainstream NLP, you start with a corpus. Wikipedia. Common Crawl. Something.&lt;/p&gt;
&lt;p&gt;For 96 minority languages, &lt;strong&gt;the corpus doesn't exist&lt;/strong&gt;. You have to find the data first — before you can even think about training embeddings, fine-tuning BERT, or building a translation system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is the ultimate cold-start problem.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Every stage of a standard NLP pipeline breaks:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;NLP Stage &lt;/th&gt;&lt;th&gt;The Problem&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Data Acquisition&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;No central repository. Data is scattered across VK, forums, blogs.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Language Identification&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;No pre-trained classifier for 90% of these languages.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Tokenization&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;No standard orthography. People type without diacritics.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Embeddings&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;No pre-trained word vectors. You must build from scratch.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Evaluation&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;No gold-standard test sets. You can't measure what you can't label.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-1-data-acquisition-the-search-api-as-your-crawler&quot;&gt;Step 1: Data Acquisition — The Search API as Your Crawler&lt;/h3&gt;
&lt;p&gt;You can't download the whole internet (unless you're Google). But search engines already crawled it.&lt;/p&gt;
&lt;p&gt;We used &lt;strong&gt;Yandex.XML&lt;/strong&gt; — a limited API with &lt;strong&gt;10,000 requests per day&lt;/strong&gt;. Each request returns one page of results, and each &lt;em&gt;next&lt;/em&gt; page costs another request.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For an engineer, this means:&lt;/strong&gt; you have to be &lt;em&gt;extremely&lt;/em&gt; efficient with your queries.&lt;/p&gt;
&lt;h4 id=&quot;the-challenge-what-do-you-search-for-&quot;&gt;The challenge: What do you search for?&lt;/h4&gt;
&lt;p&gt;We needed &lt;strong&gt;word markers&lt;/strong&gt; — words that are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Frequent&lt;/strong&gt; in the target language&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unique&lt;/strong&gt; — not appearing in Russian or other languages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Free of special characters&lt;/strong&gt; — because real users don't type them&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That last point is &lt;strong&gt;critical for any NLP system dealing with real-world user-generated content.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Most minority languages use Cyrillic extensions: &lt;code&gt;ҙ&lt;/code&gt;, &lt;code&gt;ә&lt;/code&gt;, &lt;code&gt;ö&lt;/code&gt;, &lt;code&gt;ҷ&lt;/code&gt;. There's no standard keyboard for them. People write &lt;code&gt;&quot;менан&quot;&lt;/code&gt; instead of &lt;code&gt;&quot;менән&quot;&lt;/code&gt;. If we query with the &quot;correct&quot; spelling, we lose 90% of real texts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We call this &quot;household spelling&quot;&lt;/strong&gt; — like medieval birch-bark manuscripts, but with modern laziness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For your NLP pipeline:&lt;/strong&gt; If you're building systems for languages without standard keyboards, you need &lt;strong&gt;fuzzy matching&lt;/strong&gt; at the query stage, not just at the evaluation stage. This means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Levenshtein-based query expansion&lt;/li&gt;
&lt;li&gt;Phonetic normalization&lt;/li&gt;
&lt;li&gt;Handling diacritic stripping before search&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-2-noise-filtering-the-precision-problem&quot;&gt;Step 2: Noise Filtering — The Precision Problem&lt;/h3&gt;
&lt;p&gt;Even good markers return junk. We had to filter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Wikipedia duplicates&lt;/strong&gt; — we can download those in one click, so exclude them&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linguistic papers&lt;/strong&gt; — Russian text containing one line of Rutul as an example&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Music sites&lt;/strong&gt; — song titles but no lyrics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typos&lt;/strong&gt; — e.g., Russian &lt;code&gt;&quot;пазух&quot;&lt;/code&gt; (bosom) mistyped as &lt;code&gt;&quot;пазох&quot;&lt;/code&gt;, which is a valid Khakas word meaning &quot;again&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;the-solution-multi-marker-verification&quot;&gt;The solution: Multi-marker verification&lt;/h4&gt;
&lt;p&gt;If one marker appears on a domain but others from the same language don't — it's probably a false positive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For your ML pipeline:&lt;/strong&gt; This is &lt;strong&gt;ensemble validation&lt;/strong&gt; — using multiple weak signals to confirm a strong one. The trade-off is extra API calls, which are expensive at 10k/day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Alternative approach:&lt;/strong&gt; Train a binary classifier (Russian vs. everything else) on the fly. We did this later — more on that below.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-3-domain-classification-building-a-tiered-index&quot;&gt;Step 3: Domain Classification — Building a Tiered Index&lt;/h3&gt;
&lt;p&gt;We asked Yandex to categorize each domain into three tiers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Tier &lt;/th&gt;&lt;th&gt;Description &lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;1. Language-first&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Most pages in the minority language &lt;/td&gt;&lt;td&gt;Small blogs, community sites&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;2. Mixed&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Several pages, but not dominant &lt;/td&gt;&lt;td&gt;Regional news portals&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;3. Giant platforms&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Minority content is buried &lt;/td&gt;&lt;td&gt;YouTube, stihi.ru&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Additionally, we specifically queried &lt;strong&gt;VK.com&lt;/strong&gt; communities because post-2012, most standalone language sites died — and everything moved to social networks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For your data engineering pipeline:&lt;/strong&gt; You need a &lt;strong&gt;stratified crawling strategy&lt;/strong&gt;. Don't treat all domains equally. Allocate more budget to Tier 1, and use depth-limited sampling for Tier 3.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;step-4-language-detection-without-a-training-corpus&quot;&gt;Step 4: Language Detection Without a Training Corpus&lt;/h3&gt;
&lt;p&gt;We downloaded pages and needed to separate Russian from, say, Tuvan.&lt;/p&gt;
&lt;p&gt;Classic n-gram language detection requires a pre-labelled corpus — which we didn't have for most languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt; We &lt;em&gt;did&lt;/em&gt; have Russian — plenty of it. So we built a &lt;strong&gt;binary classifier&lt;/strong&gt;: &lt;em&gt;Russian vs. everything else&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If a paragraph isn't Russian, we assume it's our target language.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For your ML system:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This is a &lt;strong&gt;one-class classification&lt;/strong&gt; problem with a twist.&lt;/li&gt;
&lt;li&gt;It's not perfect — but it's good enough to build the &lt;strong&gt;first ever web corpora&lt;/strong&gt; for these languages.&lt;/li&gt;
&lt;li&gt;This is a classic &lt;strong&gt;weak supervision&lt;/strong&gt; approach: use what you have (Russian) to learn what you don't (everything else).&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-we-learned-online-vs-offline-zero-correlation&quot;&gt;What We Learned: Online vs. Offline — Zero Correlation&lt;/h3&gt;
&lt;p&gt;We compared online metrics (Wikipedia articles, VK communities, text volume) with offline metrics (speaker count, regional economy).&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Metric Pair &lt;/th&gt;&lt;th&gt;Correlation&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Among online metrics &lt;/td&gt;&lt;td&gt;&lt;strong&gt;&amp;gt;0.7&lt;/strong&gt; (Spearman)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Online vs. offline &lt;/td&gt;&lt;td&gt;&lt;strong&gt;≈ 0&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;This is the key insight for anyone building IT systems for low-resource languages:&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;How many people speak a language &lt;strong&gt;does not predict&lt;/strong&gt; how alive it is on the internet.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What matters is a &lt;strong&gt;small, active, passionate community&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Bashkir has fewer speakers than Chechen, but far more online communities. Why?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chechnya's internet infrastructure recovered later (1990s-2000s conflicts delayed digital adoption).&lt;/li&gt;
&lt;li&gt;Online activity is a function of &lt;strong&gt;infrastructure&lt;/strong&gt;, not just population.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For your product strategy:&lt;/strong&gt; If you're building a language model for a low-resource language, prioritize communities, not census data. Find the VK groups, Discord servers, and Telegram channels. That's where the data lives.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;a-few-geeky-findings&quot;&gt;A Few Geeky Findings&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Finding &lt;/th&gt;&lt;th&gt;Implication&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Post-2012 shift&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Almost all minority language activity moved to VK.com. Standalone forums died.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Typical user&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;19-31 years old, lives in the region's capital (Ufa for Bashkir, Izhevsk for Udmurt).&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Typical post length&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;&lt;strong&gt;~5 words&lt;/strong&gt; per post in minority language. Most conversation is in Russian; people sprinkle native words as identity markers.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Interconnectivity&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Minority language sites link to each other across language families. A rare case of &quot;peoples united&quot; online.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;For your NLP models:&lt;/strong&gt; If you're building embeddings from this data, expect &lt;strong&gt;sparse, short texts&lt;/strong&gt;. Standard word2vec on 5-word posts won't work well. Consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Character-level embeddings&lt;/strong&gt; (more robust to spelling variation)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-lingual transfer&lt;/strong&gt; (use Russian or English as a bridge)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero-shot approaches&lt;/strong&gt; (label propagation from related languages)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-data-engineering-pipeline-summary&quot;&gt;The Data Engineering Pipeline — Summary&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;┌─────────────────┐
│  Yandex.XML API │  ← 10k requests/day budget
│  (search engine)│
└────────┬────────┘
         ▼
┌─────────────────┐
│  Word Markers   │  ← Frequent + Unique + No diacritics
│  (handcrafted)  │  ← &quot;Household spelling&quot; handling
└────────┬────────┘
         ▼
┌─────────────────┐
│  Domain Filter  │  ← Remove Wikipedia, linguistic papers
│  (multi-marker) │  ← Ensemble validation
└────────┬────────┘
         ▼
┌─────────────────┐
│  Tiered Index   │  ← Language-first, Mixed, Giant platforms
│  (stratified)   │  ← VK.com special treatment
└────────┬────────┘
         ▼
┌─────────────────┐
│  Binary Class.  │  ← Russian vs. everything else
│  (weak super.)  │  ← No pre-labelled corpus needed
└────────┬────────┘
         ▼
┌─────────────────┐
│  Web Corpora    │  ← First ever for these languages
│  (downloadable) │  ← Available at web-corpora.net
└─────────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-data&quot;&gt;The Data&lt;/h3&gt;
&lt;p&gt;Downloadable corpora and domain lists:&lt;br&gt;
&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;http://web-corpora.net/wsgi3/minorlangs/download&quot;&gt;web-corpora.net/wsgi3/minorlangs/download&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;And yes, there's a VK community with cute memes in minority languages — featuring cats.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;the-bottom-line-for-engineers&quot;&gt;The Bottom Line for Engineers&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;Web scraping isn't just about avoiding &lt;code&gt;robots.txt&lt;/code&gt;. It's about understanding human behaviour — typos, keyboard limitations, social network migration, and why a language with 50 speakers can thrive online if those 50 are determined enough.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key takeaways for building NLP systems for low-resource languages:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Start with search APIs, not crawlers.&lt;/strong&gt; The internet is already indexed. Use it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle real-world spelling.&lt;/strong&gt; People don't use diacritics. Your queries shouldn't either.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use weak supervision.&lt;/strong&gt; You don't need a labelled corpus to start — use what you have.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prioritize communities, not speakers.&lt;/strong&gt; Online vitality ≠ offline speaker count.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Expect short texts.&lt;/strong&gt; ~5-word posts are the norm. Plan your embeddings accordingly.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;Further reading:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Our downloadable corpora: &lt;a rel=&quot;nofollow&quot; href=&quot;http://web-corpora.net/wsgi3/minorlangs/download&quot;&gt;web-corpora.net&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Yandex.XML API documentation&lt;/li&gt;
&lt;li&gt;VK.com API for social media data extraction&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Liked this? Share with your NLP engineering team. They'll never look at &quot;low-resource&quot; the same way again.&lt;/em&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/22837/building-nlp-systems-for-96-low-resource-languages-a-web-scraping-war-story</guid>
<pubDate>Thu, 06 Aug 2026 16:21:00 +0000</pubDate>
</item>
</channel>
</rss>