更新时间:2022-12-14 GMT+08:00

空间索引

快速示例

create table IF NOT EXISTS carbonTable
(
COLUMN1    BIGINT,
LONGITUDE    BIGINT,
LATITUDE    BIGINT,
COLUMN2    BIGINT,
COLUMN3    BIGINT
)
STORED AS carbondata
TBLPROPERTIES ('SPATIAL_INDEX.mygeohash.type'='geohash','SPATIAL_INDEX.mygeohash.sourcecolumns'='longitude, latitude','SPATIAL_INDEX.mygeohash.originLatitude'='39.850713','SPATIAL_INDEX.mygeohash.gridSize'='50','SPATIAL_INDEX.mygeohash.minLongitude'='115.828503','SPATIAL_INDEX.mygeohash.maxLongitude'='720.000000','SPATIAL_INDEX.mygeohash.minLatitude'='39.850713','SPATIAL_INDEX.mygeohash.maxLatitude'='720.000000','SPATIAL_INDEX'='mygeohash','SPATIAL_INDEX.mygeohash.conversionRatio'='1000000','SORT_COLUMNS'='column1,column2,column3,latitude,longitude');

空间索引介绍

空间数据包括多维点、线、矩形、立方体、多边形和其他几何对象。空间数据对象占据空间的某一区域,称为空间范围,通过其位置和边界描述。空间数据可以是点数据,也可以是区域数据。

  • 点数据:一个点具有一个空间范围,仅通过其位置描述。它不占用空间,没有相关的边界。点数据由二维空间中的点的集合组成。点可以存储为一对经纬度。
  • 区域数据:一个区域有空间范围,有位置和边界。位置可以看作是一个定点在区域内的位置,例如它的质心。在二维中,边界可以可视化为一条线(有限区域,闭环)。区域数据包含一系列区域。

目前仅限于支持点数据,存储点数据。

经纬度可以编码为唯一的GeoID。Geohash是Gustavo Niemeyer发明的公共域地理编码系统,它将地理位置编码为一串由字母和数字组成的短字符串。它是一种分层的空间数据结构,把空间细分为网格形状的桶,是被称为Z阶曲线和通常称为空间填充曲线的许多应用之一。

点在多维中的Z值是简单地通过交织其坐标值的二进制表示来计算的,如下图所示。使用Geohash创建GeoID时,数据按照GeoID排序,而不是按照经纬度排序,数据按照空间就近性排序存储。

建表

GeoHash编码:

create table IF NOT EXISTS carbonTable
(
...
`LONGITUDE`     BIGINT,
`LATITUDE`      BIGINT,
...
)
STORED AS carbondata
TBLPROPERTIES ('SPATIAL_INDEX.mygeohash.type'='geohash','SPATIAL_INDEX.mygeohash.sourcecolumns'='longitude, latitude','SPATIAL_INDEX.mygeohash.originLatitude'='xx.xxxxxx','SPATIAL_INDEX.mygeohash.gridSize'='xx','SPATIAL_INDEX.mygeohash.minLongitude'='xxx.xxxxxx','SPATIAL_INDEX.mygeohash.maxLongitude'='xxx.xxxxxx','SPATIAL_INDEX.mygeohash.minLatitude'='xx.xxxxxx','SPATIAL_INDEX.mygeohash.maxLatitude'='xxx.xxxxxx','SPATIAL_INDEX'='mygeohash','SPATIAL_INDEX.mygeohash.conversionRatio'='1000000','SORT_COLUMNS'='column1,column2,column3,latitude,longitude');

SPATIAL_INDEX:自定义索引处理器。此处理程序允许用户从表结构列集合中创建新的列。新创建的列名与处理程序名相同。处理程序的type和sourcecolumns属性是必需的属性。目前,type属性只支持“geohash”。Carbon提供一个简单的默认实现类。用户可以通过扩展默认实现类来挂载geohash的自定义实现类。该默认处理程序还需提供以下的表属性:

  • SPATIAL_INDEX.xxx.originLatitude:Double类型,坐标原点纬度
  • SPATIAL_INDEX.xxx.gridSize:Int类型,栅格长度(米)
  • SPATIAL_INDEX.xxx.minLongitude:Double类型,最小经度
  • SPATIAL_INDEX.xxx.maxLongitude:Double类型,最大经度
  • SPATIAL_INDEX.xxx.minLatitude:Double类型,最小纬度
  • SPATIAL_INDEX.xxx.maxLatitude:Double类型,最大纬度
  • SPATIAL_INDEX.xxx.conversionRatio:Int类型,将经纬度小数值转换为整型值

用户可以按照上述格式为处理程序添加自己的表属性,并在自定义实现类中访问它们。originLatitude,gridSize及conversionRatio是必选参数,其余属性在Carbon中都是可选的。可以使用“SPATIAL_INDEX.xxx.class”属性指定它们的实现类。

默认实现类可以为每一行的sourcecolumns生成handler列值,并且支持基于sourcecolumns的过滤条件查询。生成的handler列对用户不可见。除SORT_COLUMNS表属性外,任何DDL命令和属性都不允许包含handler列。

  • 生成的handler列默认被视为排序列。如果SORT_COLUMNS不包含任何sourcecolumns,则将handler列追加到现有的SORT_COLUMNS最后。如果在SORT_COLUMNS中已经指定了该handler列,则它在SORT_COLUMNS的顺序将保持不变。
  • 如果SORT_COLUMNS包含任意的sourcecolumns,但是没有包含handler列,则handler列将自动插入到SORT_COLUMNS中的sourcecolumns之前。
  • 如果SORT_COLUMNS需要包含任意的sourcecolumns,那么需要保证handler列出现在sourcecolumns之前,这样handler列才能在排序中生效。

GeoSOT编码:

CREATE TABLE carbontable(
…
longitude DOUBLE,
latitude DOUBLE,
…)
STORED AS carbondata
TBLPROPERTIES ('SPATIAL_INDEX'='xxx',
'SPATIAL_INDEX.xxx.type'='geosot',
'SPATIAL_INDEX.xxx.sourcecolumns'='longitude, latitude',
'SPATIAL_INDEX.xxx.level'='21',
'SPATIAL_INDEX.xxx.class'='org.apache.carbondata.geo.GeoSOTIndex')
表1 参数说明

参数

说明

SPATIAL_INDEX

指定表属性”SPATIAL_INDEX”,空间索引列,列名与该属性的值相同。

SPATIAL_INDEX.xxx.type

必填参数,值为geosot。

SPATIAL_INDEX.xxx.sourcecolumns

必填参数,空间索引列属性,指定计算空间索引的源数据列,需为2个存在的列,且类型为double。

SPATIAL_INDEX.xxx.level

可选参数,用于计算空间索引列。默认值为17,因为该值可以计算出足够精确的结果,同时拥有良好的性能。

SPATIAL_INDEX.xxx.class

可选参数,用于指定geo的实现类,默认为“org.apache.carbondata.geo.GeoSOTIndex”。

使用示例:

create table geosot(
timevalue bigint,
longitude double,
latitude double)
stored as carbondata
TBLPROPERTIES ('SPATIAL_INDEX'='mygeosot',
'SPATIAL_INDEX.mygeosot.type'='geosot',
'SPATIAL_INDEX.mygeosot.level'='21', 'SPATIAL_INDEX.mygeosot.sourcecolumns'='longitude, latitude');

准备数据

  • 准备数据文件1:geosotdata.csv
    timevalue,longitude,latitude
    1575428400000,116.285807,40.084087
    1575428400000,116.372142,40.129503
    1575428400000,116.187332,39.979316
    1575428400000,116.337069,39.951887
    1575428400000,116.359102,40.154684
    1575428400000,116.736367,39.970323
    1575428400000,116.720179,40.009893
    1575428400000,116.346961,40.13355
    1575428400000,116.302895,39.930753
    1575428400000,116.288955,39.999101
    1575428400000,116.17609,40.129953
    1575428400000,116.725575,39.981115
    1575428400000,116.266922,40.179415
    1575428400000,116.353706,40.156483
    1575428400000,116.362699,39.942444
    1575428400000,116.325378,39.963129
  • 准备数据文件2:geosotdata2.csv
    timevalue,longitude,latitude
    1575428400000,120.17708,30.326882
    1575428400000,120.180685,30.326327
    1575428400000,120.184976,30.327105
    1575428400000,120.189311,30.327549
    1575428400000,120.19446,30.329698
    1575428400000,120.186965,30.329133
    1575428400000,120.177481,30.328911
    1575428400000,120.169713,30.325614
    1575428400000,120.164563,30.322243
    1575428400000,120.171558,30.319613
    1575428400000,120.176365,30.320687
    1575428400000,120.179669,30.323688
    1575428400000,120.181001,30.320761
    1575428400000,120.187094,30.32354
    1575428400000,120.193574,30.323651
    1575428400000,120.186192,30.320132
    1575428400000,120.190055,30.317464
    1575428400000,120.195376,30.318094
    1575428400000,120.160786,30.317094
    1575428400000,120.168211,30.318057
    1575428400000,120.173618,30.316612
    1575428400000,120.181001,30.317316
    1575428400000,120.185162,30.315908
    1575428400000,120.192415,30.315871
    1575428400000,120.161902,30.325614
    1575428400000,120.164306,30.328096
    1575428400000,120.197093,30.325985
    1575428400000,120.19602,30.321651
    1575428400000,120.198638,30.32354
    1575428400000,120.165421,30.314834

导入数据

GeoHash默认实现类扩展自定义索引抽象类。如果没有配置handler属性为自定义的实现类,则使用默认的实现类。用户可以通过扩展默认实现类来挂载geohash的自定义实现类。自定义索引抽象类方法包括:

  • Init方法,用来提取、验证和存储handler属性。在失败时抛出异常,并显示错误信息。
  • Generate方法,用来生成索引。它为每行数据生成一个索引数据。
  • Query方法,用来对给定输入生成索引值范围列表。

导入命令同普通Carbon表:

LOAD DATA inpath '/tmp/geosotdata.csv' INTO TABLE geosot OPTIONS ('DELIMITER'= ',');

LOAD DATA inpath '/tmp/geosotdata2.csv' INTO TABLE geosot OPTIONS ('DELIMITER'= ',');

geosotdata.csv和geosotdata2.csv表请参考准备数据

不规则空间集合的聚合查询

查询语句及Filter UDF
  • 根据polygon过滤数据

    IN_POLYGON(pointList)

    UDF输入参数:

    参数

    类型

    说明

    pointList

    String

    将多个点输入为一个字符串,每个点以longitude latitude表示。经纬度间用空格分隔,每对经纬度用逗号分隔,字符串首尾经纬度一致。

    UDF输出参数:

    参数

    类型

    说明

    inOrNot

    Boolean

    判断数据是否在指定的polygon_list之内。

    使用示例:

    select longitude, latitude from geosot where IN_POLYGON('116.321011 40.123503, 116.137676 39.947911, 116.560993 39.935276, 116.321011 40.123503');

  • 根据polygon列表过滤数据。

    IN_POLYGON_LIST(polygonList, opType)

    UDF输入参数:

    参数

    类型

    说明

    polygonList

    String

    将多个polygon输入为一个字符串,每个polygon以POLYGON ((longitude1 latitude1, longitude2 latitude2, …))表示。注意“POLYGON”后有空格,经纬度间用空格分隔,每对经纬度用逗号分隔,一个polygon的首尾经纬度一致。IN_POLYGON_LIST必须输入2个以上polygon。

    一个polygon示例:

    POLYGON ((116.137676 40.163503, 116.137676 39.935276, 116.560993 39.935276, 116.137676 40.163503))

    opType

    String

    对多个polygon进行并交差操作。

    目前支持的操作类型:

    • OR:A U B U C (假设输入了三个POLYGON,A、B、C)
    • AND:A ∩ B ∩ C

    UDF输出参数:

    参数

    类型

    说明

    inOrNot

    Boolean

    判断数据是否在指定的polygon_list之内。

    使用示例:

    select longitude, latitude from geosot where IN_POLYGON_LIST('POLYGON ((120.176433 30.327431,120.171283 30.322245,120.181411 30.314540, 120.190509 30.321653,120.185188 30.329358,120.176433 30.327431)), POLYGON ((120.191603 30.328946,120.184179 30.327465,120.181819 30.321464, 120.190359 30.315388,120.199242 30.324464,120.191603 30.328946))', 'OR');

  • 根据polyline列表过滤数据。

    IN_POLYLINE_LIST(polylineList, bufferInMeter)

    UDF输入参数:

    参数

    类型

    说明

    polylineList

    String

    将多个polyline输入为一个字符串,每个polyline以LINESTRING (longitude1 latitude1, longitude2 latitude2, …)表示。注意“LINESTRING”后有空格,经纬度间用空格分隔,每组经纬度用逗号分隔。

    对多个polyline区域内的数据会输出并集结果。

    一个polyline示例:

    LINESTRING (116.137676 40.163503, 116.137676 39.935276, 116.260993 39.935276)

    bufferInMeter

    Float

    polyline的buffer距离,单位为米。末端使用直角创建缓冲区。

    UDF输出参数:

    参数

    类型

    说明

    inOrNot

    Boolean

    判断数据是否在指定的polyline_list之内。

    使用示例:

    select longitude, latitude from geosot where IN_POLYLINE_LIST('LINESTRING (120.184179 30.327465, 120.191603 30.328946, 120.199242 30.324464, 120.190359 30.315388)', 65);
  • 根据GeoId区间列表过滤数据。

    IN_POLYGON_RANGE_LIST(polygonRangeList, opType)

    UDF输入参数:

    参数

    类型

    说明

    polygonRangeList

    String

    将多个rangeList输入为一个字符串,每个rangeList以RANGELIST (startGeoId1 endGeoId1, startGeoId2 endGeoId2, …)表示。注意“RANGELIST”后有空格,首尾GeoId间用空格分隔,每组GeoId range用逗号分隔。

    一个rangeList示例:

    RANGELIST (855279368848 855279368850, 855280799610 855280799612, 855282156300 855282157400)

    opType

    String

    对多个rangeList进行并交差操作。

    目前支持的操作类型:

    • OR:A U B U C (假设输入了三个RANGELIST,A、B、C)
    • AND:A ∩ B ∩ C

    UDF输出参数:

    参数

    类型

    说明

    inOrNot

    Boolean

    判断数据是否在指定的polyRange_list之内。

    使用示例:

    select mygeosot, longitude, latitude from geosot where IN_POLYGON_RANGE_LIST('RANGELIST (526549722865860608 526549722865860618, 532555655580483584 532555655580483594)', 'OR');
  • polygon连接查询

    IN_POLYGON_JOIN(GEO_HASH_INDEX_COLUMN, POLYGON_COLUMN)

    两张表做join查询,一张表为空间数据表(有经纬度列和GeoHashIndex列),另一张表为维度表,保存polygon数据。

    查询使用IN_POLYGON_JOIN UDF,参数GEO_HASH_INDEX_COLUMN和polygon表的POLYGON_COLUMN。Polygon_column列是一系列的点(经纬度列)。Polygon表的每一行的第一个点和最后一个点必须是相同的。Polygon表的每一行的所有点连接起来形成一个封闭的几何对象。

    UDF输入参数:

    参数

    类型

    说明

    GEO_HASH_INDEX_COLUMN

    Long

    空间数据表的GeoHashIndex列。

    POLYGON_COLUMN

    String

    Polygon表的polygon列,数据为polygon的字符串表示。例如,一个polygon是POLYGON ((longitude1 latitude1, longitude2 latitude2, …))

    使用示例:

    CREATE TABLE polygonTable(
    polygon string,
    poiType string,
    poiId String)
    STORED AS carbondata;
    
    insert into polygonTable select 'POLYGON ((120.176433 30.327431,120.171283 30.322245, 120.181411 30.314540,120.190509 30.321653,120.185188 30.329358,120.176433 30.327431))','abc','1';
    
    insert into polygonTable select 'POLYGON ((120.191603 30.328946,120.184179 30.327465, 120.181819 30.321464,120.190359 30.315388,120.199242 30.324464,120.191603 30.328946))','abc','2';
    
    select t1.longitude,t1.latitude from geosot t1 
    inner join 
    (select polygon,poiId from polygonTable where poitype='abc') t2 
    on in_polygon_join(t1.mygeosot,t2.polygon) group by t1.longitude,t1.latitude;

  • range_list连接查询

    IN_POLYGON_JOIN_RANGE_LIST(GEO_HASH_INDEX_COLUMN, POLYGON_COLUMN)

    同IN_POLYGON_JOIN,使用IN_POLYGON_JOIN_RANGE_LIST UDF关联空间数据表和polygon维度表,关联基于Polygon_RangeList。直接使用range list可以避免polygon到range list的转换。

    UDF输入参数:

    参数

    类型

    说明

    GEO_HASH_INDEX_COLUMN

    Long

    空间数据表的GeoHashIndex列。

    POLYGON_COLUMN

    String

    Polygon表的rangelist列,数据为rangeList的字符串。例如,一个rangelist是RANGELIST (startGeoId1 endGeoId1, startGeoId2 endGeoId2, …)

    使用示例:

    CREATE TABLE polygonTable(
    polygon string,
    poiType string,
    poiId String)
    STORED AS carbondata;
    
    insert into polygonTable select 'RANGELIST (526546455897309184 526546455897309284, 526549831217315840 526549831217315850, 532555655580483534 532555655580483584)','xyz','2';
    
    select t1.*
    from geosot t1
    inner join
    (select polygon,poiId from polygonTable where poitype='xyz') t2
    on in_polygon_join_range_list(t1.mygeosot,t2.polygon);

空间索引工具类UDF
  • GeoID转栅格行列号。

    GeoIdToGridXy(geoId)

    UDF输入参数:

    参数

    类型

    说明

    geoId

    Long

    根据GeoId计算栅格行列号。

    UDF输出参数:

    参数

    类型

    说明

    gridArray

    Array[Int]

    返回该geoid所包含的栅格行列号,以数组的方式返回,第一位为行,第二位为列。

    使用示例:

    select longitude, latitude, mygeohash, GeoIdToGridXy(mygeohash) as GridXY from geoTable;
  • 经纬度转GeoID。

    LatLngToGeoId(latitude, longitude oriLatitude, gridSize)

    UDF输入参数:

    参数

    类型

    说明

    longitude

    Long

    经度,注:转换后的整数类型。

    latitude

    Long

    纬度,注:转换后的整数类型。

    oriLatitude

    Double

    原点纬度,计算GeoId需要参数。

    gridSize

    Int

    栅格大小,计算GeoId需要参数。

    UDF输出参数:

    参数

    类型

    说明

    geoId

    Long

    通过编码获得一个表示经纬度的数。

    使用示例:

    select longitude, latitude, mygeohash, LatLngToGeoId(latitude, longitude, 39.832277, 50) as geoId from geoTable;
  • GeoID转经纬度。

    GeoIdToLatLng(geoId, oriLatitude, gridSize)

    UDF输入参数:

    参数

    类型

    说明

    geoId

    Long

    根据GeoId计算经纬度。

    oriLatitude

    Double

    原点纬度,计算经纬度需要参数。

    gridSize

    Int

    栅格大小,计算经纬度需要参数。

    由于GeoId由栅格坐标生成,坐标为栅格中心点,则计算出的经纬度是栅格中心点经纬度,与生成该GeoId的经纬度可能有[0度~半个栅格度数]的误差。

    UDF输出参数:

    参数

    类型

    说明

    latitudeAndLongitude

    Array[Double]

    返回该geoid所表示的栅格的中心点的经纬度坐标,以数组的方式返回,第一位为latitude,第二位为longitude。

    使用示例:

    select longitude, latitude, mygeohash, GeoIdToLatLng(mygeohash, 39.832277, 50) as LatitudeAndLongitude from geoTable;
  • 计算金字塔模型向上汇聚一层的GeoID。

    ToUpperLayerGeoId(geoId)

    UDF输入参数:

    参数

    类型

    说明

    geoId

    Long

    根据输入GeoId计算金字塔模型上一层GeoId。

    UDF输出参数:

    参数

    类型

    说明

    geoId

    Long

    金字塔模型上一层GeoId。

    使用示例:

    select longitude, latitude, mygeohash, ToUpperLayerGeoId(mygeohash) as upperLayerGeoId from geoTable;
  • 输入polygon获得GeoID范围列表。

    ToRangeList(polygon, oriLatitude, gridSize)

    UDF输入参数:

    参数

    类型

    说明

    polygon

    String

    输入polygon字符串,用一组经纬度表示。

    经纬度间用空格分隔,每对经纬度间用逗号分隔,首尾经纬度一致。

    oriLatitude

    Double

    原点纬度,计算GeoId需要参数。

    gridSize

    Int

    栅格大小,计算GeoId需要参数。

    UDF输出参数:

    参数

    类型

    说明

    geoIdList

    Buffer[Array[Long]]

    将polygon转换为一串geoid的范围列表。

    使用示例:

    select ToRangeList('116.321011 40.123503, 116.137676 39.947911, 116.560993 39.935276, 116.321011 40.123503', 39.832277, 50) as rangeList from geoTable;
  • 计算金字塔模型向上汇聚一层的longitude。

    ToUpperLongitude (longitude, gridSize, oriLat)

    UDF输入参数:

    参数

    类型

    说明

    longitude

    Long

    输入longitude,用一个长整型表示。

    gridSize

    Int

    栅格大小,计算longitude需要参数。

    oriLatitude

    Double

    原点纬度,计算longitude需要参数。

    UDF输出参数:

    参数

    类型

    说明

    longitude

    Long

    返回上一层的longitude。

    使用示例:

    select ToUpperLongitude (-23575161504L, 50, 39.832277) as upperLongitude from geoTable;
  • 计算金字塔模型向上汇聚一层的Latitude。

    ToUpperLatitude(Latitude, gridSize, oriLat)

    UDF输入参数:

    参数

    类型

    说明

    latitude

    Long

    输入latitude,用一个长整型表示。

    gridSize

    Int

    栅格大小,计算latitude需要参数。

    oriLatitude

    Double

    原点纬度,计算latitude需要参数。

    UDF输出参数:

    参数

    类型

    说明

    Latitude

    Long

    返回上一层的latitude。

    使用示例:

    select ToUpperLatitude (-23575161504L, 50, 39.832277) as upperLatitude from geoTable;

  • 经纬度转GeoSOT

    LatLngToGridCode(latitude, longitude, level)

    UDF输入参数:

    参数

    类型

    说明

    latitude

    Double

    输入latitude。

    longitude

    Double

    输入longitude。

    level

    Int

    输入level,值区间[0-32]。

    UDF输出参数:

    参数

    类型

    说明

    geoId

    Long

    通过GeoSOT编码获得一个表示经纬度的数。

    使用示例:

    select LatLngToGridCode(39.930753, 116.302895, 21) as geoId;