-1

我的数据库中有一些带有坐标的地方,我使用 GEO 函数来过滤最近的坐标。

但它不够精确,因为它不是行驶距离。

我已经使用 HERE Maps API 来获取路由信息,但是加载整个列表并在此之后调用 API 非常繁重。

有什么方法可以结合 Doctrine 和 HERE API 或任何其他方式对地点进行排序或过滤?

谢谢

4

1 回答 1

1

大约一年前,我在一个类似的项目中遇到了这个确切的问题。唯一的区别是我使用了谷歌的距离矩阵 API 来确定实际行驶里程。

简短的回答是否定的,您不能在查询级别执行此操作,因为数据库不知道路由信息。(您也不能这样提供。)即使您确实构建了一些抢占式路由信息,您仍然需要查询每个实体以找到其位置才能做到这一点,而且您还会对地图 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();
}

输入$latitude$longitude您要计算距离的起点/终点,例如用户搜索的位置

请记住,来自此存储库函数的数组中的每个结果都不会是每个实体的直接实例。它将分为 2 个键:

  • 0: 目标实体实例
  • distanceMiles: 用于限制和按距离排序的额外伪字段

然后,在您的控制器中,您需要迭代结果数组以查询您的地图 API 并获取确切的行驶距离。就我个人而言,我会在 and 中添加另一个关键兄弟drivingMiles,然后您可以在 a 中使用它来对整个结果集进行排序,以构建最终结果集。0distanceMilesusort()

这在大多数情况下应该工作得很好,但是总会有一些边缘情况,其中某些结果比初始距离限制更远,这是由于道路中奇怪的弯道/方向循环回源等。您仍然可以将它们从最终数组中过滤出来,但usort()如果您发现最终结果集变得太小,则只需根据直接距离逐渐增加查询限制。

于 2020-05-11T20:55:09.443 回答