Көбірек

PostGIS ST_Distance, kNN бар ең жақын нүктелер

PostGIS ST_Distance, kNN бар ең жақын нүктелер


Мен бір элементтің әр элементінен басқа кестенің ең жақын нүктесін алуым керек. Бірінші кестеде жол белгілері, екіншісінде қаланың кіреберісі бар. Мәселе мынада, мен ST_ClosestPoint функциясын қолдана алмаймын, және ST_Distance функциясын қолданып, min (ST_distance) жазбасын алуым керек, бірақ мен сұранысты құра алмаймын.

Кесте трафигі_белгілерін жасаңыз (id сандық (8,0)), «GEOMETRY» геометриясы, CONSTRAINT траффик_сигналдары_кепкі НЕГІЗГІ НЕГІЗГІ (id), CONSTRAINT трафик_сигналдары_ид_ кілт UNIQUE (id)) WITH (OIDS = TRUE); КЕСІПТІҢ КІРІСТІК КІРІСІН (идентификаторлық сандық (8,0)), «ГЕОМЕТРИЯ» геометриясын, CONSTRAINT кіру_халл_плей БАСТАМАЛЫ КІЛТ (идентификатор), CONSTRAINT кіру_халл_ид_ кілт БІРЕЙІМ (id)) WITH (OIDS = TRUE);

Маған барлық трафиктің_белгілерінің ең жақын entrnce_hall идентификаторын алу қажет.

Менің сұрағым:

SEAL senal.id, port.id, ST_Distance (порт. «GEOMETRY», сенал. «GEOMETRY») қашықтықтан FROM трафик_сигналдары ретінде senal, giriş_halls порты ORDER BY senal.id, port.id, ST_Distance (порт. «GEOMETRY») таңдаңыз , сенал. «ГЕОМЕТРИЯ»)

Осылайша мен барлық жол белгілерінен бастап барлық кіреберістерге дейінгі қашықтықты аламын. Бірақ минималды қашықтықты қалай алуға болады?

Құрметпен,


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

SEAL DISTINCT ON (senal.id) senal.id, port.id, ST_Distance (порт. «GEOMETRY», senal. «GEOMETRY») FROM traffic_signs As senal, input_halls As port ORDER BY senal.id, port.id, ST_Distance (порт. «GEOMETRY», сенал. «GEOMETRY»);

Егер сіз әр жағдайда минималды арақашықтық х мөлшерінен аспайтынын білсеңіз (және сіздің кестелеріңізде кеңістік индексі болса), оны жылдамдықтыSTEDWithin қайда (порт. «GEOMETRY», сенал. «GEOMETRY», арақашықтық)мысалы, егер барлық минимум арақашықтықтары 10 км-ден аспайтыны белгілі болса, онда:

SEAL DISTINCT ON (senal.id) senal.id, port.id, ST_Distance (порт. «GEOMETRY», senal. «GEOMETRY») FROM traffic_signs As senal, input_halls As port WHERE ST_DWithin (порт. «GEOMETRY», сенал) . «GEOMETRY», 10000) БҰЙЫРУ senal.id, port.id, ST_Distance (порт. «GEOMETRY», сенал. «GEOMETRY»);

Мұны абайлап қолдану керек, өйткені минималды арақашықтық үлкен болса, сенал мен порттың тіркесімі үшін жол болмайды.

Ескерту: Тапсырыс бойынша тапсырыс рет-ретімен сәйкес келуі керек, бұл мағынасы бар, өйткені айырмашылық кейбір тапсырыс бойынша бірінші топты қабылдайды.

Екі кестеде де сіздің кеңістіктік индексіңіз бар деп болжануда.

Түзету 1. Postgres-тің <-> және <#> операторларын қолданудың тағы бір нұсқасы бар (сәйкесінше орталық нүкте және шекара шеберлерінің арақашықтық есептеулері), олар кеңістіктік индексті тиімді пайдаланады және n-ні болдырмау үшін ST_DWithin бұзылуын қажет етпейді. ^ 2 салыстыру. Олардың қалай жұмыс істейтінін түсіндіретін жақсы блог мақаласы бар. Жалпы назар аударатын нәрсе - бұл екі оператор ORDER BY тармағында жұмыс істейді.

SELECT senal.id, (SELECT port.id FROM input_halls as port ORDER BY senal.geom <#> port.geom LIMIT 1) FROM трафик_сигналдары ретінде сенал;

ТІЗІМ 2. Бұл сұраққа көп көңіл бөлінгендіктен, k-ге жақын көршілер (kNN) ГАЖ-да (алгоритмдік жұмыс уақыты тұрғысынан) қиын мәселе болғандықтан, бұл сұрақтың бастапқы шеңберінде біраз кеңейтілген жөн сияқты.

Бір объектінің x жақын көршілерін табудың стандартты тәсілі - LATERAL JOIN пайдалану (әр цикл үшін а-ға ұқсас). Дбастонның жауабынан ұялмай қарыз ала отырып, сіз келесі әрекеттерді жасар едіңіз:

SELECT signs.id, closest_port.id, closest_port.dist FROM traff_signs CROSS JOIN LATERAL (SELECT id, ST_Distance (ports.geom, белгилер.geom) сияқты FROM порттардан ORDER BY signs.geom <-> ports.geom LIMIT 1) AS жақын_порт

Сонымен, қашықтыққа тапсырыс берілген жақын 10 портты тапқыңыз келсе, бүйірлік ішкі сұраныста LIMIT тармағын өзгертуіңіз керек. СОҢҒЫ БІРЛІКТЕРСІЗ бұл өте қиын және ARRAY типті логиканы қолдануды білдіреді. Бұл тәсіл жақсы жұмыс істегенімен, берілген қашықтықты іздеу керек екенін білсеңіз, оны тездетуге болады. Бұл жағдайда сіз ST_DWithin-ді (signs.geom, ports.geom, 1000) пайдалана аласыз, бұл индекстеу <-> операторымен жұмыс істейтіндіктен - геометриялардың біреуі тұрақты емес, а болуы керек баған сілтемесі - әлдеқайда жылдам болуы мүмкін. Мәселен, мысалы, ең жақын 3 портты 10 шақырымға жету үшін сіз келесідей нәрсе жаза аласыз.

SELECT signs.id, closest_port.id, closest_port.dist FROM traff_signs CROSS JOIN LATERAL (SELECT id, ST_Distance (ports.geom, белгилер.geom) сияқты ST_DWithin (ports.geom, белгилер.geom, 10000)) ST_Distance (ports.geom, signs.geom) LIMIT 3) AS ең жақын_порт;

Әдеттегідей, сіздің деректеріңіздің таралуы мен сұраныстарыңызға байланысты әр түрлі болады, сондықтан ТҮСІНДІРІҢІЗ сіздің ең жақсы досыңыз.

Соңында, егер қолданатын болса, кішігірім готча бар СОЛ орнына ӨТІНІШТЕР ҚОСЫЛУ оған қосу керек ШЫНДА бүйірлік сұраулардан кейін бүркеншік ат, мысалы,

SELECT белгилері.id, closest_port.id, closest_port.dist FROM трафик_сигналдары СОЛ ҚОСЫЛУ КЕЙІНІ (SELECT идентификаторы, ST_Distance (ports.geom, белгилер.geom) ретінде алыс FROM порттардан ORDER BY signs.geom <-> ports.geom LIMIT 1) AS close_port ON TRUE;

Мұны a көмегімен жасауға боладыСОҢҒЫ ҚОСЫЛУPostgreSQL 9.3+ нұсқасында:

SELECT signs.id, closest_port.id, closest_port.dist FROM traff_signs CROSS JOIN LATERAL (SELECT id, ST_Distance (ports.geom, белгилер.geom) сияқты FROM порттардан ORDER BY signs.geom <-> ports.geom LIMIT 1) AS жақын_порт

Кросс-қосылыспен жақындау индекстерді қолданбайды және көп жадты қажет етеді. Сонымен, сізде негізінен екі таңдау бар. 9.3-ке дейін сіз өзара байланысты сұранысты қолданасыз. 9.3+ пайдалануға боладыСОҢҒЫ ҚОСЫЛУ.

KNN GIST бүйірлік бұрылыспен жақында сіздің жаныңыздағы мәліметтер базасына келеді

(жақын арада орындалатын нақты сұрақтар)


@John Barça

Тапсырыс қате!

ORDER BY senal.id, port.id, ST_Distance (порт. «GEOMETRY», сенал. «GEOMETRY»);

Дұрыс

senal.id, ST_Distance (порт. «GEOMETRY», сенал. «GEOMETRY»), port.id;

әйтпесе ол жақын жерді қайтармайды, тек порт идентификаторы аз болады


Егер сіз сізге жақын нүктелерді сілтеме жасайтын нүктеге қайтаратын сұраныспен қызықтыратын болсаңыз, онда бұл да айла-шарғы жасайды:

senal.id, port.id, st_closestPoint таңдаңыз.

Бейнені қараңыз: K-Nearest Neighbor