Changes between Version 7 and Version 8 of AdvancedConcepts


Ignore:
Timestamp:
06/15/26 21:33:09 (14 hours ago)
Author:
231093
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • AdvancedConcepts

    v7 v8  
    147147$$;
    148148}}}
     149
     150
     151** Наоѓање на најблизок возач (K-Nearest Neighbors) **
     152
     153При креирањето на понуда од страна на диспечерот, системот автоматски го бара најблискиот слободен возач од таа компанија. За оваа цел се користи PostGIS операторот `<->`, кој го пресметува просторното растојание користејќи го GiST индексот. Ова овозможува пронаоѓање на возачот во `O(1)` односно константно време, без да се скенираат сите возачи.
     154
     155{{{
     156create or replace procedure create_offer(
     157    v_request_id int4,
     158    v_dispatcher_user_id int4,
     159    v_price numeric(19, 2),
     160    v_currency_catalog_id int4,
     161    v_eta timestamp
     162)
     163    language plpgsql
     164AS
     165$$
     166declare
     167    v_driver_user_id        int4;
     168    v_dispatcher_company_id int4;
     169    v_start_position        geometry;
     170    v_customer_user_id      int4;
     171begin
     172    if not exists(select * from request where request.id = v_request_id and request.status = 'pending') then
     173        raise exception 'Request with id % and pending status does not exist', v_request_id;
     174    end if;
     175    if v_price <= 0 then
     176        raise exception 'Price has to be greater than 0';
     177    end if;
     178    if v_eta <= now() then
     179        raise exception 'ETA cannot be lower than the time of creation';
     180    end if;
     181
     182    v_customer_user_id := (select customer_user_id from request where request.id = v_request_id);
     183
     184    v_dispatcher_company_id := (select eh.company_id
     185                                from dispatcher d
     186                                         join employmenthistory eh on eh.employee_user_id = d.user_id and
     187                                                                      (eh.end_date is null or eh.end_date > now())
     188                                where d.user_id = v_dispatcher_user_id
     189                                limit 1);
     190
     191    if v_dispatcher_company_id is null then
     192        raise exception 'Dispatcher % is not assigned to a company',
     193            v_dispatcher_user_id;
     194    end if;
     195
     196    v_start_position := (select start_location from request where id = v_request_id);
     197
     198    v_driver_user_id := (select d.user_id
     199                         from driver d
     200                                  join driver_vehicle dc on d.user_id = dc.id_driver
     201                                  join employmenthistory eh
     202                                       on eh.employee_user_id = d.user_id and (eh.end_date is null or
     203                                                                               eh.end_date > now())
     204                         where dc.time_to is null
     205                           and eh.company_id = v_dispatcher_company_id
     206                           and d.location is not null
     207                         order by d.location <-> v_start_position
     208                         limit 1);
     209
     210    if v_driver_user_id is null then
     211        raise exception 'No available drivers found for request %', v_request_id;
     212    end if;
     213
     214    insert into offer(status, created_at, request_id, dispatcher_user_id, driver_user_id, price, currency_catalog_id,
     215                      eta, customer_user_id)
     216    values ('pending', now(), v_request_id, v_dispatcher_user_id, v_driver_user_id,
     217            v_price, v_currency_catalog_id, v_eta, v_customer_user_id);
     218    commit;
     219end;
     220$$;
     221}}}
     222
     223
     224** Lambda Архитектура и 4D Траектории на возење **
     225
     226За следење на возилата во реално време, воведена е Lambda архитектура. Табелата location служи како "Hot storage" каде што се запишуваат илјадници GPS точки додека возилото се движи. Кога возењето ќе заврши, се активира тригер кој ги собира сите точки и ги компресира во една 4-димензионална линија (LineStringZM – каде Z е брзината, а M е Unix времето) во табелата ride ("Cold storage"). Откако траекторијата е зачувана, сировите точки се бришат за да се ослободи меморија.
     227
     228{{{
     229alter table location
     230    add column speed numeric(5,2) default 0;
     231
     232alter table ride
     233    add column route_path geometry(LineStringZM, 4326);
     234
     235create or replace function archive_ride_trajectory()
     236returns trigger
     237language plpgsql
     238as $$
     239begin
     240    if NEW.status = 'completed' and OLD.status != 'completed' then
     241        NEW.route_path := (
     242            select ST_MakeLine(
     243                       ST_MakePoint(
     244                           l.longitude,
     245                           l.latitude,
     246                           COALESCE(l.speed, 0),
     247                           extract(epoch from l.timestamp)
     248                       )
     249                       order by l.timestamp
     250                   )
     251            from location l
     252            where l.ride_id = NEW.id
     253        );
     254
     255        delete from location where ride_id = NEW.id;
     256    end if;
     257
     258    return NEW;
     259end;
     260$$;
     261
     262create trigger trigger_archive_trajectory
     263    before update on ride
     264    for each row
     265    execute function archive_ride_trajectory();
     266
     267update ride r
     268set route_path = (
     269    select ST_MakeLine(
     270               ST_MakePoint(
     271                   l.longitude,
     272                   l.latitude,
     273                   COALESCE(l.speed, 0),
     274                   extract(epoch from l.timestamp)
     275               )
     276               order by l.timestamp
     277           )
     278    from location l
     279    where l.ride_id = r.id
     280)
     281where r.status = 'completed' and r.route_path is null;
     282
     283delete from location
     284where ride_id in (select id from ride where status = 'completed');
     285}}}