Пошук найближчих сусідів між двома таблицями з точковими місцями в SpatiaLite?


10

Я почав грати з SpatiaLite сьогодні і вже натрапив на проблему.

Для кожного місця розташування, збереженого в tableOne, я хотів би вибрати одну, найближчу (лінійну відстань) точку від tableTwo.

Поки що я придумав незграбне рішення, яке використовує ПОГЛЯД:

CREATE VIEW testview AS 
SELECT 
A.id , 
B.myValue, 
Distance(A.Geometry, B.Geometry) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE distance < 10000
ORDER BY A.Id, distance;

І потім:

SELECT * FROM testview
WHERE distance = (SELECT MIN(distance) FROM testview AS t WHERE t.id = testview.id)

здається, виконує роботу.

Два питання:

Чи є спосіб виконати такий запит, не створюючи VIEW?

Чи є якийсь інший спосіб оптимізувати цей запит для кращої ефективності? У реальному сценарії tableOne буде мати сотні-пару тисяч записів, а tableTwo - 1,3 мільйона.


Я можу надати вам підхід, який на кілька порядків швидший, але він вимагатиме від вас використовувати postgresql 9-кнгнгістський індекс замість
просторіта

насправді швидше, ніж GRASS, ArcGIS, QGIS, SQLServer і майже будь-який інший просторовий db / Desktop GIS (хоч не пробував функціональність найближчого сусіда Oracle), просто дайте мені знати, чи це варіант.
Рагі Ясер Бурхум

@Ragi: Я знаю, що PostGIS був би набагато ефективнішим способом роботи з такою проблемою. Однак кінцевою метою цієї вправи буде зробити невеликий портативний додаток, і в цьому випадку SpatiaLite є переможцем.
radek

Яка платформа для розробки вашого портативного додатка?
Аллан Адаїр

@Allan: На даний момент працює над обома: Windows Server 2008 та Ubuntu.
radek

Відповіді:


5

Я щойно перевірив цей SQL і він працює:

SELECT g1.OGC_FID As id1, g2.OGC_FID As id2, MIN(ST_Distance(g1.GEOMETRY,g2.GEOMETRY)) AS DIST
FROM table_01 As g1, table_02 As g2   
WHERE g1.OGC_FID <> g2.OGC_FID
AND ST_Contains(ST_Expand(g1.geometry,50),g2.geometry)
GROUP BY id1
ORDER BY id1

Як ви можете прочитати тут, "Наївний спосіб здійснити запит найближчого сусіда - це замовити таблицю кандидата на відстані від геометрії запиту, а потім взяти запис з найменшою відстані".

З повагою,

Андреа


Я намагаюся використовувати цей запит, але отримую несподівані результати - я отримую отриману таблицю, але з ідентифікаторами рядків я можу бачити, що вони не найближчий сусід. Я намагаюся знайти найближчий рядок у багаторядковому шарі рядка до кожної точки іншого шару. Я новачок у spatiaLite. Будь-які пропозиції? Також я в кінцевому підсумку хочу запустити це на 1 мільйон + балів
kflaw

Я також не впевнений, що розумію мету цього твердження: ДЕ g1.OGC_FID <> g2.OGC_FID
kflaw

Крім того, в результаті я отримую нульову відстань. Я розігрував цей рядок: AND ST_Contains (ST_Expand (g1.geometry, 50), g2.geometry), а також видалив його і досі не отримую значень відстані, хоча я отримую ID
kflaw

6

Якщо ви не хочете обчислювати відстані між усіма комбінаціями точок, ви можете використовувати просторовий індекс на одній із таблиць:

SELECT 
  A.id , 
  B.myValue, 
  MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE A.ROWID IN (
  SELECT ROWID
  FROM SpatialIndex WHERE
    f_table_name = 'A' 
    AND search_frame = BuildCircleMbr(ST_X(B.Geometry), ST_Y(B.Geometry), 10000))
GROUP BY A.id, B.myValue

Я намагався використовувати розроблене вами рішення, як мені потрібно використовувати просторовий індекс, але він не повертає жодних значень? для рядка f_table_name = 'A', чи потрібно мені замінити "A" фактичним іменем таблиці (таблиця перша)? Я намагався в будь-якому випадку, і все ще нічого не повертає, чому це може бути
kflaw

Ви маєте рацію , f_table_name = 'A'має бути f_table_name = 'tableOne'. Зверніть увагу, що цей запит передбачає просторовий> 4.x (використовується SpatialIndexвіртуальна таблиця). Чи намагалися ви відкоригувати search_frameваш випадок використання? У наведеному вище прикладі точки вважаються на максимальній відстані 10000 метрів.
Самуїл

Я пограв зі значенням рамки пошуку, я вважаю, що це значить в межах 10000 метрів, які повинні працювати для мене. Я насправді не знаю, яка версія просторіта, я створив базу даних через qgis і використовую gui в qgis. Дозвольте мені побачити, чи можу я це зрозуміти
kflaw

Це версія 4.1.1 з sqlite версії 3.7.17, тож вона повинна працювати тоді? Цікаво, що не так, я
тестую

3

Оскільки версія 4.4.0 SpatiaLite підтримує індекс віртуальної таблиці KNN для проблем найближчих сусідів. Ось запит знаходить найближчий рядок у таблиці рядків рядків до кожної точки таблиці таблиці.

SELECT k.* FROM knn k, points p
WHERE f_table_name = 'linestrings' 
AND ref_geometry = p.geometry
AND max_items = 1;

2

Ви можете спростити запит таким чином.

SELECT 
   A.id , 
   B.myValue, 
   MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
GROUP BY A.id, B.myValue

Для більш загального рішення, можливо, варто спробувати перетворити цю функцію Найближчого сусіда PostGIS: http://blog.mackerron.com/2011/03/postgis-nevable-neighbour/


на жаль, код призводить до:SQL error: "misuse of aggregate: MIN()"
radek

Що стосується PostGIS, на веб-сайті BostonGIS також є кілька прикладів , але поки що я не мав успіху в перекладі їх на SpatiaLite: /
radek
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.