暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

社区贡献 | 新Feature发布:TuGraph-DB支持空间数据类型

TuGraph 2024-07-15
656

点击蓝字,关注我们

本文介绍了来自北京大学的TuGraph开源社区开发者孙同学的工作,孙同学基于开源图数据库TuGraph-DB的开发,支持了空间数据类型。文章将从空间数据类型的应用、在TuGraph-DB中的实现以及使用三个方面进行介绍。孙同学的工作丰富了TuGraph-DB功能,因此获得“TuGraph社区年度优秀贡献者”,再次感谢孙同学的贡献,项目功能正在持续完善中,也欢迎更多伙伴加入TuGraph社区一起共建。


近年来,地理数据类型/空间数据类型(Spatial Data Type)在图数据库中的应用价值显著,它不仅增强了数据的表达能力,还促进了跨领域数据的融合分析,尤其在社交网络、地图探索、城市规划等关键领域展现了强大的实用价值。

空间数据类型在图数据库中的应用案例

空间地理数据也是天然适合使用图数据库的一种场景,我们先来看看在图数据库中使用空间数据的几个经典场景:

场景案例一:判断某空间类型内的坐标

如上图1和图2所示,日常生活中我们通常需要在地图中查询距离自己一定距离内的景点/美食信息。对应的在图数据库中,即为判断哪些坐标在以某点为中心的圆形或矩形区域内,对应的Cypher查询语句如下:

# 判断在圆形区域内
WITH point({latitude: $latitude, longitude:$longitude}) AS radiusCenter
MATCH (p:Point)-[:HAS_GEOMETRY]-(poi:PointOfInterest)-[:HAS_TAGS]->(t:Tags)
    WHERE point.distance(p.location, radiusCenter) < $radius
RETURN p {
    latitude: p.location.latitude,
    longitude: p.location.longitude,
    name: poi.name,
    categories: labels(poi),
    tags: t{.*}                       
} AS point

# 判断在矩形区域内
MATCH (p:Point)-[:HAS_GEOMETRY]-(poi:PointOfInterest)-[:HAS_TAGS]->(t:Tags)
   WHERE point.withinBBox(
        p.location,
       point({longitude: $lowerLeftLon, latitude: $lowerLeftLat}),
       point({longitude: $upperRightLon, latitude: $upperRightLat})
   )
RETURN p {
  latitude: p.location.latitude,
  longitude: p.location.longitude,
  name: poi.name,
  categories: labels(poi),
  tags: t{.*}
} AS point

场景案例二:判断路径与某空间类型是否重合

如上图3所示,移动物体的行动轨迹可以被抽象成一条线,这条轨迹往往伴随着时序信息。日常生活中,有时候我们想知道哪部分行动轨迹和给定区域有重合。对应在图数据库中,即判断一系列坐标中哪些坐标落在在空间类型内。对应的Cypher查询语句如下:

WITH point({latitude: $latitude, longitude: $longitude}) AS radiusCenter
MATCH (g: Geometry)
    WHERE any(
        p IN g.coordiates WHERE point.distance(p, radiusCenter) < $radius
    )
RETURN [n IN g.coordinates | [n.latitude, n.longitude]] AS route

空间数据类型在TuGraph-DB中的实现

需求分析

结合上述案例,我们可以分析总结出对空间数据类型的需求:

  • • 支持不同坐标系下(包括地球地理坐标系,平面几何坐标系等)不同空间数据类型(包括Point、LineString,、Polygon)的存储与创建

  • • 支持不同坐标系下的常见空间查询操作, 包括Distance、BoundingBox、Disjoint(判断两个数据是否相交)的查询等

  • • 支持空间数据索引(R-Tree)

  • • 支持常见空间数据格式的导入(ESRI Shapefile data OpenStreetMap)

  • • 支持空间数据的可视化

空间数据类型的表示

空间数据类型可以用不同的坐标系来表示,EPSG[1]是一个标准化的地理空间参考系统标识符集合, 用于标识不同的地理空间参考系统,包括坐标系统、地理坐标系、投影坐标系等。通常使用EPSG编码表示数据的坐标系。行业内一般采用

  • • WGS84坐标系(没错,就是GPS系统的坐标系),标识符为EPSG 4326

  • • Cartesian(笛卡尔)坐标系(没错,就是你高中数学学的直角坐标系),标识符为EPSG 7203

WGS84是全球定位系统(GPS)的基础,允许全球的GPS接收器确定精确位置。几乎所有现代GPS设备都是基于WGS84坐标系来提供位置信息。在地图制作和GIS(地图制作和地理信息系统)领域,WGS84被广泛用于定义地球上的位置。这包括各种类型的地图创建、空间数据分析和管理等。

Cartesian(笛卡尔)坐标系,又称直角坐标系,是一种最基本、最广泛应用的坐标系统。它通过两条数轴定义一个平面,三条数轴定义一个空间,这些轴互相垂直,在数学、物理、工程、天文和许多其他领域中有着广泛的应用。

空间数据类型的实现

OGC(Open Geospatial Consortium) 定义了空间数据的标准表示格式,分别为EWKT(extended well known text)与EWKB(extended well known binary)格式,用于在不同系统和平台之间交换和存储空间数据,现已被广泛采用。

EWKT

EWKT格式数据如下所示,先指定空间数据类型,再在括号内指定具体的坐标,一个坐标对表示一个点,每个坐标对之间用逗号隔开。其中,对于Polygon类型的数据,第一个坐标对需要与最后一个坐标对相同,形成闭合的面。

SRID=s;POINT (<x> <y>)
SRID=s;LINESTRING(<x1> <y1>, <x2> <y2>, …)

注: SRID默认为4326, 可以不指定

EWKB

EWKB格式数据如下图所示,

  • • 第0-1位: 表示编码方式 00表示大端法,01表示小端法

  • • 第2 - 5位: 空间数据类型

    • • 0100: point

    • • 0200: linestring

    • • 0300: polygon

  • • 第6 - 9位: 数据维度

    • • 0020: 二维

    • • 0030: 三维

  • • 第10 - 17位: 坐标系的EPSG编码

  • • 第18 - n位: double类型的坐标对的16进制表示

注: 对于POINT类型,其EWKB格式为定长存储,固定长度为50,而对于其他类型,则为不定长。

实现思路

在TuGraph-DB的实现,基于boost geometry库的基础上进行封装,用EWKB格式存储数据,其中Point类型为定长存储50,其余皆为变长存储。我们支持了Point, Linestring与Polygon三种类型,同时支持了WGS84, CARTESIAN两种坐标系,数据类型与坐标系均可根据需要拓展。

在TuGraph-DB中使用空间数据类型

定义空间数据类型

TuGraph-DB当前已经支持Point、Linestring与Polygon三种类型

  • • Point:点,创建方式例如POINT(2.0, 2.0, 7203)

  • • Linestring:折线,创建方式例如LINESTRING(0 2,1 1,2 0)

  • • Polygon:多边形,创建方式例如POLYGON((0 0,0 7,4 2,2 0,0 0))

其中坐标点都是double型

相关函数介绍

创建空间数据相关函数,以Point为例:

函数名描述输入参数返回值类型
Point()根据坐标或EWKB创建Point坐标对(double, double) EWKB format(string)point
PointWKB()根据WKB与指定SRID创建PointWKB format(string) , SRID(int)point
PointWKT()根据WKT与指定SRID创建PointWKT format(string) , SRID(int)point

查询用相关函数:

函数名描述输入参数返回值类型
Distance()计算两个空间数据间的距离

注:要求坐标系相同Spatial data1, Spatial data2double
Disjoint()判断两个空间数据是否相交

注:开发中Spatial data1, Spatial data2bool
WithinBBox()判断某个空间数据是否在给定的长方形区域内

注:开发中Spatial data, Point1bool

使用实例如下:

# 创建包含空间数据类型的点模型
CALL db.createVertexLabel('food', 'id', 'id', int64, false, 'name', string, true,'pointTest',point,true) 

# 插入标记美食点的数据
CREATE (n:food {id:10001, name: 'aco Bell',pointTest:point(3.0,4.0,7203)}) RETURN n

# 创建具有折线属性的点模型
CALL db.createVertexLabel('lineTest', 'id', 'id', int64, false, 'name', string, true,'linestringTest',linestring,true)

# 插入具有折线属性的点数据
CREATE (n:lineTest {id:102, name: 'Tom',linestringTest:linestringwkt('LINESTRING(0 2,1 1,2 0)', 7203)}) RETURN n

# 创建具有多边型属性的点模型
CALL db.createVertexLabel('polygonTest', 'id', 'id', int64, false, 'name', string, true,'polygonTest',polygon,true)

# 插入具有多边型属性的点数据
CREATE (n:polygonTest {id:103, name: 'polygonTest',polygonTest:polygonwkt('POLYGON((0 0,0 7,4 2,2 0,0 0))', 7203)}) RETURN n

Demo演示:基于地理位置个性化推荐的美食探索

在本章节中,我们将探索如何利用TuGraph-DB图数据库的地理空间功能,构建一个生动有趣的美食探索应用,“人”与“美食”通过地理位置紧密相连,实现个性化美食推荐。

数据模型设计

定义两种核心节点类型:

  • • Food(美食)点:每一家餐厅或小吃店都可以作为一个Food节点,其属性包括但不限于名称、地址、评分、美食类别等。特别地,我们将在每个Food节点上附加地理坐标信息,用以精确记录其地理位置。

  • • Person(人物)点:代表应用的用户,属性包含用户名、当前位置等。用户的当前位置同样通过地理坐标表示,便于后续的地理空间查询。

# 创建Schema
CALL db.createVertexLabel('food', 'id', 'id', int64, false, 'name', string, true,'pointTest',point,true,'mark',double,true)
CALL db.createVertexLabel('person', 'id', 'id', int64, false, 'name', string, true,'pointTest',point,true)

# 插入示例数据 food
CREATE (n:food {id:10001, name: 'Starbucks',pointTest:point(1.0,1.0,7203),mark:4.8}) RETURN n
CREATE (n:food {id:10002, name: 'KFC',pointTest:point(2.0,1.0,7203),mark:4.5}) RETURN n
CREATE (n:food {id:10003, name: 'Pizza Hut',pointTest:point(2.0,5.0,7203),mark:4.5}) RETURN n
CREATE (n:food {id:10004, name: 'Taco Bell',pointTest:point(3.0,4.0,7203),mark:4.7}) RETURN n
CREATE (n:food {id:10005, name: 'Pizza Fusion',pointTest:point(5.0,3.0,7203),mark:4.9}) RETURN n
CREATE (n:food {id:10006, name: 'HaiDiLao Hot Pot',pointTest:point(2.0,2.0,7203),mark:4.8}) RETURN n
CREATE (n:food {id:10007, name: 'Lao Sze Chuan',pointTest:point(4.0,3.0,7203),mark:4.7}) RETURN n

# 插入示例数据 person
CREATE (n:person {id:1, name: 'Tom',pointTest:point(3.0,3.0,7203)}) RETURN n

构建美食探索查询

能够根据用户的当前位置,寻找距离2.5以内的美食,根据距离进行升序排列,返回距离和评分。

MATCH (n:person{id:1}), (m:food)
WITH n.pointTest AS p1, m.pointTest AS p2, m.name AS food, m.mark AS mark
CALL spatial.distance(p1,p2) YIELD distance 
WHERE distance < 2.5
RETURN food,distance,mark
ORDER BY distance

此查询首先匹配特定的Person节点,然后找到所有Food节点,利用自定义的distance函数计算Person节点当前位置与每个Food节点之间的直线距离,筛选出距离在2.5之内的美食。最后,按照美食的距离升序排列结果,附带评分参考,为用户提供最优质的推荐。

未来展望

孙同学的工作,让TuGraph-DB具备了处理地理空间数据的能力。未来,TuGraph-DB将来会继续实现Disjoint() 、WithinBBox()等更多的函数,以及实现更高级的索引、数据导入、可视化等功能,丰富更多的使用场景。作为开源项目,TuGraph社区也欢迎大家一起参与共建开发地理空间功能。

引用链接

[1]
 EPSG: https://epsg.io/


作者:TuGraph社区优秀开发者 孙同学

校对:戚仕鹏、张文豪


·END·



欢迎关注TuGraph代码仓库✨

TuGraph-DB 图数据库

https://github.com/tugraph-family/tugraph-db

TuGraph-Analytics 流式图计算引擎

https://github.com/tugraph-family/tugraph-analytics

TuGraph-AGL 图学习引擎
https://github.com/tugraph-family/tugraph-antgraphlearning




最后修改时间:2024-07-15 11:08:00
文章转载自TuGraph,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论