Doctrine заказ по расстоянию - PullRequest
0 голосов
/ 06 мая 2020

У меня есть места с координатами в моей базе данных, которые я извлекаю с помощью функции GEO для фильтрации ближайшего.

Но это недостаточно точно, потому что не зависит от расстояния.

Я уже используйте HERE Maps API, чтобы получить информацию о маршрутизации, но так сложно загрузить весь список и вызвать API после этого.

Есть ли способ отсортировать или отфильтровать места с помощью Doctrine и HERE API, объединенного или любого другого другим способом?

Спасибо

1 Ответ

1 голос
/ 11 мая 2020

У меня была точно такая же проблема на подобном проекте год или около того go. Единственная разница в том, что я использовал API матрицы расстояний Google для определения реального пробега.

Короткий ответ - нет , вы не можете сделать это на уровне запроса, потому что база данных не будет ' t знать информацию о маршрутизации. (И вы не могли бы его так кормить.) Даже если бы вы создали некоторую информацию для упреждающей маршрутизации, вам все равно нужно было бы запрашивать каждую сущность, чтобы найти ее местоположение, чтобы сделать это, плюс вы также окажете огромную нагрузку на API карт, вероятно, заставив вас чтобы достичь квоты использования (и взимать плату за это) очень быстро! данные по прямому расстоянию до более подходящего набора (скажем, 50). Затем в вашем контроллере используйте API карт для сортировки результирующего массива по расстоянию проезда. Это также должно уменьшить количество запросов к API карт.

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

public function findClostestTo(float $latitude, float $longitude, float $milesLimit = null, int $resultsLimit = 1): ?array
{
    $qb = $this->createQueryBuilder("entity");

    // Find and sort records by their direct distance
    $qb
        ->addSelect("DEGREES(ACOS((SIN(RADIANS(:latitude)) * SIN(RADIANS(entity.latitude))) + (COS(RADIANS(:latitude)) * COS(RADIANS(entity.latitude)) * COS(RADIANS(:longitude - entity.longitude))))) * :radius AS distanceMiles")
        // ->addSelect("(distanceMiles * 1.609344) AS distanceKilometres")
        // ->addSelect("(distanceMiles * 0.868976) AS distanceNauticalMiles")
        ->setParameter("latitude", $latitude)
        ->setParameter("longitude", $longitude)
        ->setParameter("radius", (60 * 1.1515))
        ->addOrderBy("distanceMiles", "ASC")
    ;

    // Optional: Clamp results to a direct distance
    if (is_numeric($milesLimit) && $milesLimit > 0.0) {
        $qb
            ->andWhere("distanceMiles < :milesLimit")
            ->setParameter("milesLimit", $milesLimit)
        ;
    }

    // Limit quantity of direct distance results, important to reduce route distance API call count later
    $qb->setMaxResults(max(min($resultsLimit, 50), 1));

    return $qb->getQuery()->getResult();
}

Input $latitude и $longitude для исходная / конечная точка, расстояние от которой вы хотите вычислить, например, местоположение пользователя, выполняющего поиск

Не забывайте, что каждый результат в массиве из этой функции репозитория не будет прямым экземпляром каждой сущности. Он будет разделен на 2 ключа:

  • 0: экземпляр целевой сущности
  • distanceMiles: дополнительное псевдополе, используемое для ограничения и сортировки по расстоянию

Затем в контроллере потребуется выполнить итерацию массива результатов, чтобы запросить API карт и получить точное расстояние проезда. Лично я бы добавил, что еще один ключ drivingMiles родственник 0 и distanceMiles, из которых вы затем можете использовать в usort(), чтобы отсортировать весь набор результатов, чтобы построить окончательный набор результатов.

Это должно работать достаточно хорошо для большинства случаев, однако всегда будут некоторые крайние ситуации, когда определенные результаты будут дальше, чем начальный предел расстояния, из-за странных изгибов / направлений на дорогах, возвращающихся к источнику, и тому подобное. Вы все еще можете отфильтровать их из вашего окончательного массива, хотя после usort() его просто постепенно увеличивайте лимит запроса на основе прямого расстояния, если вы обнаружите, что ваши окончательные наборы результатов становятся слишком маленькими.

...