Инженерлік блог

Алматы кептелістері vs BigQuery: Біз 1 000 000 курьер бағдарын қалай талдап, локальді жарнаманы оңтайландырдық

12.08.2026
Шарафутдинов Р.

Жұма. Кешкі сағат 19:00. Алматы, Әл-Фараби даңғылы қып-қызыл болып тұр. Жүргізушілер рульді ұрып, Яндекс Картаға қарап, күрсінумен уақыт өткізуде. Дәл осы сәт — жарнама берушілер үшін алтын уақыт. Неге? Өйткені адамның назары 100% бос, ал оның геолокациясы келесі 40 минут бойы өзгермейді. Осы бос уақытты аудиокітаптарға, жақын маңдағы мейрамханалардан тамаққа тапсырыс беруге немесе стресске қарсы қосымшаларға бағыттасақ қайтеді?

Бүгін біз Google Cloud (BigQuery GIS, Pub/Sub) көмегімен қаладағы миллиондаған координаттарды қалай талдап, «кептеліс полигондарын» нақты уақытта қалай тұрғызғанымызды және осы деректерді банерлік жарнаманы (Google Publisher Tag арқылы) 300%-ға дейін тиімдірек ету үшін қалай қолданғанымызды архитектуралық деңгейде талдаймыз.

Архитектура: Координаттар хаосынан нақты полигондарға дейін

Бізде серіктес курьерлік қызметтен (иә, сол сары және жасыл сөмкелері бар жігіттер) келетін үздіксіз гео-деректер ағыны бар. Олардың қолданбасы әр 10 секунд сайын MQTT арқылы локацияны жіберіп отырады. Бұл дегеніміз — секундына мыңдаған оқиғалар (events).

Егер біз мұның бәрін тікелей дерекқорға (PostgreSQL) жазатын болсақ, база бірнеше минут ішінде өліп қалады. Сондықтан біз серверсіз (serverless) ағындық архитектураны таңдадық.

1-қадам: Pub/Sub және Dataflow арқылы деректерді қабылдау

Барлық координаттар Google Cloud Pub/Sub топигіне түседі. Бұл біздің амортизаторымыз. Ол секундына миллиондаған хабарламаларды ешқандай баптаусыз-ақ қабылдай алады.

Pub/Sub-тан деректерді оқу үшін біз Cloud Dataflow (Apache Beam) құбырын (pipeline) көтердік. Оның міндеті — «қоқысты» тазарту: GPS секірулерін (аномалияларды) алып тастау, деректерді байыту (мысалы, H3 хэштерін қосу) және оларды сақтауға жіберу.

# Dataflow (Apache Beam) құбырының фрагменті
import apache_beam as beam
import json

def parse_and_clean_gps(message):
    data = json.loads(message)
    # GPS аномалияларын сүзу (мысалы, Қапшағайдағы нүктелерді алып тастау)
    if 43.0 < data['lat'] < 43.6 and 76.6 < data['lon'] < 77.2:
        yield data

(p 
 | 'ReadFromPubSub' >> beam.io.ReadFromPubSub(subscription='projects/ozat-kz/subscriptions/gps-sub')
 | 'CleanData' >> beam.FlatMap(parse_and_clean_gps)
 | 'WriteToBigQuery' >> beam.io.WriteToBigQuery(
       table='ozat-kz:traffic_dataset.raw_gps',
       create_disposition=beam.io.BigQueryDisposition.CREATE_NEVER,
       write_disposition=beam.io.BigQueryDisposition.WRITE_APPEND
   )
)

GitHub-тағы кодты көру (OZAT-kz)

2-қадам: BigQuery GIS — Кептелістерді табу магиясы

Сонымен, бізде raw_gps кестесінде миллиондаған нүктелер бар. Енді ең қызықтысы басталады. Бізге жай ғана нүктелер емес, кептеліс полигондары (аудандары) қажет.

Біз BigQuery GIS (Geographic Information Systems) функцияларын қолданамыз. Бұл — геометриялық есептеулерді SQL арқылы петабайт деректерге секундтар ішінде жасауға мүмкіндік беретін құрал.

Логика келесідей: 1. Біз соңғы 5 минуттағы курьерлердің жылдамдығын есептейміз (егер ол 15 км/сағ-тан төмен болса — ол кептелісте). 2. Осындай "баяу" нүктелерді бір-бірінен 50 метр радиуста болса, ST_CLUSTERDBSCAN функциясы арқылы кластерлерге біріктіреміз. 3. Содан кейін осы кластерленген нүктелердің үстінен виртуалды полигон сызамыз (ST_CONVEXHULL).

-- Кептеліс полигонын құру SQL сұрауы
SELECT
  ST_CONVEXHULL(ST_UNION_AGG(geo_point)) as traffic_jam_polygon,
  COUNT(DISTINCT courier_id) as stuck_couriers_count
FROM clustered_data
WHERE cluster_id IS NOT NULL
GROUP BY cluster_id;

GitHub-тағы кодты көру (OZAT-kz)

Бұл процесс әр 3 минут сайын қайталанады!

Клиентпен синхрондау: Полигондарды қолданбаға жеткізу

BigQuery-де кептелістерді есептеу — керемет. Бірақ дәл қазір телефонда қолданбаны ашып отырған пайдаланушының осы полигонның ішінде екенін қалай білеміз?

Мобильді қолданбадан тікелей BigQuery-ге сұрау жасауға болмайды — бұл өте баяу (2-3 секунд) және өте қымбат. Сондықтан біз әр 3 минут сайын BigQuery-ден өзекті кептеліс полигондарын алып, оларды Redis (Cloud Memorystore)-ға салатын Cloud Function орнаттық.

Пайдаланушы біздің қолданбаны (немесе жарнамамыз бар сайтты) ашқан кезде, біз оның GPS координаттарын аламыз (әрине, рұқсатымен) және Golang-та жазылған микросервисімізге өте жылдам сұрау жасаймыз. Микросервис нүктенің жадтағы полигондармен қиылысуын (Point-in-Polygon) небәрі 1 миллисекундта тексереді.

AdTech: Google Publisher Tag арқылы динамикалық таргетинг

Ендігі кезек — монетизация. Біз Google Ad Manager-мен интеграцияланғанбыз. Әдетте жарнама желісі не көрсету керектігін өзі шешеді. Бірақ біз оған Google Publisher Tag (GPT) кітапханасындағы Key-Value Targeting (Кілт-мән таргетингі) технологиясы арқылы көмектесе аламыз.

Егер біздің микросервис пайдаланушының кептелісте екенін (isInJam: true) деген жауап қайтарса, біз гуглдан баннер сұрамас БҰРЫН жарнамалық слотқа параметрді динамикалық түрде қосамыз.

// Қосымшадағы/сайттағы клиенттік код
// GPT + React интеграциясының толық мысалын GitHub-тан іздеңіз

async function initAds(userLat, userLon) {
  // 1. Біздің кептеліс кэшімізді жылдам тексереміз
  const trafficStatus = await checkTrafficJam(userLat, userLon); 
  
  window.googletag = window.googletag || {cmd: []};
  googletag.cmd.push(function() {
    var slot = googletag.defineSlot('/1234567/almaty_app_banner', [300, 250], 'div-gpt-ad-123')
      .addService(googletag.pubads());

    // 2. ҚҰПИЯ ИНГРЕДИЕНТ: Кептеліс контекстін Ad Manager-ге береміз
    if (trafficStatus.isInJam) {
      slot.setTargeting('context', 'traffic_jam');
      slot.setTargeting('jam_severity', trafficStatus.severity); // e.g. '10_points'
    } else {
      slot.setTargeting('context', 'moving');
    }

    googletag.enableServices();
    googletag.display('div-gpt-ad-123');
  });
}

GitHub-тағы кодты көру (OZAT-kz)

Google Ad Manager интерфейсінің өзінде біздің Trafficking-мамандарымыз (жарнамашылар) арнайы премиум науқандар (Line Items) жасады. Бұл науқандар ТЕК context=traffic_jam болған жағдайда ғана белсендіріледі. Жарнама берушілер (аудиокітап сервистері, онлайн-кинотеатрлар, аудандағы жергілікті мейрамханалар) бұл көрсетілімдер үшін бізге жоғары CPM төлейді, өйткені конверсияның жынды болатынын біледі.

Нәтижелер: А/В Тестілеу және Метрикалар

Біз 1 айға А/В тест іске қостық. Кептелісте тұрған пайдаланушылардың жартысына біз кәдімгі жарнама (Random) көрсеттік. Қалған жартысына — таргетингтелген "кептеліс" жарнамасын (Audiobooks, Food Pickup, Anti-stress apps) көрсеттік.

  • CTR (Click-Through Rate): Көңілсіз 1.2%-дан пиктік сағаттарда (18:00 - 20:00) сенгісіз 4.5%-ға дейін өсті.
  • eCPM (1000 көрсетілімнің тиімді құны): 210%-ға өсті. Жарнама берушілер біздің "қамалған" аудиториямыз үшін аукционда соғыса бастады.
  • User Feedback: Қызығы, негатив азайды. Адамдар саппортқа былай деп жазды: «Сіздердің аудиоспектакль жарнамаларыңыз мені Сайын/Жандосовтағы жүйке жұқаруынан құтқарды». Релевантты жарнама контент ретінде қабылданады.

Кептелісте тұрған және қарапайым пайдаланушылар арасындағы аудиокітаптар мен фастфуд жарнамасының басылу жиілігін (CTR) салыстыру.

Қорытындылар

Гео-деректер — бұл жаңа мұнай. Бірақ шикі мұнай сіздің көлігіңізге май құймайды. Google Cloud Pub/Sub және BigQuery GIS сияқты құралдар миллиондаған координаталардың хаосынан мағына шығаруға мүмкіндік беретін сол мұнай өңдеу зауыты болып табылады.

Терең бэкенд-аналитиканы (Data Engineering) фронтенд-монетизация технологияларымен (AdTech / GPT) біріктіру Қазақстандағы мобильді қосымшалар мен веб-сайттардан ақша табу үшін мүлдем жаңа тауашалар ашады.

Сөз арзан, ал код мәңгілік екенін ұмытпаңыз. Егер сізде архитектура бойынша сұрақтар болса немесе интеграцияны талқылағыңыз келсе — сіздерді түсініктемелерде күтеміз.

Рустам Шарафутдинов

Рустам Шарафутдинов

Инженерлік блог авторы

Google Cloud архитектурасы саласындағы сарапшы және 15 жылдан астам тәжірибесі бар Senior Full-Stack әзірлеушісі. Ақауға төзімді архитектураларға, жоғары жүктемелі жобаларды оңтайландыруға және AI (Vertex AI) интеграциясына маманданған.

Сараптама: GCP, Kubernetes, Микросервистер, React, Node.js

Пікірлер (0)