本文介绍通过云原生内存数据库Tair的GIS结构,实现同城购业务。
背景说明
随着同城购业务的兴起,品牌商家在其众多门店中判断出距离消费者最近门店的场景越来越流行。
商家通常会对每一个门店设置可销售的范围,可能是以行政区划分,也可能是不规则形状的区域,或按照半径圈选。如果消费者坐标在销售范围内,就认为该门店可以对该消费者进行销售,否则,则不可销售。此模型为:判断点(消费者)和多边形(门店销售范围)是否为包含关系。
该方案的传统架构通常使用MySQL或PostGIS数据库,虽然其对GIS相关能力有专业的支持,API也比较完备,但是由于MySQL或PostGis数据库本身磁盘存储的特性,查询速度较慢,特别是在数据量较大的场景下,会产生多次磁盘读IO,容易导致业务查询超时。
您可以使用TairGIS能力构建新一代判店系统,TairGIS底层使用RTree结构,支持常见的Contains、Within、Intersects等关系判断,可以在毫秒(ms)级别返回查询结果。更多信息请参见GIS。
方案概述
将某品牌旗下各门店的销售范围存入GIS中。
根据消费者GPS坐标,查询可进行销售服务的门店。
代码示例
本示例的Python版本为3.8,且已安装Tair-py依赖,Tair-py的快捷安装命令为:pip3 install tair
。
# -*- coding: utf-8 -*-
# !/usr/bin/env python
from typing import Dict
from tair import Tair
from tair import ResponseError
def get_tair() -> Tair:
"""
该方法用于连接Tair实例。
* host:Tair实例连接地址。
* port:Tair实例的端口号,默认为6379。
* password:Tair实例的密码(默认账号)。若通过自定义账号连接,则密码格式为“username:password”。
"""
tair: Tair = Tair(
host="r-8vb************.redis.zhangbei.rds.aliyuncs.com",
port=6379,
db=0,
password="D******23",
decode_responses=True
)
return tair
def add_brand_store(brandID: str, mapping: Dict[str, str]) -> bool:
"""
该方法为通过GIS.ADD命令,将品牌(brandID)下的各门店(storeID)与其销售范围(store_wkt)存入GIS中。
"""
try:
tair = get_tair()
ret = tair.gis_add(brandID, mapping)
return ret == 1
except ResponseError as e:
print(e)
return False
def get_brand_all(brandID):
"""
该方法为通过GIS.GETALL命令,获取某品牌的全部门店及其对应销售范围。
"""
try:
tair = get_tair()
return tair.gis_getall(brandID)
except:
return None
def get_service_store(brandID: str, user_location: str):
"""
根据消费者坐标(user_location),查询可进行销售服务的门店。
"""
try:
tair = get_tair()
return tair.gis_contains(brandID, user_location)
except:
return None
if __name__ == "__main__":
tair = get_tair()
# 添加“brand1”品牌的2家门店销售范围。
add_brand_store(
"brand1",
{
"store_1": "POLYGON ((120.14772 30.19513, 120.15370 30.17838, 120.19385 30.18011, 120.18853 30.20817))",
"store_2": "POLYGON ((120.18986 30.20852, 120.19651 30.17988, 120.22512 30.17978, 120.21667 30.22292))"
},
)
print("查询“brand1”品牌的所有门店及销售范围:")
print(get_brand_all('brand1'))
print("查询可对消费者(120.19707 30.19539)进行销售服务的门店信息:")
print(get_service_store('brand1', 'POINT(120.19707 30.19539)'))
本示例的正确执行结果如下:
查询“brand1”品牌的所有门店及销售范围:
['store_1', 'POLYGON((120.14772 30.19513,120.1537 30.17838,120.19385 30.18011,120.18853 30.20817))', 'store_2', 'POLYGON((120.18986 30.20852,120.19651 30.17988,120.22512 30.17978,120.21667 30.22292))']
查询可对消费者(120.19707 30.19539)进行销售服务的门店信息:
[1, ['store_2', 'POLYGON((120.18986 30.20852,120.19651 30.17988,120.22512 30.17978,120.21667 30.22292))']]
结果说明:消费者(120.19707 30.19539)的可服务门店为store_2
。
总结
同城购、买菜、本地商超等应用均可通过TairGIS数据结构,方便地实现地理相关的计算,同时也能满足用户对高性能的需求。