基于Tablestore管理海量快递轨迹数据架构实现
快遞軌跡管理
對(duì)于一個(gè)快遞公司,在全國(guó)范圍內(nèi)有著大量的快遞點(diǎn)、快遞員、運(yùn)輸車輛以及倉(cāng)儲(chǔ)中心。而快遞自產(chǎn)生后,就會(huì)在這些地點(diǎn)、人物之間流轉(zhuǎn)。因而,一套完善的快遞管理追蹤系統(tǒng)是快遞公司的重要管理工具;
用戶通過(guò)平臺(tái)客戶端下單后,產(chǎn)生唯一的快遞單號(hào)作為唯一身份標(biāo)識(shí)。快遞除了訂單號(hào),還會(huì)有很多屬性信息,如:郵寄人、郵寄人手機(jī)、郵寄人地址、收件人、快遞類型等信息。生成快遞訂單后,用戶的郵寄物品才會(huì)成為“快遞”。快遞公司配合掃碼機(jī)器,將快遞的流轉(zhuǎn)事件、地點(diǎn)、時(shí)間等信息不定期推送至系統(tǒng)。快遞流轉(zhuǎn)信息不僅可以是簡(jiǎn)單的量化數(shù)據(jù),也可以是描述性文字、地理位置等特殊信息。系統(tǒng)將流轉(zhuǎn)信息記錄成快遞的監(jiān)控?cái)?shù)據(jù),同時(shí)修改快遞狀態(tài)、實(shí)時(shí)位置等。直至快遞送達(dá)收件人手中,結(jié)束快遞生命周期。
通過(guò)系統(tǒng),用戶可以管理自己的歷史郵寄單列表、收件列表,掌握自己郵寄中的快遞軌跡。快遞公司也可以查詢、修改快遞信息、追蹤快遞時(shí)效,并借助海量軌跡監(jiān)控?cái)?shù)據(jù),掌握快遞產(chǎn)生、收件的高頻路線,在高頻位置鋪設(shè)更多的基礎(chǔ)設(shè)施、轉(zhuǎn)移調(diào)度快遞員;
功能需求
面向用戶:
1、用戶在線下單生成快遞單,等候快遞員上門取件;
2、管理歷史訂單列表,了解快遞明細(xì);
3、追蹤特定快遞周轉(zhuǎn)狀態(tài)、運(yùn)送軌跡;
面向平臺(tái):
1、借助掃碼器,實(shí)現(xiàn)快遞周轉(zhuǎn)事件采集、存儲(chǔ);
2、統(tǒng)計(jì)、查詢所有快遞訂單,實(shí)現(xiàn)全訂單的管理:CRUD;
3、掌握所有郵寄中快遞的實(shí)時(shí)位置;
4、掌握任意一個(gè)訂單的周轉(zhuǎn)狀態(tài)、運(yùn)送軌跡;
5、基于歷史快遞數(shù)據(jù),分析快遞時(shí)效;
6、方便掌握高頻地域、路線,為增設(shè)基礎(chǔ)設(shè)施、快遞員提供依據(jù);
等等...
系統(tǒng)樣例,如下所示:官網(wǎng)控制臺(tái)地址:項(xiàng)目樣例
實(shí)現(xiàn)方案
MySQL方案與難點(diǎn)
通常,用戶會(huì)選用MySQL作為方案數(shù)據(jù)庫(kù),因?yàn)镸ySQL作為數(shù)庫(kù)在查詢、分析等功能上有優(yōu)勢(shì),用戶創(chuàng)建兩個(gè)表:訂單表、事件追蹤表實(shí)現(xiàn)對(duì)快遞數(shù)據(jù)的存儲(chǔ)。
但是快遞場(chǎng)景有幾個(gè)強(qiáng)需求:
第一、需要有強(qiáng)大的查詢、統(tǒng)計(jì)能力,實(shí)現(xiàn)快遞單的管理;
第二、對(duì)于海量快遞,有著高并發(fā)寫入需求,對(duì)寫入性能要求較高;
第三、數(shù)據(jù)持續(xù)膨脹,但歷史快遞訂單、事件數(shù)據(jù)多為冷數(shù)據(jù),存儲(chǔ)成本需要盡可能低;
第四、數(shù)據(jù)未來(lái)挖掘潛在價(jià)值較高,需要有較好的計(jì)算生態(tài);
而MySQL方案在面對(duì)第二、第三個(gè)強(qiáng)需求時(shí),劣勢(shì)凸顯,海量并發(fā)、不斷的數(shù)據(jù)膨脹、存儲(chǔ)成本高一直以來(lái)都是關(guān)系型數(shù)據(jù)庫(kù)的痛點(diǎn);
表格存儲(chǔ)方案
選擇表格存儲(chǔ)有以下優(yōu)勢(shì):
其一、表格存儲(chǔ)的多元索引(SearchIndex)功能輕松滿足用戶的多維查詢、GEO檢索、統(tǒng)計(jì)等功能需求;
其二、基于LSM tree打造的分布式NoSQL數(shù)據(jù)庫(kù),輕松支持海量高并發(fā)讀、寫,零運(yùn)維輕松應(yīng)對(duì)數(shù)據(jù)量的不斷膨脹,理論上無(wú)上限。
其三、表格存儲(chǔ)按量計(jì)費(fèi),提供容量型、高性能型兩種實(shí)例,容量型對(duì)冷數(shù)據(jù)更適宜,提供了更低存儲(chǔ)成本。
其四、更重要的,表格存儲(chǔ)擁有較為完善的計(jì)算生態(tài),提供全、增量通道服務(wù),提供流計(jì)算、批計(jì)算一體的計(jì)算體系,對(duì)未來(lái)監(jiān)控?cái)?shù)據(jù)價(jià)值挖掘提供渠道。
表格存儲(chǔ)在時(shí)序場(chǎng)景需求的技術(shù)點(diǎn)上擁有極高的匹配,而基于時(shí)序場(chǎng)景打造的Timestream模型更是將時(shí)序場(chǎng)景通用功能,封裝成易用的場(chǎng)景接口,使用戶更容易的基于表格存儲(chǔ),根據(jù)自身需求設(shè)計(jì)、打造不同特點(diǎn)的軌跡追蹤系統(tǒng);
數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)
基于快遞的時(shí)序,將快遞的屬性信息作為meta數(shù)據(jù),而快遞的周轉(zhuǎn)路徑、狀態(tài)、位置等則為data數(shù)據(jù),下面對(duì)兩類數(shù)據(jù)做簡(jiǎn)單介紹。
快遞元數(shù)據(jù)
meta數(shù)據(jù)管理著快遞的屬性信息,支持指標(biāo)、標(biāo)簽、屬性、地理位置、更新時(shí)間等參數(shù),模型會(huì)為所有屬性創(chuàng)建相應(yīng)的索引,提供多維度條件組合查詢(包含GEO查詢)。其中Identifier是時(shí)間線的標(biāo)識(shí),包含兩部分:name部分(監(jiān)控指標(biāo)標(biāo)識(shí))、tags部分(固有不可變參數(shù)集合)。
在快遞場(chǎng)景中,用戶通常是基于快遞單號(hào)直接定位快遞,因而tags使用空的。而屬性信息則存儲(chǔ)快遞的郵寄人信息、收件人信息、郵寄起/止地址等,location字段,用于最新位置追蹤,可不定期根據(jù)產(chǎn)生新的狀態(tài)周轉(zhuǎn)數(shù)據(jù)時(shí)更新。
快遞軌跡數(shù)據(jù)
data數(shù)據(jù)記錄著快遞的狀態(tài)周轉(zhuǎn)信息,主要為量化數(shù)據(jù)、地理位置、文字表述等任意類型。data數(shù)據(jù)按照+有序排列,因而同一快遞的所有數(shù)據(jù)物理上存在一起,且基于時(shí)間有序。這種數(shù)據(jù)存儲(chǔ)方式,極大的提升了時(shí)間線的查詢效率。對(duì)應(yīng)到快遞軌跡,監(jiān)控?cái)?shù)據(jù)主要記錄了:【who】do【something】@【where】with the location【geo】以及聯(lián)系方式等。
讀寫接口使用介紹
寫數(shù)據(jù)
寫接口根據(jù)數(shù)據(jù)類型分為兩類:meta寫入(新增快遞)、data寫入(快遞周轉(zhuǎn)數(shù)據(jù))
- 新增快遞:當(dāng)用戶通過(guò)系統(tǒng)直接下快遞單后,產(chǎn)生唯一訂單號(hào),加上用戶填寫的快遞單信息組成必要的凱迪數(shù)據(jù)。此時(shí),就會(huì)生成一個(gè)時(shí)間線,產(chǎn)生一個(gè)meta數(shù)據(jù);
- 快遞周轉(zhuǎn):當(dāng)快遞發(fā)生取件、運(yùn)輸周轉(zhuǎn)、派送、取件是,產(chǎn)生的狀態(tài)轉(zhuǎn)變數(shù)據(jù)時(shí),就會(huì)產(chǎn)生一條追蹤數(shù)據(jù),通過(guò)data數(shù)據(jù)的寫接口不定期的寫入;
讀數(shù)據(jù)
與寫數(shù)據(jù)一樣,針對(duì)兩類數(shù)據(jù)提供了兩類讀接口:meta讀取(快遞查詢)、data讀取(查詢快遞軌跡)
- 查詢快遞:根據(jù)快遞號(hào)、寄件人手機(jī)、收件人手機(jī)等信息,獲取對(duì)應(yīng)快遞的列表,掌握所有快遞的最新動(dòng)態(tài);
- 查詢快遞軌跡:基于單個(gè)meta的Identifier,獲取該快遞從產(chǎn)生到結(jié)束整個(gè)生命周期內(nèi)的軌跡周轉(zhuǎn)數(shù)據(jù),可以通過(guò)列表、地圖軌跡展示等方式,直觀的了解快遞的周轉(zhuǎn)過(guò)程;
方案核心代碼
SDK與樣例代碼
SDK使用:
時(shí)序模型Timestream模型集成于表格存儲(chǔ)的SDK中,目前已在4.11.0版本中支持;
代碼開(kāi)源:
https://github.com/aliyun/tablestore-examples/tree/master/demos/MailManagement
建表準(zhǔn)備
在創(chuàng)建完成實(shí)例后,用戶需要通過(guò)時(shí)序模型的sdk創(chuàng)建相應(yīng)的meta表(快遞元數(shù)據(jù))、data表(快遞周轉(zhuǎn)數(shù)據(jù)):
private void init() {AsyncClient asyncClient = new AsyncClient(endpoint, accessKeyId, accessKeySecret, instance);//快遞抽象TimestreamTimestreamDBConfiguration mailConf = new TimestreamDBConfiguration("metaTableName");mailDb = new TimestreamDBClient(asyncClient, mailConf); }public void createTable() {mailDb.createMetaTable(Arrays.asList(//自定義索引new AttributeIndexSchema("fromMobile", AttributeIndexSchema.Type.KEYWORD),new AttributeIndexSchema("fromName", AttributeIndexSchema.Type.KEYWORD),new AttributeIndexSchema("toMobile", AttributeIndexSchema.Type.KEYWORD),new AttributeIndexSchema("toName", AttributeIndexSchema.Type.KEYWORD),new AttributeIndexSchema("toLocation", AttributeIndexSchema.Type.GEO_POINT)));mailDb.createDataTable("dataTableName"); }寫數(shù)據(jù)
數(shù)據(jù)寫入主要分兩部分,meta表創(chuàng)建新快遞、data表采集快遞周轉(zhuǎn)信息
創(chuàng)建快遞單(meta表寫入)
//metaWriter對(duì)應(yīng)meta表,提供讀、寫接口 TimestreamMetaTable mailMetaWriter = mailDb.metaTable();//identifier作為時(shí)間線的身份標(biāo)識(shí)(unique),僅含:快遞單號(hào)ID, TimestreamIdentifier identifier = new TimestreamIdentifier.Builder("mail-id-001").build();//基于identifier創(chuàng)建meta對(duì)象,并為meta設(shè)置更多屬性,Attributes為屬性參數(shù) TimestreamMeta meta = new TimestreamMeta(identifier).addAttribute("fromName", whos.get(Rand.nextInt(whos.size()))).addAttribute("fromMobile", "15812345678").addAttribute("toName", whos.get(Rand.nextInt(whos.size()))).addAttribute("toMobile", "15812345678").addAttribute("toLocation", "30,120");//創(chuàng)建新的時(shí)間線,然后寫入監(jiān)控?cái)?shù)據(jù) mailMetaWriter.put(meta);采集快遞周轉(zhuǎn)事件(data表寫入)
//dataWriter分別對(duì)應(yīng)data表,提供讀、寫接口 TimestreamDataTable mailDataWriter = mailDb.dataTable("mailDataTableName"); TimestreamMeta meta;//meta上一步已經(jīng)構(gòu)建//創(chuàng)建新的時(shí)間線,然后寫入監(jiān)控?cái)?shù)據(jù) mailDataWriter.write(meta.getIdentifier(),new Point.Builder(14500000000, TimeUnit.MILLISECONDS).addField("who", "張三").addField("do", "取件").addField("where", "云棲小鎮(zhèn)").addField("location", "30,120").build() );數(shù)據(jù)讀取
數(shù)據(jù)讀取分為兩類:
快遞訂單多維查詢(meta表讀取)
//reader對(duì)應(yīng)meta表,提供讀、寫接口,此處名字為突出讀功能 TimestreamMetaTable metaReader = mailDb.metaTable();//構(gòu)建篩選條件 Filter filter = AndFilter(Name.equal("mail-id-001"),Attribute.equal("fromMobile", "15812345678") );Iterator<TimestreamMeta> metaIterator = mailDb.metaTable().filter(filter).fetchAll();while (iterator.hasNext()) {TimestreamMeta meta = iterator.next();//deal with metas }快遞軌跡追蹤(data表讀取)
//dataWriter分別對(duì)應(yīng)data表,提供讀、寫接口 TimestreamDataTable dataReader = db.dataTable("dataTableName"); TimestreamMeta meta;//基于已獲取的meta列表,分別獲取每個(gè)快遞的軌跡追蹤Iterator<Point> dataIterator = mailDb.dataTable(mailDataTableName).get(meta.getIdentifier()).fetchAll();while (iterator.hasNext()) {Point point = iterator.next();//deal with pointslong timestamp = point.getTimestamp(TimeUnit.MILLISECONDS);//毫秒單位時(shí)間戳String location = point.getField("location").asString();//獲取該點(diǎn)String類型的位置信息 }
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的基于Tablestore管理海量快递轨迹数据架构实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 深度揭秘“蚂蚁双链通”
- 下一篇: 阿里开发者们的第16个感悟:让阅读源码成