wiki:AdvancedConcepts

Version 6 (modified by 231028, 33 hours ago) ( diff )

--

Advanced Concepts

Во оваа фаза од проектот, стандардниот релационен модел е надограден со просторни функционалности преку екстензијата PostGIS. Дополнително, за следење на возилата е имплементирана Lambda архитектура (Hot/Cold складирање) со 4D просторно-временски траектории (LineStringZM).

Иницијализација на PostGIS и конверзија во полигони (Geofencing)

Првиот чекор вклучува овозможување на PostGIS екстензијата и мигрирање на постоечките координати во geometry објекти. Дополнителна промена е отфрлањето на обичните радиуси за зоните на компаниите. Наместо тоа, користејќи ја функцијата ST_Buffer, кружните области се конвертирани во прецизни полигони со што се овозможува вистинско дигитално надградување. Креирани се и GiST (Generalized Search Tree) индекси кои се потребни за брзо пребарување на просторни податоци.

create extension if not exists postgis schema public;

alter table driver add column location geometry(Point, 4326);

update driver
set location = st_setsrid(st_makepoint(longitude, latitude), 4326);

alter table request add column start_location geometry(Point, 4326);

alter table request add column end_location geometry(Point, 4326);

update request
set start_location = st_setsrid(st_makepoint(start_longitude, start_latitude), 4326);

update request
set end_location = st_setsrid(st_makepoint(end_longitude, end_latitude), 4326);

alter table waypoints add column location geometry(Point, 4326);

update waypoints
set location = st_setsrid(st_makepoint(longitude, latitude), 4326);

alter table location add column location geometry(Point, 4326);

update location
set location = st_setsrid(st_makepoint(longitude, latitude), 4326);

alter table report add column location geometry(Point, 4326);

update report
set location = st_setsrid(st_makepoint(longitude, latitude), 4326);

alter table area add column coverage_polygon geometry(Polygon, 4326);

update area
set coverage_polygon = ST_Buffer(
    ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography,
    radius
)::geometry;

create index idx_area_coverage_polygon on area using gist (coverage_polygon);

Просторно филтрирање на барања (Spatial Join)

За ефикасно поврзување на патниците со релевантните такси компании, креиран е нов поглед кој користи просторно спојување (Spatial Join). Преку функцијата ST_Contains, погледот проверува дали почетната локација на патникот (start_location) се наоѓа во рамките на полигонот на покриеност на компанијата (coverage_polygon). Овој пристап е многу поефикасен од пресметување на растојанија. Ова е оптимизацијата која ги подобрува перформансите на погледот vw_unassigned_requests спомнат во делот за QueryOptimization каде почетно беше решено со пагинација на барањата, а во случајот се земаат помал број на барања поради тоа што ќе се земат само барања кои се наоѓаат во одреден радиус.

create or replace view vw_company_available_requests as
select distinct
       r.id as request_id,
       r.customer_user_id,
       cus.username as customer_username,
       r.timestamp,
       r.number_of_adult_passengers,
       r.number_of_children,
       r.status,
       r.female_driver,
       r.luggage,
       r.luggage_count,
       r.baby_seat_count,
       ca.company_id
from request r
         join AppUser cus on r.customer_user_id = cus.id
         join area a on ST_Contains(a.coverage_polygon, r.start_location)
         join company_area ca on a.id = ca.area_id
where r.status = 'pending';

Динамична пресметка на цена преку просторна дистанца

Креирана е нова функција calculate_price која ја пресметува цената на возењето. Таа користи ST_Distance со кастирање во geography за да ја добие точната воздушна дистанца во километри помеѓу почетната и крајната дестинација, по што го множи растојанието со соодветната тарифа на компанијата или фриленсерот. Тарифата може да биде цена за секоја минута возење или цена за секој изминат километар.

CREATE OR REPLACE FUNCTION calculate_price(request_id int4, id_company int4, id_area int4, freelance_driver_id int4)
RETURNS numeric(19,2)
LANGUAGE plpgsql
AS
$$
DECLARE
    distance_km numeric;
    price_per_km numeric;
    price_per_min numeric;
BEGIN
    SELECT
        ST_Distance(
            start_location::geography,
            end_location::geography
        ) / 1000.0
    INTO distance_km
    FROM request
    WHERE id = request_id;

    IF distance_km IS NULL THEN
        RAISE EXCEPTION 'Request % not found', request_id;
    END IF;

    SELECT value
    INTO price_per_km
    FROM pricinginfo p
    JOIN company_area c on p.id=c.pricing_info_id
    WHERE c.company_id=id_company and c.area_id=id_area and unit='kilometer'
    LIMIT 1;

    SELECT value
    INTO price_per_km
    FROM pricinginfo p
    JOIN freelancedriver d on p.id=d.pricing_info_id
    WHERE d.driver_user_id=freelance_driver_id and unit='kilometer'
    LIMIT 1;

    SELECT value
    INTO price_per_min
    FROM pricinginfo p
    JOIN company_area c on p.id=c.pricing_info_id
    WHERE c.company_id=id_company and c.area_id=id_area and unit='minute'
    LIMIT 1;

    SELECT value
    INTO price_per_min
    FROM pricinginfo p
    JOIN freelancedriver d on p.id=d.pricing_info_id
    WHERE d.driver_user_id=freelance_driver_id and unit='minute'
    LIMIT 1;

    IF price_per_km IS NULL and price_per_min IS NULL
    THEN
        RAISE EXCEPTION 'Pricing info not found';
    end if;

    IF price_per_km IS NOT NULL
    THEN
        RETURN ROUND((distance_km * price_per_km)::numeric, 2);
    ELSE
        RETURN ROUND((distance_km/40 * price_per_min * 60)::numeric, 2);
    end if;
END;
$$;

Attachments (1)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.