如何查询postgres数据库以获取某些坐标10公里半径内的所有点

Posted

技术标签:

【中文标题】如何查询postgres数据库以获取某些坐标10公里半径内的所有点【英文标题】:How to query a postgres database to get all points within a 10km radius of certain coordinates 【发布时间】:2019-11-29 20:29:04 【问题描述】:

我有一个商店数据库,在该数据库中我保存了这些商店的坐标。我想获取半径 10 公里内的商店列表,但是我不知道如何编写 Postgres 查询,因为我使用的是 Postgres 数据库。

我的数据库:

我正在尝试将查询添加到 springboot 地理定位微服务:

存储库代码:

@Repository
public interface SellerGeolocationRepository extends CrudRepository<Seller_Geolocation, Long> 

    @Query(value="SELECT * FROM seller_geolocation_ms WHERE 
   // get coordinates that are in the vicinity
", nativeQuery = true)
        public Set<Seller_Geolocation> findAllSellersInRange(double longitude, double latitude);

    

卖家对象:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "seller_geolocation_ms")
public class Seller_Geolocation 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private static final long serialVersionUID = 2L;

    private double latitude;
    private double longitude;
    private String country;
    private String city;
    private String zipCode;
    private String town;
    private String address;
    private Long sellerId;

【问题讨论】:

gis.stackexchange.com/questions/77072/… @Erent 为什么不使用像com.vividsolutions.jts.geom.Point 这样的类来保存地理空间数据,而不是简单地保存两个双数字?在这种情况下,您可以轻松地进行地理空间查询 我不知道 com.vividsolutions.jts.geom.Point,如果我要使用它,我将如何进行查询 您需要使用hibernate-spatial并安装postgis。我将在 spring-boot 中使用这些发布答案 @Erent 看看这个question 这就是你应该如何实现它。 【参考方案1】:

您可以使用半正弦公式,使用当前坐标 (target_latitude_deg/longitude) 和列名 (latitude_deg, longitude_deg),均以度数表示

SELECT * 
FROM myTable
WHERE acos(
       sin(radians(target_latitude_deg)) 
         * sin(radians(latitude_deg)) 
       + cos(radians(target_latitude_deg)) 
         * cos(radians(latitude_deg)) 
         * cos( radians(target_longitude_deg)
           - radians(longitude_deg))
       ) * 6371 <= 10;

或者,看看 PostGIS 扩展

SELECT * 
FROM MyTable 
WHERE ST_Dwithin(geom, st_point(target_longitude, target_latitude,10000);

【讨论】:

我不确定我是否理解半正弦公式以及如何传递我当前的坐标并从我的数据库中查询经度和纬度 在这种情况下,这不是解决问题的好方法。使用 spring boot 等框架与 hibernate-spatial 相结合的目的是不要涉及地理空间公式如何工作的低级细节。 OP 应该使用这些框架的内置功能,而不是原始 sql 查询。 @Omid 很公平......虽然没有 PostGIS,但我很想知道框架如何利用它 @JGH 没有 postgis 是不可能的。 @Omid :-/ 所以它要么是 OP 的重要更改(最好),要么是提供的原始 SQL 替代方案【参考方案2】:

为此,您需要安装 postgis:

brew 安装 postgis

之后,您需要在您的 postgres 数据库“seller_geolocation_ms”上安装 postgis:

   1. $ sudo -i -u postgres
   2. $ psql
   3. postgres=# \c seller_geolocation_ms;
   4. seller_geolocation_ms=# CREATE EXTENSION postgis;
   5. \q

完成这些步骤后,您的数据库中应该安装了 postgis。那么接下来要做的就是在你的 Springboot 存储库接口上编写查询,如下所示:

@Repository
public interface SellerGeolocationRepository extends CrudRepository<Seller_Geolocation, Long> 

    @Query(value="SELECT * FROM seller_geolocation_ms WHERE ST_DWithin(cast(seller_geolocation_ms.location as geography),ST_SetSRID(ST_Point(?2, ?1),4326), 10000);", nativeQuery = true)
    public Set<Seller_Geolocation> findAllSellersInRange(double longitude, double latitude);


要更深入地了解ST_DWithin,请点击此链接:here

【讨论】:

非常感谢@DivxExtract 的回答!在当前的形式下,它对我不起作用,但是一旦我将 ?2、?1 参数绑定切换到命名参数 :longitude :latitude ,它就起作用了【参考方案3】:

看看 Postgres earthdistance,还有一个提到的例子here 但是,您可以使用具有丰富地理空间功能的Postgis。 如果您想在业务逻辑上进行计算,请使用上面@JGH 答案中解释的Haversine 公式。

【讨论】:

以上是关于如何查询postgres数据库以获取某些坐标10公里半径内的所有点的主要内容,如果未能解决你的问题,请参考以下文章

从 Laravel 中的坐标获取半径内的用户

如何获取 postgresql 中的前 10 个值?

如何使用 Sequelize 从 GEOMETRY('POINT') 获取纬度/经度坐标?

Postgres jsonb null vs 空对象查询性能

查询联合查询

如何在没有连接的情况下为 postgres (Redshift) 生成 SQL 查询?