Вычисление большого кругового расстояния с SQLite

Вот моя проблема, у меня есть таблица SQLite с местоположениями и широтами / долготы. В основном я должен:

SELECT location, HAVERSINE(lat, lon) AS distance FROM location ORDER BY distance ASC;

HAVERSINE() функция PHP, которая должна возвратить Большое Круговое Расстояние (в милях или км), учитывая пару значений широты и долготы. Одна из этих пар должна быть обеспечена PHP, и другая пара должна быть обеспечена каждой широтой / строка долготы, доступная в locations таблица.

Так как SQLite не делает имеет любое Гео-Пространственное расширение (AFAIK SpatiaLite существует, но все еще...), я предполагаю, что лучший подход должен был бы использовать пользовательскую функцию с любым из методов PDO:

Я думаю для этого случая PDO::sqliteCreateFunction() был бы достаточно, однако мой ограниченный опыт с этой функцией может быть уменьшен до случаев использования, подобных тому, обеспеченному в Руководстве PHP:

$db = new PDO('sqlite:geo.db');

function md5_and_reverse($string) { return strrev(md5($string)); }

$db->sqliteCreateFunction('md5rev', 'md5_and_reverse', 1);
$rows = $db->query('SELECT md5rev(filename) FROM files')->fetchAll();

Я испытываю некоторые затруднения при выяснении, как я могу заставить определяемую пользователем функцию SQLite обрабатывать данные от PHP и данные таблицы одновременно, и я ценил бы, если кто-то мог бы помочь мне решить эту проблему, также понимая SQLite UDFs (большая победа SQLite IMO) немного лучше.

Заранее спасибо!

7
задан Alix Axel 18 January 2010 в 14:42
поделиться

2 ответа

До сих пор я могу думать только об этом решении:

$db = new PDO('sqlite:geo.db');

$db->sqliteCreateFunction('ACOS', 'acos', 1);
$db->sqliteCreateFunction('COS', 'cos', 1);
$db->sqliteCreateFunction('RADIANS', 'deg2rad', 1);
$db->sqliteCreateFunction('SIN', 'sin', 1);

, а затем выполнить следующий длительный запрос:

SELECT "location",
       (6371 * ACOS(COS(RADIANS($latitude)) * COS(RADIANS("latitude")) * COS(RADIANS("longitude") - RADIANS($longitude)) + SIN(RADIANS($latitude)) * SIN(RADIANS("latitude")))) AS "distance"
FROM "locations"
HAVING "distance" < $distance
ORDER BY "distance" ASC
LIMIT 10;

Если кто-то может придумать лучшее решение, пожалуйста, дайте мне знать.


Я просто нашел эту интересную ссылку , я попробую это завтра.

9
ответ дан 6 December 2019 в 21:14
поделиться

Если у вас есть:

listRubriques = null;

и нет других объектов, содержащих ссылки на listRubriques или содержащие их объекты, это подходит для сбора мусора. Но нет никакой гарантии, когда JVM фактически запустит на нем сбор мусора и свободную память. Вы можете позвонить по телефону

System.gc();

, чтобы порекомендовать JVM, что вы считаете запуск сбора мусора в это время хорошей идеей. Но и тогда гарантии нет.

Также наличие

listRubriques.clear();

перед установкой listRubriques в значение null не требуется.

EDIT : Чтобы ответить на ваш вопрос о циклических ссылках, JVM достаточно умны, чтобы понять, что весь граф объектов отключен от любого активно работающего кода, и JVM правильно определит, что все они имеют право на вывоз мусора. Это всегда было верно даже в плохие старые дни отсчета. Современные JVM просто быстрее и эффективнее. Но они не собирают больше объектов, чем старые JVM.

-121--2695415-

Можно обрабатывать несколько типов исключений с помощью одной попытки/цикла захвата. Но позаботьтесь о порядке, в котором вы собираетесь справиться с исключениями. Порядок блока исключений захвата имеет значение.

-121--3866415-

Построение из ответа Аликса...

$db->sqliteCreateFunction('HAVERSINE', 'haversine', 2);

Я бы предположил, что это позволит сработать тому запросу, который вы указали в своем вопросе.

0
ответ дан 6 December 2019 в 21:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: