基于Tablestore的一站式物联网存储解决方案-数据操作篇

简介: ## 前言上一章节介绍了共享充电宝场景的表结构设计。本章节主要为大家介绍如何使用表格存储Tabelstore数据表实现基本数据读写、批量更新,以及利用多元索引特性实现多维度查询功能。## 准备工作- 测试数据说明| 数据表 | 数据表名 | 数据行数 | 说明 || --- | --- | --- | --- || 元数据表 | cabinet | 一千万行 | 模拟一千万台机柜 |

前言

上一章节介绍了共享充电宝场景的表结构设计。本章节主要为大家介绍如何使用表格存储Tabelstore数据表实现基本数据读写、批量更新,以及利用多元索引特性实现多维度查询功能。

准备工作

  • 测试数据说明
数据表 数据表名 数据行数 说明
元数据表 cabinet 一千万行 模拟一千万台机柜
订单数据表 order 五千万行 模拟五千万条订单数据
元数据时序表 cabinet_time 一亿行 模拟跟踪一万台机柜元数据,十分钟上报一次,共一万个时序点。
说明:Dataworks可用于OSS与Tablestore之间做数据离线迁移。本场景中的迁移脚本可参考 Github中OSStoOTS.txt。关于Dataworks的介绍可参考 MaxCompute官方文档
  • 测试数据样例

数据表读写

在共享充电宝场景中,新增机柜、机柜下线、租借、归还、查看订单这些业务操作映射到数据库操作中均可看作是对数据表中行的新增、删除、更新、读取。数据操作的方法如下:

说明:更多关于基于主键的数据操作请参考 单行数据操作多行数据操作
  • 新增机柜。可看做在元数据表cabinet中新增一行记录。下面提供了控制台操作截图和SDK代码片段。

PutRowRequest putRowRequest = new PutRowRequest();
//指定表名
RowPutChange rowPutChange = new RowPutChange("cabinet");
//指定主键
rowUpdateChange.setPrimaryKey(PrimaryKeyBuilder.createPrimaryKeyBuilder()           .addPrimaryKeyColumn("cabinet_Md5ID",PrimaryKeyValue.fromString(Md5ID))
.addPrimaryKeyColumn("cabinet_ID",PrimaryKeyValue.fromString(ID)).build());
//添加机柜经纬度
rowPutChange.addColumn("cabinet_geo", ColumnValue.fromString(geo));
//添加机柜位置
rowPutChange.addColumn("cabinet_location",ColumnValue.fromString(position));
//添加机柜所在省份
rowPutChange.addColumn("cabinet_province",ColumnValue.fromString(province));
putRowRequest.setRowChange(rowPutChange);
//发起新增请求
client.putRow(putRowRequest);
  • 租借充电宝。可看做两个步骤。1、订单数据表order写入一条记录。2、更新元数据表cabiet对应的机柜元数据信息。这里主要介绍更新元数据表的操作步骤。
注意:只可对属性列的值进行更新,主键值无法更新。
UpdateRowRequest updateRowRequest = new UpdateRowRequest();
//指定表名 
RowUpdateChange rowUpdateChange = new RowUpdateChange("cabinet");
//指定主键
rowUpdateChange.setPrimaryKey(PrimaryKeyBuilder.createPrimaryKeyBuilder()           .addPrimaryKeyColumn("cabinet_Md5ID",PrimaryKeyValue.fromString(Md5ID))
.addPrimaryKeyColumn("cabinet_ID",PrimaryKeyValue.fromString(ID)).build());
//更新可用充电宝数量
rowUpdateChange.put("cabinet_available_size",ColumnValue.fromLong(availableSize));
//更新机柜电量
rowUpdateChange.put("cabinet_powerPercent",ColumnValue.fromLong(powerPercent));
updateRowRequest.setRowChange(rowUpdateChange);
//发起更新请求
client.updateRow(updateRowRequest);
  • 查看订单。根据订单Md5ID,订单ID查看订单详情。

GetRowRequest getRowRequest = new GetRowRequest();
//指定表名
SingleRowQueryCriteria criteria = new SingleRowQueryCriteria("order");
//指定主键
criteria.setPrimaryKey(PrimaryKeyBuilder.createPrimaryKeyBuilder()              .addPrimaryKeyColumn("order_Md5ID",PrimaryKeyValue.fromString(orderMd5ID))
.addPrimaryKeyColumn("order_ID",PrimaryKeyValue.fromString(orderID)).build());
//指定读取的版本数
criteria.setMaxVersions(1);
getRowRequest.setRowQueryCriteria(criteria);
//发起查询请求
clinet.getRow(getRowRequest);

上面介绍了数据新增、数据更新、数据查询的操作步骤。可以看出,上述操作均是基于主键的,无论是更新或者是查询,都需要传入完整的主键信息。然而在共享充电宝场景中,许多业务需求是要根据属性列作为查询条件来进行筛选。所以,仅仅依靠主键的读写并不能完全满足业务需求,还需要依赖索引能力。下面将为大家介绍Tablestore功能之一多元索引。

多元索引操作

什么是多元索引

多元索引是表格存储Tablestore的功能之一。多元索引基于倒排索引、列式存储,可满足多列自由组查询等复杂查询需求。不同于传统数据库MySQL的索引使用方式,没有最左匹配原则的限制,可灵活地在任意列上建立索引,将查询能力扩展到属性列上,实现对百亿数据毫秒级查询。

创建多元索引

  • 控制台创建步骤
  1. 进入表管理-索引管理页面。点击创建多元索引。
小技巧:多元索引创建后,即可在控制台上看到数据表实时的总行数。
  1. 输入索引名。添加多个索引字段。点击确定。

  • SDK创建代码片段。
说明: 更多关于多元索引创建SDK示例请参考官网文档 创建多元索引
//这里为部分列创建索引
CreateSearchIndexRequest csir = new CreateSearchIndexRequest();
csir.setTableName("cabinet");//设置表名
csir.setTableName("cabinet_index_1");//设置索引名
IndexSchema indexSchema = new IndexSchema();
indexSchema.setFieldSchemas(Arrays.asList(
    new FieldSchema("cabinet_Md5ID", FieldType.KEYWORD),//指定字段名和字段类型
    new FieldSchema("cabinet_ID", FieldType.KEYWORD),
    new FieldSchema("cabinet_available_size", FieldType.LONG),
    new FieldSchema("cabinet_location", FieldType.KEYWORD),
    new FieldSchema("cabinet_geo", FieldType.GEO_POINT),
    new FieldSchema("cabinet_pricePerHour", FieldType.DOUBLE),
    new FieldSchema("cabinet_isonline", FieldType.KEYWORD)
));
csir.setIndexSchema(indexSchema);//设置索引schema
//发送创建多元索引请求
client.createSearchIndex(csir);

多元索引查询

多元索引可实现丰富的查询方式,例如全文检索、前缀查询、模糊查询、组合查询、地理位置查询等等功能。下面以共享充电宝场景中具体的查询需求为例,模拟四个业务场景介绍多元索引的几个重要功能:多字段排序、多字段组合查询、分组聚合等。

  • 场景一。用户需要查询有可租用充电宝的机柜信息,并先按照距离远近倒序排序,再按照机柜时价倒序排序。

查询代码

//场景一。用户需要查询有可租用充电宝的机柜信息,并先按照距离远近倒序排序,再按照机柜时价倒序排序。
    public void searchDemo01(SyncClient client){
        SearchRequest searchRequest = SearchRequest.newBuilder()
                .tableName(Config.CABINET_TABLENAME)//设置表名
                .indexName(Config.CABINET_TABLENAME_INDEX)//设置多元索引名
                .searchQuery(SearchQuery.newBuilder()
                        .query(QueryBuilders.bool()
                                .must(QueryBuilders.range("cabinet_available_size").greaterThan(0))//可用充电宝个数>0
                                .must(QueryBuilders.range("cabinet_powerPercent").greaterThan(50))//电量>50
                               .must(QueryBuilders.term("cabinet_isonline","online"))//状态=在线
                        )
                        .sort(new Sort(Arrays.asList(
                                new GeoDistanceSort("cabinet_geo",Arrays.asList("30.17110,120.29937")),//先按照距离远近升序
                                new FieldSort("cabinet_pricePerHour", SortOrder.ASC)//再按照价格升序
                        )))
                        .build())
                .addColumnsToGet(Arrays.asList("cabinet_manufacturers","cabinet_type","cabinet_pricePerHour","cabinet_location"))//指定返回哪些字段
                .build();
        SearchResponse response = client.search(searchRequest);
        System.out.println(response.getRows());
    }

返回结果

  • 场景二。用户需要查询租赁时价在2元/小时之内,并且有可租用充电宝的机柜。按照距离远近排序。

查询代码

//场景二。用户需要查询租赁时价在2元/小时之内,并且有可租用充电宝的机柜。按照距离远近排序。
    public static void searchDemo02(SyncClient client){
        SearchRequest searchRequest = SearchRequest.newBuilder()
                .tableName(Config.CABINET_TABLENAME)//设置表名
                .indexName(Config.CABINET_TABLENAME_INDEX)//设置多元索引名
                .searchQuery(SearchQuery.newBuilder()
                        .query(QueryBuilders.bool()
                                .must(QueryBuilders.range("cabinet_pricePerHour").greaterThan(0).lessThanOrEqual(2))//时价在0-2元内
                                .must(QueryBuilders.range("cabinet_available_size").greaterThan(0))//可用充电宝个数>0
                                .must(QueryBuilders.term("cabinet_isonline","online"))//状态=在线
                        )
                        .sort(new Sort(Arrays.asList(
                                new GeoDistanceSort("cabinet_geo",Arrays.asList("30.17110,120.29937"))//按照距离远近升序
                        )))
                        .build())
                .addColumnsToGet(Arrays.asList("cabinet_manufacturers","cabinet_type","cabinet_pricePerHour","cabinet_location"))//指定返回哪些字段
                .build();
        SearchResponse response = client.search(searchRequest);
        System.out.println(response.getRows());
    }

返回结果

  • 场景三。运维人员需要查询浙江省内,机柜检修时间戳在半年之前,或者已经下线的机柜。取十条记录。

查询代码

//场景三。运维人员需要查询浙江省内,机柜检修时间戳在半年之前或者已经下线的机柜。取十条记录。
    public static void searchDemo03(SyncClient client){
        SearchRequest searchRequest = SearchRequest.newBuilder()
                .tableName(Config.CABINET_TABLENAME)//设置表名
                .indexName(Config.CABINET_TABLENAME_INDEX)//设置多元索引名
                .searchQuery(SearchQuery.newBuilder()
                        .query(QueryBuilders.bool()
                                .must(QueryBuilders.term("cabinet_province","浙江省"))
                                .must(QueryBuilders.bool()
                                        .should(QueryBuilders.range("cabinet_overhaul_time").lessThan(2592000000L))
                                        .should(QueryBuilders.term("cabinet_isonline","offline"))
                                .minimumShouldMatch(1)
                        ))
                        .limit(10)
                        .sort(new Sort(Arrays.asList(
                                new GeoDistanceSort("cabinet_geo",Arrays.asList("30.17110,120.29937"))//按照距离远近升序
                        )))
                        .build())
                .addColumnsToGet(Arrays.asList("cabinet_manufacturers","cabinet_type","cabinet_pricePerHour","cabinet_location"))//指定返回哪些字段
                .build();
        SearchResponse response = client.search(searchRequest);
        System.out.println(response.getRows());
    }

返回结果

  • 场景四。运维人员需要统计每个省份已经上线的机柜个数,并按照机柜型号分组,取出前五个型号的数据。

查询代码

//场景四。运维人员需要统计每个省份已经上线的机柜个数,并按照机柜型号分组,取出前五个型号的数据。
    public static void searchDemo04(SyncClient client){
        SearchRequest searchRequest = SearchRequest.newBuilder()
                .tableName(Config.CABINET_TABLENAME)//设置表名
                .indexName(Config.CABINET_TABLENAME_INDEX)//设置多元索引名
                .searchQuery(SearchQuery.newBuilder()
                        .query(QueryBuilders.matchAll())
                        .addGroupBy(GroupByBuilders.groupByField("groupByProvince","cabinet_province")
                                .addSubGroupBy(GroupByBuilders.groupByField("groupByType","cabinet_type").size(5)))
                        .build())
                .build();
        SearchResponse searchResponse = client.search(searchRequest);
        List<GroupByFieldResultItem> list = searchResponse.getGroupByResults().getAsGroupByFieldResult("groupByProvince").getGroupByFieldResultItems();
        for(GroupByFieldResultItem groupByFieldResultItem : list){
            System.out.println("省份:【"+groupByFieldResultItem.getKey()+"】 机柜数量:【"+groupByFieldResultItem.getRowCount()+"】");
            List<GroupByFieldResultItem> subList = groupByFieldResultItem.getSubGroupByResults().getAsGroupByFieldResult("groupByType").getGroupByFieldResultItems();
            for(GroupByFieldResultItem subItem : subList){
                System.out.println("型号:"+subItem.getKey()+",机柜数量:"+subItem.getRowCount());
            }
        }
    }

返回结果

SQL操作

可通过
可通过表格存储控制台进行SQL查询,关于表格存储SQL相关操作请参考文档表格存储SQL

创建数据表映射关系

  1. 进入表格存储控制台,实例管理-SQL查询页面。点击一键生成映射关系。

  1. 选择需要映射的表,点击生成SQL。

  1. 执行SQL,得到cabinet、cabinet_time、order三张表的映射。

DML操作示例

  • 场景一。用户需要查询有可租用充电宝的机柜信息,按照机柜时价倒序排序,取前100条。
select * from cabinet where
cabinet_isonline = "online" and
cabinet_available_size > 0 and
cabinet_powerPercent > 50 
order by cabinet_pricePerHour asc limit 100;

  • 用户需要查询租赁时价在2元/小时之内,并且有可租用充电宝的机柜,取100条。
select * from cabinet where cabinet_pricePerHour between 0 and 2 
and cabinet_available_size > 0 and cabinet_isonline = 'online' limit 100;

  • 运维人员需要查询浙江省内,机柜检修时间戳在半年之前,或者已经下线的机柜。取十条记录
select * from cabinet where 
(cabinet_province = '浙江省' and cabinet_overhaul_time < 2592000000) 
or cabinet_isonline = 'offline' limit 10;

  • 运维人员需要统计每个省份已经上线的机柜个数,并按照机柜型号分组
select cabinet_province,cabinet_type,count(*) cabinet_count,any_value(cabinet_Md5ID)
from cabinet
where cabinet_isonline = 'online' 
group by cabinet_province,cabinet_type order by cabinet_count

小结

表格存储Tablestore实现了表引擎和多元索引引擎。其中表引擎可以基于主键实现高并发数据读写,可满足元数据并发更新、订单数据新增等业务。多元索引引擎则提供了多字段组合查询、排序、统计聚合等功能,可在毫秒延迟内对百亿级元数据进行检索、轻量级分析。下一章节将为大家介绍如何通过Spark访问Tablestore实现离线流批计算。

联系我们

如对本章节所述有疑问或有其他问题需要咨询,欢迎加入钉钉群:“表格存储公开交流群-2”。群内提供免费的在线专家服务,欢迎扫码加入,群号23307953。

相关实践学习
钉钉群中如何接收IoT温控器数据告警通知
本实验主要介绍如何将温控器设备以MQTT协议接入IoT物联网平台,通过云产品流转到函数计算FC,调用钉钉群机器人API,实时推送温湿度消息到钉钉群。
阿里云AIoT物联网开发实战
本课程将由物联网专家带你熟悉阿里云AIoT物联网领域全套云产品,7天轻松搭建基于Arduino的端到端物联网场景应用。 开始学习前,请先开通下方两个云产品,让学习更流畅: IoT物联网平台:https://iot.console.aliyun.com/ LinkWAN物联网络管理平台:https://linkwan.console.aliyun.com/service-open
目录
相关文章
|
11天前
|
监控 安全 物联网
Java基于物联网技术的智慧工地解决方案源代码
应用先进的大数据、物联网、云计算等数字化技术,融合施工运营管理规范和技术标准,建构支撑施工和运营的一体化平台是投资、施工和运营单位能力建设的关键。应用企业架构、设计思维和软件工程方法,深入分析施工和运营技术特性与管理体系,研究开发基于大数据技术的智慧工地信息一体化平台,智慧工地管理平台是依托物联网、互联网建立的大数据管理平台,是一种全新的管理模式,能够实现劳务管理、安全施工、绿色施工的智能化和互联网化。
94 2
|
7月前
|
存储 索引
表格存储根据多元索引查询条件直接更新数据
表格存储是否可以根据多元索引查询条件直接更新数据?
65 3
|
11天前
|
分布式计算 DataWorks API
DataWorks常见问题之按指定条件物理删除OTS中的数据失败如何解决
DataWorks是阿里云提供的一站式大数据开发与管理平台,支持数据集成、数据开发、数据治理等功能;在本汇总中,我们梳理了DataWorks产品在使用过程中经常遇到的问题及解答,以助用户在数据处理和分析工作中提高效率,降低难度。
|
11天前
|
物联网 定位技术
【技术探讨】一种多节点5Km(1.2M bps速率)实时Sub-G无线通信的物联网通讯解决方案
针对在高速公路上货车行驶过程中收集5公里范围内的GPS定位数据,上报云服务器端,最终实时显示每一辆货车的运行轨迹,用户的项目需求如下:200辆货车(无线从站节点),要求很高的实时性,每秒发5包,每个GPS定位数据报文30个字节,这样200辆车同时上报每秒需要发送30K的字节(200 x 5 x 3 0 =30K字节),30K字节 x 8bit=240 k bps速率。
|
11天前
|
DataWorks NoSQL 关系型数据库
可以使用dataworks从tablestore同步数据到mysql吗?
可以使用dataworks从tablestore同步数据到mysql吗?
36 1
|
8月前
|
运维 监控 安全
物联网行业解决方案(五)
物联网行业解决方案(五)
395 2
|
8月前
|
传感器 人工智能 监控
物联网行业解决方案(四)
物联网行业解决方案(四)
328 1
|
8月前
|
存储 人工智能 监控
物联网行业解决方案(三)
物联网行业解决方案(三)
341 0
|
3天前
|
存储 供应链 物联网
未来技术纵横:区块链、物联网与虚拟现实的融合革新
【5月更文挑战第23天】 随着科技的迅猛发展,新兴技术正不断突破传统的边界,推动着社会向更加智能和互联的方向演进。本文将聚焦于区块链技术、物联网(IoT)以及虚拟现实(VR)这三个技术领域,探讨它们各自的发展趋势以及在不同应用场景中的交叉融合和创新应用。通过分析这些技术的互动和集成,揭示它们如何共同塑造未来的数字世界,并讨论在实际应用中面临的挑战及其解决方案。
|
20小时前
|
安全 物联网 区块链
未来技术浪潮:区块链、物联网和虚拟现实的革新之路
【5月更文挑战第25天】 随着第四次工业革命的到来,新兴技术如区块链、物联网(IoT)和虚拟现实(VR)正不断重塑我们的世界。区块链技术以其去中心化和不可篡改的特性为数据安全和交易透明性提供了新范式。物联网通过使设备互联互通,优化了自动化系统的运行效率和生活品质。而虚拟现实则在娱乐、教育和医疗等领域创造了沉浸式体验。本文将深入探讨这些技术的发展趋势,并分析它们在不同应用场景中的实际作用与潜力。

相关产品

  • 物联网平台