B2B Marketplace Django · PostgreSQL · GIN SEO · Yandex · 11M records

B2B-маркетплейс: SEO-инфраструктура и поиск для базы 11+ миллионов компаний

Федеральная промышленная платформа РОСИНДАСТРИ: данные ЕГРЮЛ, 580+ региональных поддоменов, 1,701 сайт в Яндекс.Вебмастер. Поиск с 15 секунд до 10ms — на полной базе.

11.4 M
компаний из ЕГРЮЛ в базе платформы
10 ms
время поиска по 400K товаров после GIN
1 701 sites
поддоменов верифицировано в Яндекс.Вебмастер
1 187 files
sitemap-файлов, 1.86 GB, полный краулинг
Контекст
Федеральная B2B-платформа РОСИНДАСТРИ (rosindustry.pro): 11.4 млн компаний из ЕГРЮЛ, 398K товаров, 580+ городских/региональных поддоменов. Стек: Django + PostgreSQL, Celery, Яндекс OAuth, Yandex Webmaster API.
Django · PostgreSQL ЕГРЮЛ 11.4M Роспатент
Проблема
ORM-поиск по 400K товарам — 8–15 секунд: неприемлемо. 580+ поддоменов не верифицированы в Яндекс.Вебмастер — органический трафик заблокирован. Дублирование контента без canonical → SEO-штраф.
8–15s search 0 verified domains canonical missing
Масштаб платформы
Цифры инфраструктуры, с которой работали
Каждый показатель — отдельная инженерная задача: импорт, хранение, индексация, краулинг
Компании ЕГРЮЛ
11 400 000
записей · bulk import · PostgreSQL
Товары
398 000
позиций · GIN trigram index
PersonProfile
7 500 000
профилей · claim/verification flow
Поддомены
580+
городских и региональных сайтов
Sitemap-файлы
1 187
файлов · 1.86 GB · статическая генерация
Яндекс.Вебмастер
1 701
сайтов верифицировано через API
Fix 1 — Поиск по товарам
GIN trigram + raw ILIKE вместо ORM-поиска
ORM генерировал LIKE '%query%' без индекса — seq scan по 400K строк. GIN + raw SQL дал ×1200 ускорение
perf: before
8–15 sec
Время ответа · поиск по 400K товаров
ORM .filter
~12 000 ms
raw ILIKE
~10 ms
GIN trigram index: seq scan → index scan · ускорение ×1200
До — ORM LIKE без индекса
# products/views.py — медленно def search_products(query): # ❌ ORM → LIKE '%query%' # ❌ seq scan по 400K строк return Product.objects\ .filter( name__icontains=query )\ .select_related('company') # → 8–15 секунд на prod
После — raw SQL + GIN index
# products/search.py — быстро from django.db import connection def search_products(query): with connection.cursor() as cur: cur.execute(""" SELECT id, name, company_id FROM products_product WHERE name ILIKE %s LIMIT 50 """, [f'%{query}%']) return cur.fetchall() # → ~10ms благодаря GIN index
PostgreSQL — GIN trigram index
-- Включаем расширение pg_trgm CREATE EXTENSION IF NOT EXISTS pg_trgm; -- GIN индекс на поле name CREATE INDEX CONCURRENTLY idx_product_name_trgm ON products_product USING GIN (name gin_trgm_ops); -- EXPLAIN ANALYZE подтверждает: -- Seq Scan → Bitmap Index Scan -- cost: 24800 → 18 rows: 400K → 50
Fix 2 — Яндекс.Вебмастер API
Автоматическая верификация 1,701 поддомена
Ручная верификация 580+ сайтов невозможна — написан скрипт с OAuth и батч-запросами к Webmaster API
seo blocker
0 verified
Проблема — ни один сайт не верифицирован
# 580+ поддоменов вида: # moscow.rosindustry.pro # spb.rosindustry.pro # novosibirsk.rosindustry.pro # ❌ ни один не верифицирован # ❌ Яндекс не индексирует # ❌ органический трафик = 0 # ручная верификация: ~3 мин/сайт # × 1701 = ~85 часов работы
Решение — Webmaster API batch
# yandex_webmaster.py import requests def verify_all_subdomains(token, domains): session = requests.Session() session.headers['Authorization'] = \ f'OAuth {token}' verified = 0 for domain in domains: r = session.post( f"{API}/user/{USER}/hosts", json={"name": domain} ) if r.status_code == 200: verified += 1 return verified # → 1701
Fix 3 — Sitemap + Canonical
1,187 статических sitemap-файлов и canonical для всех регионов
Динамическая генерация не масштабировалась — написан генератор статических файлов пачками по 50,000 URL
seo
crawling
sitemap_generator.py — статика
# Генерация пачками по 50K URL CHUNK = 50_000 def generate_sitemaps(domain, qs): total = qs.count() files = [] for i, offset in enumerate( range(0, total, CHUNK) ): chunk = qs[offset:offset+CHUNK] fname = f"sitemap-{domain}-{i}.xml" write_xml(fname, chunk) files.append(fname) write_index(f"sitemap-{domain}.xml", files) return len(files) # → 1187 total
Django template — canonical тег
{# base.html — устранение дублей #} <!-- Без canonical: 580 копий --> {# ❌ каждый поддомен = дубль #} {# Яндекс штрафует за дублирование #} <!-- С canonical: один источник --> <link rel="canonical" href="https://rosindustry.pro {{ request.path }}"> {# ✓ все регионы → главный домен #} {# ✓ SEO-вес консолидирован #} {# ✓ дублирование устранено #}
Реализованные решения: ✓ GIN trigram index ✓ ×1200 поиск ✓ 1701 сайт верифицирован ✓ canonical теги ✓ 1187 sitemap файлов
Live ✓
Результат
Поиск работает в реальном времени на базе 11.4 млн записей. Все региональные поддомены верифицированы и открыты для индексации. 1,187 sitemap-файлов обеспечивают полный краулинг. Платформа зарегистрирована как программное обеспечение в Роспатенте.
Django
PostgreSQL · GIN trigram
pg_trgm
Yandex Webmaster API
ЕГРЮЛ · bulk import
Celery
Роспатент · ПО

Есть задача? Давайте разберём её

Расскажите что происходит — мы скажем можем ли помочь и как это выглядит по деньгам и срокам. Без обязательств.