| Version 7 (modified by , 32 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)
- 1.png (10.1 KB ) - added by 26 hours ago.
Download all attachments as: .zip
