1. 前言:项目中用到了postgreSQL中的earthdistance()函数功能计算地球上两点之间的距离,中文的资料太少了,我找到了一篇英文的、讲的很好的文章 ,特此翻译,希望能够帮助到以后用到earthdistance的同学。

    一、两种可用的选择
    当我们想用Postgres作为GEO函数使用时,我们通常有2中选择(据我所知):

    1.PostGIS: 为postgreSQL提供了高级GEO函数功能。我用了它一段时间,但是它对于我的需求来说太笨重了。
    2.Cube和Earthdistance: 这两个拓展为轻量级的Geo关系实体提供了简单、快速的实现方法。

    二、为什么在数据库服务器端做计算
    这是件非常明显的事。服务器存储了所有的数据,服务器拓展是用C/C++实现的,非常快。为数据表做索引也能加快计算速度。

    三、使用我的选择--Cube and EarthDistance
    作为开始,你应该先建一个数据库(我想你知道该怎么做),然后使它们能用我们的架构。 执行:

    1. CREATE EXTENSION cube;
    2. CREATE EXTENSION earthdistance;

    上面的命令创建了大约40个函数,以后我们做数据查询的时候就可以用了。
    在我们的例子中,我创建了名为events的表,字段有:id(serial), name(varchar 255), lat(double), lng(double)。(别忘了~~)

    四、计算2个坐标之间的距离

    计算2个坐标之间的距离,我们要用到earth_distance(ll_to_earth($latlngcube), ll_to_earth($latlng_cube))这个函数。 earth_distance()函数接受2组坐标值,返回值一个以米为单位的的数值。这能用于很多场景,比如根据某一位置找到离其最近的发生的新闻事件的列表。

    【译者注】这里要提下几个重要的函数:(参考:http://www.postgresql.org/docs/8.3/static/earthdistance.html

    Table F-3. Cube-based earthdistance functions

    Function Returns Description
    earth() float8 Returns the assumed radius of the Earth.
    sec_to_gc(float8) float8 Converts the normal straight line (secant) distance between between two points on the surface of the Earth to the great circle distance between them.
    gc_to_sec(float8) float8 Converts the great circle distance between two points on the surface of the Earth to the normal straight line (secant) distance between them.
    ll_to_earth(float8, float8) earth Returns the location of a point on the surface of the Earth given its latitude (argument 1) and longitude (argument 2) in degrees.
    latitude(earth) float8 Returns the latitude in degrees of a point on the surface of the Earth.
    longitude(earth) float8 Returns the longitude in degrees of a point on the surface of the Earth.
    earth_distance(earth, earth) float8 Returns the great circle distance between two points on the surface of the Earth.
    earth_box(earth, float8) cube Returns a box suitable for an indexed search using the cube @> operator for points within a given great circle distance of a location. Some points in this box are further than the specified great circle distance from the location, so a second check using earth_distance should be included in the query.

    数据库的操作可能就像下面这样:

    1. SELECT events.id events.name, eaerthdiatance(ll_to_earth({currentuserlat}, {currentuserlng}), llto_earth(events.lat, events.lng))
    2. as distancefromcurrentlocation FROM events
    3. ORDER BY distancefromcurretnlocation ASC;

    这将给我们一个很nice的新闻事件列表,按他们的离我们当前位置的距离由近到远排序。第一个是离我们最近的。


    五、找到某个半径范围内的记录

    Cube和Earthdiatance拓展提供的另一个伟大的函数是earth_box(ll_to_earch($latlngcub), $radiusinmetres)。 这个函数通过简单的比较就能到找到某个半径范围内的所有记录。它是靠返回2点之间的“大圆距离”实现的。

    【译者注】大圆距离(Great circle disstance)指的是从球面的一点A出发到达球面上另一点B,所经过的最短路径的长度。一般说来,球面上任意两点A和B都可以与球心确定唯一的大圆,这个大圆被称为黎曼圆,而在大圆上连接这两点的较短的一条弧的长度就是大圆距离。如果想了解更多,请看wiki:大圆距离

    它能用于查询我们城市中所有的新闻事件:

    1. SELECT events.id, events.name FROM events
    2. WHERE earth_box({currentuserlat}, {currentuserlng}, {radiusinmetres}) @> ll_to_earth(events.lat, events.lng);

    这条查询语句仅仅会返回在radius_in_metres指定的半径范围内的记录,非常简单吧!

    六、提高查询速度

    你可能会发现上面的查询有不小的开销。以我的经验,最好对一些字段建立索引。 (下面这条语句假定你又events表, 同时events表有字段lat和lng)

    1. CREATE INDEX ${nameofindex} on events USING gits(lltoearth(lat, lng));

    七、数据类型

    我的应用比较简单,所以我把经纬度(lat和lng)都设成了double类型。这使得我用Node.js开发起来更加快速,而不用再去自己定制针对GIST类型的解决方案。

    八、就这些!

    很神奇,对么?!?我们仅仅用常用的数据类型(double)就足以去用一些GEO函数创建基于地理位置的社交app(【译者注】知乎上的一个回答)!

    ---------------------------
    英语水平有限,如有翻译不周之处,请您指点!

    ------------------------------

    update:

    我使用的postgreSQL语句总结:

    1. /*
    2. * postgreSQL之earthdistance学习笔记
    3. * author: wusuopubupt
    4. * date: 2013-03-31
    5. */
    6. /*创建表*/
    7. CREATE TABLE picture (
    8. id serial PRIMARY KEY ,
    9. p_uid char(12) NOT NULL,
    10. p_key char(23) NOT NULL,
    11. lat real not null,
    12. lng real NOT NULL,
    13. up int NOT NULL,
    14. down int NOT NULL,
    15. ip varchar(15) DEFAULT NULL,
    16. address varchar(256) DEFAULT NULL
    17. );
    18. /*插入记录*/
    19. INSERT INTO picture(p_uid, p_key, lat, lng, up, down, ip, address)
    20. VALUES('aaaabbbbcccc', '2014032008164023279.png', 40.043945, 116.413668, 0, 0, '', '');
    21. /*插入记录*/
    22. INSERT INTO picture(p_uid, p_key, lat, lng, up, down, ip, address)
    23. VALUES('xxxxccccmmmm', '2014032008164023111.png', 40.067183, 116.415230, 0, 0, '', '');
    24. /*选择记录*/
    25. SELECT * FROM picture;
    26. /*更新记录*/
    27. UPDATE picture SET address='LiShuiqiao' WHERE id=1;
    28. UPDATE picture SET address='TianTongyuan' WHERE id=2;
    29. /*对经纬度列创建索引*/
    30. CREATE INDEX ll_idx on picture USING gist(ll_to_earth(lat, lng));
    31. /*根据半径(1000米)选择记录*/
    32. SELECT * FROM picture where earth_box(ll_to_earth(40.059286,116.418773),1000) @> ll_to_earth(picture.lat, picture.lng);
    33. /*选择距离当前用户的距离*/
    34. SELECT picture.id, earth_distance(ll_to_earth(picture.lat, picture.lng), ll_to_earth(40.059286,116.418773))
    35. AS dis FROM picture
    36. ORDER BY dis ASC;
    37. /*
    38. * 以下内容是网上的一篇教程
    39. * 地址:http://www.cse.iitb.ac.in/dbms/Data/Courses/CS631/PostgreSQL-Resources/postgresql-9.2.4/contrib/earthdistance/expected/earthdistance.out
    40. */
    41. --
    42. --  Test earthdistance extension
    43. --
    44. -- In this file we also do some testing of extension create/drop scenarios.
    45. -- That's really exercising the core database's dependency logic, so ideally
    46. -- we'd do it in the core regression tests, but we can't for lack of suitable
    47. -- guaranteed-available extensions.  earthdistance is a good test case because
    48. -- it has a dependency on the cube extension.
    49. --
    50. CREATE EXTENSION earthdistance;  -- fail, must install cube first
    51. ERROR:  required extension "cube" is not installed
    52. CREATE EXTENSION cube;
    53. CREATE EXTENSION earthdistance;
    54. --
    55. -- The radius of the Earth we are using.
    56. --
    57. SELECT earth()::numeric(20,5);
    58. earth
    59. ---------------
    60. 6378168.00000
    61. (1 row)
    62. --
    63. -- Convert straight line distances to great circle distances.把直线距离转成大圆距离
    64. --
    65. SELECT (pi()*earth())::numeric(20,5);
    66. numeric
    67. ----------------
    68. 20037605.73216
    69. (1 row)
    70. SELECT sec_to_gc(0)::numeric(20,5);
    71. sec_to_gc
    72. -----------
    73. 0.00000
    74. (1 row)
    75. --
    76. -- Convert great circle distances to straight line distances.
    77. --
    78. SELECT gc_to_sec(0)::numeric(20,5);
    79. gc_to_sec
    80. -----------
    81. 0.00000
    82. (1 row)
    83. SELECT gc_to_sec(sec_to_gc(2*earth()))::numeric(20,5);
    84. gc_to_sec
    85. ----------------
    86. 12756336.00000
    87. (1 row)
    88. --
    89. -- Set coordinates using latitude and longitude.
    90. -- Extract each coordinate separately so we can round them.
    91. --
    92. SELECT cube_ll_coord(ll_to_earth(0,0),1)::numeric(20,5),
    93. cube_ll_coord(ll_to_earth(0,0),2)::numeric(20,5),
    94. cube_ll_coord(ll_to_earth(0,0),3)::numeric(20,5);
    95. cube_ll_coord | cube_ll_coord | cube_ll_coord
    96. ---------------+---------------+---------------
    97. 6378168.00000 |       0.00000 |       0.00000
    98. (1 row)
    99. SELECT cube_ll_coord(ll_to_earth(360,360),1)::numeric(20,5),
    100. cube_ll_coord(ll_to_earth(360,360),2)::numeric(20,5),
    101. cube_ll_coord(ll_to_earth(360,360),3)::numeric(20,5);
    102. cube_ll_coord | cube_ll_coord | cube_ll_coord
    103. ---------------+---------------+---------------
    104. 6378168.00000 |       0.00000 |       0.00000
    105. (1 row)
    106. --
    107. -- Test getting the latitude of a location.
    108. --
    109. SELECT latitude(ll_to_earth(0,0))::numeric(20,10);
    110. latitude
    111. --------------
    112. 0.0000000000
    113. (1 row)
    114. SELECT latitude(ll_to_earth(45,0))::numeric(20,10);
    115. latitude
    116. ---------------
    117. 45.0000000000
    118. (1 row)
    119. --
    120. -- Test getting the longitude of a location.
    121. --
    122. SELECT longitude(ll_to_earth(0,0))::numeric(20,10);
    123. longitude
    124. --------------
    125. 0.0000000000
    126. (1 row)
    127. SELECT longitude(ll_to_earth(45,0))::numeric(20,10);
    128. longitude
    129. --------------
    130. 0.0000000000
    131. (1 row)
    132. --
    133. -- For the distance tests the following is some real life data.
    134. --
    135. -- Chicago has a latitude of 41.8 and a longitude of 87.6.
    136. -- Albuquerque has a latitude of 35.1 and a longitude of 106.7.
    137. -- (Note that latitude and longitude are specified differently
    138. -- in the cube based functions than for the point based functions.)
    139. --
    140. --
    141. -- Test getting the distance between two points using earth_distance.
    142. --
    143. SELECT earth_distance(ll_to_earth(0,0),ll_to_earth(0,0))::numeric(20,5);
    144. earth_distance
    145. ----------------
    146. 0.00000
    147. (1 row)
    148. SELECT earth_distance(ll_to_earth(0,0),ll_to_earth(0,180))::numeric(20,5);
    149. earth_distance
    150. ----------------
    151. 20037605.73216
    152. (1 row)
    153. --
    154. -- Test getting the distance between two points using geo_distance.
    155. --
    156. SELECT geo_distance('(0,0)'::point,'(0,0)'::point)::numeric(20,5);
    157. geo_distance
    158. --------------
    159. 0.00000
    160. (1 row)
    161. SELECT geo_distance('(0,0)'::point,'(180,0)'::point)::numeric(20,5);
    162. geo_distance
    163. --------------
    164. 12436.77274
    165. (1 row)
    166. --
    167. -- Test getting the distance between two points using the <@> operator.
    168. --
    169. SELECT ('(0,0)'::point <@> '(0,0)'::point)::numeric(20,5);
    170. numeric
    171. ---------
    172. 0.00000
    173. (1 row)
    174. SELECT ('(0,0)'::point <@> '(180,0)'::point)::numeric(20,5);
    175. numeric
    176. -------------
    177. 12436.77274
    178. (1 row)
    179. --
    180. -- Test for points that should be in bounding boxes.
    181. --
    182. SELECT earth_box(ll_to_earth(0,0),
    183. earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))*1.00001) @>
    184. ll_to_earth(0,1);
    185. ?column?
    186. ----------
    187. t
    188. (1 row)
    189. SELECT earth_box(ll_to_earth(0,0),
    190. earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.1))*1.00001) @>
    191. ll_to_earth(0,0.1);
    192. ?column?
    193. ----------
    194. t
    195. (1 row)
    196. --
    197. -- Test for points that shouldn't be in bounding boxes. Note that we need
    198. -- to make points way outside, since some points close may be in the box
    199. -- but further away than the distance we are testing.
    200. --
    201. SELECT earth_box(ll_to_earth(0,0),
    202. earth_distance(ll_to_earth(0,0),ll_to_earth(0,1))*.57735) @>
    203. ll_to_earth(0,1);
    204. ?column?
    205. ----------
    206. f
    207. (1 row)
    208. SELECT earth_box(ll_to_earth(0,0),
    209. earth_distance(ll_to_earth(0,0),ll_to_earth(0,0.1))*.57735) @>
    210. ll_to_earth(0,0.1);
    211. ?column?
    212. ----------
    213. f
    214. (1 row)

Cube and EarthDistance的更多相关文章

  1. 用postgreSQL做基于地理位置的app(zz)

    前言:项目中用到了postgreSQL中的earthdistance()函数功能计算地球上两点之间的距离,中文的资料太少了,我找到了一篇英文的.讲的很好的文章,特此翻译,希望能够帮助到以后用到eart ...

  2. Searching in a Radius using Postgres[Marked]

    Searching in a Radius using Postgres Creating a GEO application has never been easier. You can have ...

  3. 常用 PostgreSQL 脚本

    数据定义 数据库 -- 创建数据库 -- https://www.postgresql.org/docs/current/static/multibyte.html -- database_name, ...

  4. postgresql中的CUBE函数

    数据函数简介添加汇总额外信息 数据 --复杂统计函数 CREATE TABLE t3 (color_type varchar(20), in_date varchar(30),color_count ...

  5. HDU 3584 Cube (三维 树状数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3584 Cube Problem Description Given an N*N*N cube A,  ...

  6. SQLSERVER中的ALL、PERCENT、CUBE关键字、ROLLUP关键字和GROUPING函数

    SQLSERVER中的ALL.PERCENT.CUBE关键字.ROLLUP关键字和GROUPING函数 先来创建一个测试表 USE [tempdb] GO )) GO INSERT INTO [#te ...

  7. 轻量级OLAP(一):Cube计算

    有一个数据多维分析的任务: 日志的周UV: APP的收集量及标注量,TOP 20 APP(周UV),TOP 20 APP标注分类(周UV): 手机机型的收集量及标注量,TOP 20 机型(周UV),T ...

  8. BI cube的前世今生:商业智能BI为什么需要cube技术

    企业中常常会出现这样一幕幕尴尬的场景: 企业的决策人员需要从不同的角度来审视业务,协助他们分析业务,例如分析销售数据,可能会综合时间周期.产品类别.地理分布.客户群类等多种因素来考量.IT人员在每一个 ...

  9. [译]Dynamics AX 2012 R2 BI系列-Cube概览

    https://msdn.microsoft.com/EN-US/library/dd252604.aspx     Cube是一个多维度的结构,它是BI应用开发的基础.本文描述了cube的组成部分, ...

随机推荐

  1. Adobe Edge Animate –svg地图交互-精确的边缘及颜色置换

    Adobe Edge Animate –svg地图交互-精确的边缘及颜色置换 版权声明: 本文版权属于 北京联友天下科技发展有限公司. 转载的时候请注明版权和原文地址. 上一篇我们说到了使用jquer ...

  2. VB.net 字符串 分割 及 重新倒序组装

    ''' <summary> ''' split with ">>>>" , and inverted order ''' </summar ...

  3. [改善Java代码]集合运算时使用更优雅的方式

    在初中代数中,我们经常会求两个集合的并集.交集.差集等,在Java中也存在着此 类运算,那如何实现呢? 一提到此类集合操作,大部分的实现者都会说:对两个集合进行遍历,即可求出结果.是的,遍历可以实现并 ...

  4. [未完成]关于Java网络编程总结

    网络的七层结构: 第一层:物理层,网线. 第二层: 数据链路层,交换机.交换机有IP地址.这一层的数据叫做帧 第三层:网络层,数据包方向的定义,路由器.现在也有具有路由功能的交换机.主要将从下层接收到 ...

  5. [未完成][Mooc]关于IO总结

    整个课程的大纲:1.编码问题.2.File类的使用3.RandomAccessFile的使用4.字节流的使用.5.字符流的使用.6.对象的序列化和反序列化. 视频1:文件的编码Eclipse的一大特点 ...

  6. [未完成][Mooc]关于Linxu的总结(一)

    视频1:Linux之前有个Minix(这个是一个教授用来教学用的)开源的,不是编译过的,不能通过QQ.exe找到其源码.后来Linus这个家伙搞了一个Linux.服务器领域超过百分之八十.linux是 ...

  7. poj 1679 次小生成树

    次小生成树的求法: 1.Prime法 定义一个二维数组F[i][j]表示点i到点j在最小生成树中的路径上的最大权值.有个知识就是将一条不在最小生成树中的边Edge加入最小生成树时,树中要去掉的边就是E ...

  8. SharePoint手机App巅峰对决:rShare 挑战 SharePlus

    真是个移动的时代,当我们去百度,Bing,雅虎等搜索引擎,搜索关键字比如“SharePoint iOS”, “SharePoint 安卓”, “SharePoint iPhone”,“SharePoi ...

  9. WCF简介

    WCF(Windows communication Foundation),顾名思义,就是在windows平台下解决通信的基础框架.WCF做为.NET Framework 3.0的一个组件发布出来的, ...

  10. Google推Android新开发语言Sky:流畅度 秒iOS

    Dart初衷 作为当前市占率最高的智能手机操作系统,Android平台正在吸引着越来越多的开发者. 不过,对用户而言,Android的体验还不够完善,卡顿的情况时有发生.再深入点理解,许多应用的帧率达 ...