
Donc j'imagine qu'avec 50 ou 100 ou 200 fois plus de points et plusieurs personnes qui font des recherches en même temps, j'aurai le temps d'aller boire un café ... ou de me pendre

J'ai deux options, soit optimiser la requête et arriver à un temps de chargement optimal ou bien tricher un peu en faisant des pré-calculs, que je stocke en bdd. Franchement, la deuxième option, n'a rien d'idéale, ça supposerait de parcourir toutes les données de façon régulière et générer/updater la data qui va bien.
Donc c'est pour ça que je crie au secours et appelle à votre expérience pour voir ce qu'il est possible de faire.
La requête me permet de récupérer l'ensemble des POIs situé de part et d'autre d'une trace (en fonction d'un point de départ).
Et la sous requête qui calcule la distance entre le point de départ et le point affiché, pour pouvoir afficher les POIs dans l'ordre. Cette sous-requête est donc appelée pour chaque point d'arrivée potentiel.
Pour afficher le kilométrage, je rappelle une deuxième fois l'équivalent de la sous requête. Ce qui n'est pas franchement idéal...
La requ^te pour récupérer la liste des POIs :
Code : Tout sélectionner
def poi_around_trace_from__(poi, trace, dist)
distance_sql = <<-SQL
SELECT
ST_Distance(tr.path::geography, pta.lonlat::geography) +
ST_Distance(tr.path::geography, poi.lonlat::geography) +
ST_Length(ST_LineSubstring(
tr.path,
least(ST_LineLocatePoint(tr.path, pta.lonlat::geometry), ST_LineLocatePoint(tr.path, poi.lonlat::geometry)),
greatest(ST_LineLocatePoint(tr.path, pta.lonlat::geometry), ST_LineLocatePoint(tr.path, poi.lonlat::geometry))),false) AS dst_line, poi.*
FROM traces tr, pois pta, (
SELECT poi.* AS pois
FROM traces tr, pois pta, pois poi
WHERE tr.id = #{trace.id}
AND pta.id = #{poi.id}
AND ST_DWithin(ST_LineSubstring(
tr.path,
ST_LineLocatePoint(tr.path, pta.lonlat::geometry) + (#{dist} * 1000) / (tr.length * 1000) ,
ST_LineLocatePoint(way.path, pta.lonlat::geometry) + #{end_point} / ST_Length(way.path, false))::geography,
poi.lonlat::geography,
200)
) as poi
WHERE tr.id = #{trace.id}
AND pta.id = #{poi.id}
AND poi.id = poi.id
ORDER BY dst_line ASC
SQL
Rails.cache.fetch(['sql-distance', trace, poi, dist]) {
Poi.find_by_sql(distance_sql)
}
end
Code : Tout sélectionner
def distance_along_way_to(poi1, poi2, way)
distance_sql = <<-SQL
SELECT
ST_Distance(way.path::geography, pta.lonlat::geography) +
ST_Distance(way.path::geography, ptb.lonlat::geography) +
ST_Length(ST_LineSubstring(
way.path,
least(ST_LineLocatePoint(way.path, pta.lonlat::geometry), ST_LineLocatePoint(way.path, ptb.lonlat::geometry)),
greatest(ST_LineLocatePoint(way.path, pta.lonlat::geometry), ST_LineLocatePoint(way.path, ptb.lonlat::geometry))),false) AS dst_line
FROM ways way, pois pta, pois ptb
WHERE way.id = #{way.id}
AND pta.id = #{poi1.id}
AND ptb.id = #{poi2.id}
SQL
Rails.cache.fetch(['sql-distance', way, poi1, poi2]) {
Poi.find_by_sql(distance_sql).first.dst_line
}
end

Code : Tout sélectionner
"Sort (cost=46.67..46.71 rows=15 width=209)"
" Sort Key: (((_st_distance((tr.path)::geography, pta.lonlat, '0'::double precision, true) + _st_distance((tr.path)::geography, poi.lonlat, '0'::double precision, true)) + st_length((st_linesubstring(tr.path, LEAST(st_linelocatepoint(tr.path, (pta.lonlat)::geometry), st_linelocatepoint(tr.path, (poi.lonlat)::geometry)), GREATEST(st_linelocatepoint(tr.path, (pta.lonlat)::geometry), st_linelocatepoint(tr.path, (poi.lonlat)::geometry))))::geography, false)))"
" -> Nested Loop (cost=0.00..46.38 rows=15 width=209)"
" Join Filter: st_dwithin((st_linesubstring(tr_1.path, (st_linelocatepoint(tr_1.path, (pta_1.lonlat)::geometry) + ('20000'::double precision / (tr_1.length * '1000'::double precision))), (st_linelocatepoint(tr_1.path, (pta_1.lonlat)::geometry) + ('200000'::double precision / st_length((tr_1.path)::geography, false)))))::geography, poi.lonlat, '2000'::double precision)"
" -> Nested Loop (cost=0.00..7.23 rows=1 width=136)"
" -> Nested Loop (cost=0.00..4.64 rows=1 width=104)"
" -> Nested Loop (cost=0.00..3.61 rows=1 width=64)"
" -> Seq Scan on traces tr (cost=0.00..1.02 rows=1 width=32)"
" Filter: (id = 2)"
" -> Seq Scan on pois pta (cost=0.00..2.58 rows=1 width=32)"
" Filter: (id = 2)"
" -> Seq Scan on traces tr_1 (cost=0.00..1.02 rows=1 width=40)"
" Filter: (id = 2)"
" -> Seq Scan on pois pta_1 (cost=0.00..2.58 rows=1 width=32)"
" Filter: (id = 2)"
" -> Seq Scan on pois poi (cost=0.00..2.46 rows=46 width=201)"
" Filter: (id IS NOT NULL)"

Mais je suis sûr qu'il existe une solution, sinon faut 'expliquer comment google fait pour afficher aussi vite ses itinéraire sur une map
