
PostGIS是PostgreSQL的一个支持地理信息处理的数据库组件,允许用SQL语句直接对位置信息进行查询和排序。目前在关系数据库中,对空间数据库技术支持最成熟的就属PostGreSQL关系数据库,PostGIS 则是PostgreSQL的一个扩展,目的是使PostgreSQL支持空间数据的存储和使用,下面一起了解下PostGIS的应用场景。
大家都知道微信有个功能就叫”附近的人“,饿了么有商家的配送距离,滴滴有行程距离预估,这些功能都有个共同点,就是会去计算两个地理位置之间的距离,更有甚者,会统计一个地理位置附近与多个地点之间的距离。为了解决这个问题,不同的中间件都推出了解决方案,比如搜索中间件solr和elasticsearch、缓存中间件redis、文档数据库mongodb、关系数据库mysql(5.75版本以后)和PostgreSQL。也有一些算法的解决方案如geohash。如今的业务系统都是比较广泛的构建在关系数据库之上,对于关系数据库这块mysql 5.75和PostgreSQL对比来看,PostgreSQL对空间搜索GIS的支持是完全碾压mysql的。
下面会做一个简单的应用示例,示例中将会演示如何存储人物的地理位置信息并且查找附近的人。
新建一张表存储人物的地理信息:id、人物名字和地理位置经纬度信息。其中GPS信息采样来源于百度的拾取坐标系统http://api.map.baidu.com/lbsapi/getpoint/。

(1)登录数据库;假设已经安装好了PostgreSQL的数据库环境,并且用默认账号postgres/postgres登录了数据库,并且连接好了数据库。
(2)加载postgis组件,运行如下命令:
CREATE EXTENSION postgis;
CREATE EXTENSION postgis_topology;
CREATE EXTENSION postgis_tiger_geocoder;
用查询语句SELECT postgis_full_version()可查询当前的GIS版本。
上面加载了PostgreSQL的扩展组件;
(3)建表:
CREATE TABLE users (id serial PRIMARY KEY, name varchar(50), the_geom geometry(Point, 4326));
往数据库插入数据:
INSERT INTO users (id, the_geom, name) VALUES (1,ST_GeomFromText('POINT(114.316559 30.48828)',4326),'小王');
INSERT INTO users (id, the_geom, name) VALUES (2,ST_GeomFromText('POINT(114.314008 30.486568)',4326),'小明');
INSERT INTO users (id, the_geom, name) VALUES (3,ST_GeomFromText('POINT(114.313685 30.479379)',4326),'小李');
INSERT INTO users (id, the_geom, name) VALUES (4,ST_GeomFromText('POINT(114.317853 30.479799)',4326),'小张');

现在把小王的坐标位置POINT(114.316559 30.48828)附件的人按距离排序:
select id, name, ST_AsText(the_geom) from users order by the_geom <-> 'SRID=4326;POINT(114.316559 30.48828)'::geometry limit 5;

把小明的坐标位置POINT(114.314008 30.486568)附近的人按距离排序:
select id, name, ST_AsText(the_geom) from users order by the_geom <-> 'SRID=4326;POINT(114.314008 30.486568)'::geometry limit 5;

查找500米以内的人:
select id, name, ST_AsText(the_geom) from users where ST_DWithin(the_geom::geography, ST_GeographyFromText('POINT(114.314008 30.486568)'), 500.0);

并计算出距离(单位:百公里):
select id, name, ST_AsText(u.the_geom), ST_Distance(ST_GeomFromText('POINT(114.314008 30.486568)',4326), u.the_geom) from users as u
where ST_DWithin(the_geom::geography, ST_GeographyFromText('POINT(114.314008 30.486568)'), 500.0)
order by the_geom <-> 'SRID=4326;POINT(114.314008 30.486568)'::geometry;
另一种写法(单位:百公里):
select id, name, ST_AsText(u.the_geom), ST_Distance(ST_GeomFromText('POINT(114.314008 30.486568)',4326), u.the_geom) from users u
where name in ('小明', '小王') order by st_distance(the_geom, ST_GeomFromText('POINT(114.314008 30.486568)',4326));

在PostGIS里面有很多需要使用和掌握的,本文篇幅有限,未展开讲语法细节,更多的语法细节需要参考PostgreSQL关于PostGIS的语法概况介绍。




