数据存储

基础概念

术语

名字 中文描述 语义
schema class的元数据,在前端定义
class 数据集 相当于数据库中的table
group 数据空间 相当于数据库中的database,不指定使用默认值
partition 分区 数据集水平拆分,当前只支持散列分区
row 数据行 相当于数据库上的一行记录
column 数据列列名 相当于数据库中的列名
key 相当于数据库表中某一列的名字
value 相当于数据库表中某一列的值
primaryKeys 主键 数据集中唯一标识一行记录
partitionKeys 分区键 数据集用于水平拆分的键
filter 过滤条件 过滤结果集中数据的条件,如:a>=10
expr 表达式 支持简单运算
connector 连接符 AND, OR
operator 操作符 <, >, <=, >=, ==, !=, LIKE, in等
join 联结 多表查询条件
select 选择列 结果集中需要返回的列
ACContext 上下文标识

支持的数据类型

类型 描述
整型 byte, short, int, long
浮点型 float, double
字符串 String
布尔型 Boolean

支持的接口

名字 描述
Create 创建一行数据(行不存在,则执行创建; 行存在,报错)
BatchCreate 批量插入数据
Replace 覆盖一行数据(行存在,则执行覆盖; 行不存在,则执行插入)
BatchReplace 批量覆盖数据
Delete 删除一行数据(行存在,则执行删除; 行不存在,不执行)
Update 更改一行数据(行存在,则执行更改; 行不存在,执行创建)
Modify 更改一行数据(行存在,则执行更改; 行不存在,不执行)
Find 查找一行数据(行存在,则返回这行记录; 行不存在,返回NULL)
Scan 查找多行数据(行存在,则返回多行记录; 行不存在,结果集为空)
BatchDelete 批量删除数据(行存在,则执行删除; 行不存在,不执行)
BatchUpdate 批量更新数据(行存在,则执行更新; 行不存在,不执行)
MultiScan 多表查询(当前只支持处于同一个Group的非分区数据集)
SimpleFullScan 全表扫描(结果集不保证顺序)

数据模型

AbleCloud目前提供基于MySQL的分布式存储服务。开发者需要预先设定数据集的结构,同时可以选择对数据进行分区或不分区。为定位数据所在分区,需要定义数据分区键(partitionKeys),可以为一列或多列。主键(primaryKeys)唯一表示一行数据, 可以为一列或多列。

分区数据集数据模型

非分区数据集数据模型

分区与非分区

什么是分区

分区指的是对数据集进行水平拆分,将同一个数据集中的数据分发到不同的分区,从而可以增大数据存储容量,实现负载均衡。

如何分区

当前是根据用户指定的分区键,内部使用散列分区算法来实现。分区键必须是主键的前缀,同一个分区键的数据会分布到同一个分区。

如何选择

如果是数据随着时间不断增加,建议使用分区数据集,如设备的上报数据,可以将设备ID设置为分区键,(设备ID, 时间戳)做为主键。

如果是数据随着时间变化不大,如设备表,用户表,则建议使用非分区数据集

分区的限制

分区一旦设定,不能更改,对于分区数据集,查询或是执行其它批量操作时,必须明确指定分区键。不能跨分区操作数据

基础数据结构

ACContext

ACContext 包含了用户的MajorDomain, SubDomain, DeveloperId, TraceId, 时间戳, 签名等信息,每个请求都必须带有ACContext才能与云端交互。单个ACContext可以认为是逻辑上一系列请求的唯一标识。

获取方式

ACContext ctx = ac.newContext();

ACFilter

ACFilter用于过滤结果集中的数据,当前支持:

名字 数学表示 描述
EQUAL == 等于
NOT_EQUAL != 不等于
GREATER > 大于
GREATE_OR_EQUAL >= 大于等于
LESS < 小于
LESS_OR_EQUAL <= 小于等于
LIKE like 字符串模糊匹配
NOT_LIKE not like 字符串模糊匹配
BINARY_LIKE binary like 区分大小写的字符串模糊匹配
BINARY_NOT_LIKE binary not like 区分大小写的字符串模糊匹配
IN in 基于列表进行查找
NOT_IN not in 基于列表进行查找
AND and 与(与的优化级高于或)
OR or

使用实例

// 实例1: 创建一个filter(key1>0 and key1<10)
ACFilter f1 = ac.filter().whereGreaterThan("key1", 0).andLessThan("key1", 10);

// 实例2: 创建一个filter(key1<=0 or key1>=10)
ACFilter f1 = ac.filter().whereLessThanOrEqualTo("key1", 0).orGreaterThanOrEqualTo("key1", 10);

// 实例3: 创建一个filter(key1以 "abcd" 为前缀, 不区分大小写)
ACFilter f1 = ac.filter().whereLike("key1", "abcd%");

// 实例4: 创建一个filter(key1以 "abcd" 为前缀, 不区分大小写)
ACFilter f1 = ac.filter().whereLike("key1", "abcd%");

// 实例5: 创建一个filter(key1以 "abcd" 为后缀, 不区分大小写)
ACFilter f1 = ac.filter().whereLike("key1", "%abcd");

// 实例6: 创建一个filter(key1包含子串 "abcd", 不区分大小写)
ACFilter f1 = ac.filter().whereLike("key1", "%abcd%");

// 实例7: 创建一个filter(key1 为 "v1" 或 "v2" 或 "v3"中的一个)
ACFilter f1 = ac.filter().whereIn("key1", String[]{"v1", "v2", "v3"});

// 实例8: 创建一个filter(数据集t1的c1列与数据集t2的c2列相等)
ACFilter f1 = ac.filter().whereEqualToColumn("t1.c1", "t2.c2");

ACJoin

ACJoin在多表查询时用于表示联表条件,当前仅支持内联结

使用实例

// t1为基准表,t2是需要联结的表

// 实例1: 联表条件(数据集t1的c1列 与 数据集t2的c2列相等)
ACFilter f1 = ac.filter().whereEqualToColumn("t1.c1", "t2.c2");
ACJoin j1 = ac.innerJoin("t2").where(f1);

// 实例2: 联表条件(数据集t1的c1列 与 数据集t2的c2列相等,并且 数据集t1的c1列的值大于100)
ACFilter f1 = ac.filter().whereEqualToColumn("t1.c1", "t2.c2").andGreaterThan("t1.c1", 100);
ACJoin j1 = ac.innerJoin("t2").where(f1);

使用实例

以空气净化器为例来说明。每个实例会针对分区数据集和非分区数据集分别说明接口使用方法。

列名 类型 描述
device_id 字符串 设备ID
timestamp 整数 时间戳
pm25 浮点数 pm2.5值
speed 整数 当前风机转速
mode 字符串 当前净化器状态(auto(自动), high(高速), medium(中速), low(低速))

device_data(分区数据集)

device_data(非分区数据集)

数据写入

Create

在数据集中插入一条数据,如果数据不存在,则执行插入; 如果数据已经存在,则会报错。

分区数据集和非分区数据集使用方式相同

标准用法

ac.store(数据集名字, context).create(键值列表)
        .put(key_1,value_1)
        .put(key_..., value_...)
        .put(key_n, value_n)
        .execute();

注意事项

  • 主键列表至少包含所有的主键列,可以包含非主键列
  • key,value对根据需要选填,如果没有设置,则会填充默认值。整数,浮点数的默认值为0,字符串默认值为空字符串,布尔型的默认值为false

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param createParam is not set createParam没有设置
ACServiceException CLOUD 3924 data already exist row[key1=xxx, keys2=xxx] is already exist 数据行已经存在,创建失败

使用实例

  • 实例1: 插入一条数据(device_id:"001", timestamp:1469098960, pm25:70.5, speed:40, mode:"low")
// 其它所有接口都有以下三种使用方式

// 使用方式一
ac.store("device_data", ctx).create("device_id", "001", "timestamp", 1469098960)
        .put("pm25", 70.5)
        .put("speed", 40)
        .put("mode", "low")
        .execute();

// 使用方式二
ac.store("device_data", ctx).create("device_id", "001", "timestamp", 1469098960, "pm25", 70.5, "speed", 40, "mode", "low")
        .execute();

// 使用方式三
ACObject keyObj = new ACObject();
keyObj.put("device_id", "001");
keyObj.put("timestamp", 1469098960);

ac.store.("device_data", ctx).create(keyObj)
        .put("pm25", 70.5)
        .put("speed", 40)
        .put("mode", "low")
        .execute();

类比SQL

INSERT INTO `device_data` SET `device_id`='001', `timestamp`=1469098960, `pm25`=70.5, `speed`=40, `mode`='low';

BatchCreate

在数据集中指插入多行数据,如果数据不存在,则执行插入; 如果数据已经存在,则会报错。

分区数据集和非分区数据集使用方式相同

标准用法

// 用法1
ac.store(数据集名字, context).batchCreate()
        .add(ACObject_1)
        ...
        .add(ACObject_n)
        .execute();

// 用法2
List<ACObject> objs = new ArrayList<>();

ac.store(数据集名字, context).batchCreate()
        .put(objs)
        .execute();

注意事项

  • 一次批量最多支持1000条

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param batchCreateParam is not set batchCreateParam没有设置

使用实例

  • 实例1:批量插入三条数据

(device_id:"001", timestamp:1469098960, pm25:70.5, speed:40, mode:"low") (device_id:"001", timestamp:1469098961, pm25:70.6, speed:41, mode:"low") (device_id:"001", timestamp:1469098962, pm25:70.7, speed:42, mode:"low")

ACObject obj1 = new ACObject();
obj1.put("device_id", "001");
obj1.put("timestamp", 1469098960);
obj1.put("pm25", 70.5);
obj1.put("speed", 40);
obj1.put("mode", "low");

ACObject obj2 = new ACObject();
obj2.put("device_id", "001");
obj2.put("timestamp", 1469098961);
obj2.put("pm25", 70.6);
obj2.put("speed", 41);
obj2.put("mode", "low");

ACObject obj3 = new ACObject();
obj3.put("device_id", "001");
obj3.put("timestamp", 1469098962);
obj3.put("pm25", 70.7);
obj3.put("speed", 42);
obj3.put("mode", "low");

// 方法一:
ac.store("device_data", ctx).batchCreate()
    .add(obj1, obj2, obj3)
    .execute();

// 方法二:
ac.store("device_data", ctx).batchCreate()
    .add(obj1)
    .add(obj2)
    .add(obj3)
    .execute();

//方法三:
List<ACObject> objs = new ArrayList<>();
objs.add(obj1);
objs.add(obj2);
objs.add(obj3);

ac.store("device_data", ctx).batchCreate()
    .put(objs)
    .execute();

类比SQL

INSERT INTO `device_data`(`device_id`, `timestamp`, `pm25`, `speed`, `mode`) VALUES ('001', 1469098960, 70.5, 40, 'low'), ('001', 1469098961, 70.6, 41, 'low'), ('001', 1469098962, 70.7, 42, 'low');

Replace

当此行数据不存在时,则插入这行数据,如果已经存在,则覆盖已有数据

分区数据集和非分区数据集使用方式相同

标准用法

ac.store(数据集名字, context).replace(键值列表)
        .put(key_1, value_1)
        .put(key_..., value_...)
        .put(key_n, value_n)
        .execute();

注意事项

  • 键值列表至少包含所有的主键列,可以包含其它键值
  • (key,value)对选填,如果没有设置,则会使用默认值,整数,浮点型的默认值为0,字符串默认值为空字符串,布尔型的默认值为false。

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param replaceParam is not set replaceParam没有设置

使用实例

  • 实例1:覆盖写入一条数据(device_id="001", timestamp:1469098960, pm25:70.5, speed:40, mode:low)
// 使用方法一
ac.store("device_data", ctx).replace("device_id", "001", "timestamp", 1469098960)
        .put("pm25", 70.5)
        .put("speed", 40)
        .put("mode", "low")
        .execute();

// 使用方法二
ac.store("device_data", ctx).replace("device_id", "001", "timestamp", 1469098960, "pm25", 70.5, "speed", 40, "mode", "low")
        .execute();

类比SQL

REPLACE INTO `device_data` SET `device_id`='001', `timestamp`=1469098960, `pm25`=70.5, `speed`=40, `mode`='low';

BatchReplace

在数据集中批量覆盖多行数据,如果数据不存在,则执行插入; 如果数据已经存在,则执行覆盖。

分区数据集和非分区数据集使用方式相同

标准用法

// 用法1
ac.store(数据集名字, context).batchReplace()
        .add(ACObject_1)
        ...
        .add(ACObject_n)
        .execute();

// 用法2
List<ACObject> objs = new ArrayList<>();

ac.store(数据集名字, context).batchReplace()
        .put(objs)
        .execute();

注意事项

  • 一次批量最多支持1000条

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param batchReplaceParam is not set batchReplaceParam没有设置

使用实例

  • 实例1:批量插入三条数据

(device_id:"001", timestamp:1469098960, pm25:70.5, speed:40, mode:"low") (device_id:"001", timestamp:1469098961, pm25:70.6, speed:41, mode:"low") (device_id:"001", timestamp:1469098962, pm25:70.7, speed:42, mode:"low")

ACObject obj1 = new ACObject();
obj1.put("device_id", "001");
obj1.put("timestamp", 1469098960);
obj1.put("pm25", 70.5);
obj1.put("speed", 40);
obj1.put("mode", "low");

ACObject obj2 = new ACObject();
obj2.put("device_id", "001");
obj2.put("timestamp", 1469098961);
obj2.put("pm25", 70.6);
obj2.put("speed", 41);
obj2.put("mode", "low");

ACObject obj3 = new ACObject();
obj3.put("device_id", "001");
obj3.put("timestamp", 1469098962);
obj3.put("pm25", 70.7);
obj3.put("speed", 42);
obj3.put("mode", "low");

// 方法一:
ac.store("device_data", ctx).batchReplace()
    .add(obj1, obj2, obj3)
    .execute();

// 方法二:
ac.store("device_data", ctx).batchReplace()
    .add(obj1)
    .add(obj2)
    .add(obj3)
    .execute();

//方法三:
List<ACObject> objs = new ArrayList<>();
objs.add(obj1);
objs.add(obj2);
objs.add(obj3);

ac.store("device_data", ctx).batchReplace()
    .put(objs)
    .execute();

类比SQL

REPLACE INTO `device_data`(`device_id`, `timestamp`, `pm25`, `speed`, `mode`) VALUES ('001', 1469098960, 70.5, 40, 'low'), ('001', 1469098961, 70.6, 41, 'low'), ('001', 1469098962, 70.7, 42, 'low');

数据删除

Delete

删除单行数据,如果这行数据存在,则执行删除,如果数据不存在,不会执行

分区数据集和非分区数据集使用方式相同

标准用法

ac.store(数据集名字, context).delete(键值列表)
        .execute();

注意事项

  • 键值列表至少含所有的主键列

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param deleteParam is not set deleteParam没有设置

使用实例

  • 实例1: 删除一行设备数据记录(ID="001", timestamp=1469098960)
ac.store("device_data", ctx).delete("device_id", "001", "timestamp", 1469098960)
        .execute();

类比SQL

DELETE FROM `device_data` WHERE `device_id`='001' AND `timestamp`=1469098960;
  • 实例2: 删除一行设备数据记录(ID="001", timestamp=1469098960, mode='high')
ac.store("device_data", ctx).delete("device_id", "001", "timestamp", 1469098960, "mode", "high")
        .execute();

类比SQL

DELETE FROM `device_data` WHERE `device_id`='001' AND `timestamp`=1469098960 AND `mode`='high';

BatchDelete

根据过滤条件删除多行数据

分区数据集的使用有限制,键值列表至少包含完整的分区键

标准用法

ac.store(数据集名字,context).batchDelete(键值列表)
        .where(filter_1)
        .and(filter_2)
        .or(filter_3)
        .execute();

注意事项

  • 对于分区数据集,键值列表必须包含完整的分区键
  • 对于非分区数据集,键值列表可以为空

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param batchDeleteParam is not set batchDeleteParam没有设置

使用实例

  • 实例1:删除设备(ID="001", timestamp>=1469098960 and timestamp<=1469102560)之间的所有数据
ACFilter filter1 = ac.filter().whereGreaterThanOrEqualTo("timestamp", 1469098960).andLessThanOrEqualTo("timestamp", 1469102560);

ac.store("device_data", context).batchDelete("device_id", "001").
        .where(filter1)
        .execute();

类比SQL

DELETE FROM `device_data` WHERE `device_id`="001" AND (`timestamp`>=1469098960 AND `timestamp`<=1469102560);
  • 实例2:删除设备(ID="001", timestamp>=1469098960 timestamp<=1469102560)之间并且speed大于40的所有数据
ACFilter filter1 = ac.filter().whereGreaterThanOrEqualTo("timestamp", 1469098960).andLessThanOrEqualTo("timestamp", 1469102560);
ACFilter filter2 = ac.filter().whereGreaterThan("speed", 40);

ac.store("device_data", context).batchDelete("device_id", "001").
        .where(filter1)
        .and(filter2)
        .execute();

类比SQL

DELETE FROM `device_data` WHERE `device_id`="001" AND (`timestamp`>=1469098960 AND `timestamp`<=1469102560) AND `speed`>40;

修改数据

Update

修改单行数据,如果这行数据不存在则执行插入,如果存在,则修改指定的列。

分区数据集和非分区数据集使用方式相同

标准用法

ac.store(数据集名字, context).update(键值列表)
        .put(key_1, value_1)
        .put(key_..., value_...)
        .put(key_n, value_n)
        .execute();

注意事项

  • 键值列表至少包含所有主键列
  • (key,value)对可选
  • 没有更新的列会使用原来的值

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param updateParam is not set updateParam没有设置

使用实例

  • 实例1:写入一条数据(device_id="001", timestamp=1469098960, speed=60)数据,如果数据行不存在,则插入此行数据(device_id="001", timestamp=1469098960, speed=60,其它列使用默认值),如果数据行已经存在,则将speed列的值改为60。
ac.store("device_data", context).batchUpdate("device_id", "001", "timestamp", 1469098960)
        .put("speed", 60)
        .execute();

类比SQL

INSERT INTO `device_data` SET `device_id`='001', `timestamp`=1469098960, `speed`=60 ON DUPLICATE KEY update `device_id`='001', `timestamp`=1469098960, `speed`=60;

Modify

修改单行数据,如里数据不存在,则报错,如果数据存在,则将指定列修改为特定的值,可以进行加减运算

分区数据集和非分区数据集使用方式相同

标准用法

ac.store(数据集名字, context).modify(键值列表)
        .where(key_xxx, value_xxx)
        .and(key_xxx, value_xxx)
        .set(key_1, value_1)
        .inc(key_..., value_...)
        .dec(key_n, value_n)
        .execute();

注意事项

  • 键值列表至少包含所有主键列
  • where指的是过滤条件
  • set/inc/dec至少使用一个

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param modifyParam is not set modifyParam没有设置

使用实例

  • 实例1:将(ID="001", timestamp=1469098960)的数据,speed加5,mode设备设置为high, pm25值减1.5
ac.store("device_data", context).modify("device_id", "001", "timestamp", 1469098960)
        .inc("speed", 5)
        .set("mode", "high")
        .dec("pm25", 1.5)
        .execute();

类比SQL

UPDATE `device_data` SET `speed`=`speed`+5, `mode`='high', `pm25`=`pm25`-1.5 WHERE `device_id`="001" AND `timestamp`=1469098960;
  • 实例2:将(ID="001", timestamp=1469098960 并且 speed=5)的数据,mode设置为high
ac.store("device_data", context).modify("device_id", "001", "timestamp", 1469098960)
        .where("speed", 5)
        .set("mode", "high")
        .execute();

类比SQL

UPDATE `device_data` SET `mode`='high' WHERE `device_id`="001" AND `timestamp`=1469098960 AND `speed`=5;

BatchUpdate

根据条件修改数据

分区数据集的使用方式有限制,键值列表至少包含完整的分区键

标准用法

ac.store(数据集名字, ctx).batchUpdate(键值列表)
        .where(filter_1)
        .or(filter_2)
        .and(filter_3)
        .set(key_n, value_n)
        .inc(key_n, value_n)
        .dec(key_n, value_n)
        .execute();

注意事项

  • 对于分区数据集,键值列表至少包含所有的分区键
  • 对于非分区数据集,键值列表可以为空
  • set/inc/dec可以为多个,至少包含一个

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc/日志 说明
ACServiceException CLOUD 3002 invalid param batchUpdateParam is not set batchUpdateParam没有设置

使用实例

  • 实例1:将(device_id="001", pm25>40)的数据的mode改为"high", speed加20
ACFilter f1 = ac.filter().whereGreaterThan("pm25", 40);

ac.store("device_data", ctx).batchUpdate("device_id", "001")
        .where(f1)
        .set("mode", "high")
        .inc("speed", 20)
        .execute();

类比SQL

UPDATE `device_data` SET `mode`='high', `speed`=`speed`+20 WHERE `deviceId`='001' AND `pm25`>40;

查询数据

find

查询单条数据,如果数据不存在,则返回的数据为空,如果存在,则返回单行数据。

分区数据集和不分区数据集使用方式相同

标准用法

// 如果数据不存在,则返回null
ACObject result = ac.store(数据集名字, ctx).find(键值列表)
                    .select(key1, ..., keyn)
                    .execute();

注意事项

  • 键值列表必须包含完整的主键列
  • select可选,如果没有指定select,则会返回所有的列

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc 日志 说明
ACServiceException CLOUD 3002 invalid param findParam is not set findParam is not set 没有设置findParam

使用实例

  • 实例1:查询(device_id="001", timestamp=1469098960)这一行的所有列
ACObject result = ac.store("device_data", ctx).find("device_id", "001", "timestamp", 1469098960)
                .execute();
// 结果集如果为空则, result==null

// 结果集不为空输出数据
String device_id = result.getString("device_id");
Long timestamp = result.getLong("timestamp");
Double pm25 = result.getDouble("pm25");
String mode = result.getString("mode");
Long speed = result.getLong("speed");
System.out.Println(device_id + ", " + timestamp + ", " + pm25 + ", " + mode + ", " + speed);

类比SQL

SELECT * FROM `device_data` WHERE `device_id`='001' AND `timestamp`=1469098960;
  • 实例2:查询(device_id="001", timestamp=1469098960)这一行的speed列和mode列
ACObject result = ac.store("device_data", ctx).find("device_id", "001", "timestamp", 1469098960)
        .select("speed", "mode")
        .execute();
// 如果为空则, result==null

// 如果结果不为空,取出数据
Long speed = result.getLong("speed");
String mode = result.getString("mode");
System.out.Println(speed + ", " + mode);

类比SQL

SELECT `speed`, `mode` FROM `device_data` WHERE `device_id`='001' AND `timestamp`=1469098960;

scan

根据条件查询数据,可能有多条。

分区数据集的使用有限制,键值列表至少包含完整的分区键

标准用法

// 如果符合条件的数据不存在,则返回一个空的数组
List<ACObject> results = ac.store(数据集名字, ctx).scan(键值列表)
                      .select(key_1, ...., key_n)
                      .start(键值列表)
                      .end(键值列表)
                      .where(filter_1)
                      .and(filter_2)
                      .or(filter_3)
                      .groupBy(key_1, ..., key_n)
                      .sum(key_1, ..., key_n)
                      .avg(key_1, ..., key_n)
                      .max(key_1, ..., key_n)
                      .min(key_1, ..., key_n)
                      .count()
                      .orderByAsc(key_1, ..., key_n)
                      .orderByDesc(key_1, ..., key_n)
                      .offset(数值)
                      .limit(数值)
                      .execute();

注意事项

  • select可以包含一列或多列,如果未指定,则表示返回所有列
  • start/end至少包含完整的分区键
  • start/end最多可以包含一个非主键key
  • sum(key1, ..., keyn)指的是对每一列分别求sum
  • limit最大为1000, 每次最多返回1000行数据

错误码

通用错误码

Exception 报错位置 errorCode errorMsg errorDesc 日志 说明
ACServiceException CLOUD 3002 invalid param scanParam is not set scanParam is not set 没有设置scanParam

使用实例

  • 实例1:查询(device_id="001", timestamp>=1469098960, timestamp<=1469102560) 的pm25值和对应的timestamp
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("timestamp", "pm25")
        .start("timestamp", 1469098960)
        .end("timestamp", 1469102560)
        .execute();

// 输出结果
for (ACObject result:results) {
    long timestamp = result.getLong("timestamp");
    double pm25 = result.getDouble("pm25");
    System.out.Println(timestamp + "," + pm25)
}

类比SQL

SELECT `timestamp`, `pm25` FROM `device_data` WHERE `timestamp`>-1469098960 AND `timestamp`<=1469102560;
  • 实例2:查询(device_id="001", timestamp>=1469098960) 的第11条到第30条的 pm25值和对应的timestamp
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("timestamp", "pm25")
        .start("timestamp", 1469098960)
        .offset(10)
        .limit(20)
        .execute();

// 输出结果
for (ACObject result:results) {
    long timestamp = result.getLong("timestamp");
    double pm25 = result.getDouble("pm25");
    System.out.Println(timestamp + "," + pm25)
}

类比SQL

SELECT `timestamp`, `pm25` FROM `device_data` WHERE `device_id`='001' AND `timestamp`>-1469098960 limit 10,20;
  • 实例3:查询(device_id="001")的最近的20条数据的pm25值和对应的时间戳
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("timestamp", "pm25")
        .orderByDesc("timestamp")
        .limit(20)
        .execute();

// 输出结果
for (ACObject result:results) {
    long timestamp = result.getLong("timestamp");
    double pm25 = result.getDouble("pm25");
    System.out.Println(timestamp + "," + pm25)
}

类比SQL

SELECT `timestamp`, `pm25` FROM `device_data` WHERE `device_id`='001' ORDERY BY `timestamp`DESC limit 10,20;
  • 实例4:查询device_id="001"并且pm25>40.5的pm25值和时间戳
ACFilter f1 = ac.filter().whereGreaterThan("pm25", 40.5);

List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("timestamp", "pm25")
        .where(f1)
        .execute();

// 输出结果
for (ACObject result:results) {
    long timestamp = result.getLong("timestamp");
    double pm25 = result.getDouble("pm25");
    System.out.Println(timestamp + "," + pm25)
}

类比SQL

SELECT `timestamp`, `pm25` FROM `device_data` WHERE `device_id`='001' AND `pm25`>40.5 LIMIT 1000;
  • 实例5:查询device_id="001" 并且 pm25>40.5的数据行数
Filter f1 = ac.filter().whereGreaterThan("pm25", 40.5);

List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .where(f1)
        .count()
        .execute();

// 输出结果
Long count = results.get(0).getLong("_count");
System.out.Println(count)

类比SQL

SELECT count(*) FROM `device_data` WHERE `device_id`='001' AND `pm25`>40.5;
  • 实例6:计算device_id="001" 并且 timestamp>=1469098960 && timestamp<=146910256的pm25平均值
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .start("timestamp", 1469098960)
        .end("timestamp", 1469102560)
        .avg("pm25")
        .execute();

// 输出结果
Long avg_pm25 = results.get(0).getLong("_avg_pm25");
System.out.Println(avg_pm25)

类比SQL

SELECT AVG(`pm25`) as _avg_pm25 FROM `device_data` WHERE `device_id`='001' AND (`timestamp`>=1469098960 AND `timestamp`<=1469102560);
  • 实例7:查询device_id="001" (mode="auto"并且pm25>40) 或 (mode="high"并且pm25>30)的pm25,mode,timestamp,最多返回500条
ACFilter f1 = ac.filter().whereEqualTo("mode", "auto").andGreateThan("pm25", 40);
ACFilter f2 = ac.filter().whereEqualTo("mode", "high").andGreateThan("pm25", 30);

List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("timestamp", "mode", "pm25")
        .where(f1)
        .or(f2)
        .limit(500)
        .execute();

// 输出结果
for (ACObject result:results) {
    long timestamp = result.getLong("timestamp");
    String mode = result.getString("mode");
    double pm25 = result.getDouble("pm25");
    System.out.Println(timestamp + ", " + mode + ", " + pm25)
}

类比SQL

SELECT `timestamp`, `mode`, `pm25` FROM `device_data` WHERE `device_id`='001' AND (`mode`='auto' AND `pm25`>40) AND (`mode`='high' AND `pm25`>30) LIMIT 500;
  • 实例8:查询device_id="001"并且(timestamp>1469098960并且timestamp<=1469102560)的时间戳和pm25值,并按pm25值逆序排列
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .start("timestamp", 1469098960)
        .end("timestamp", 1469102560)
        .orderByDesc("pm25")
        .execute();

// 输出结果
for (ACObject result:results) {
    long timestamp = result.getLong("timestamp");
    double pm25 = result.getDouble("pm25");
    System.out.Println(timestamp + ", " + pm25)
}

类比SQL

SELECT * FROM `device_data` WHERE `device_id`='001' AND (`timestamp`>=1469098960 AND `timestamp`<=1469102560) ORDER BY `pm25`DESC;
  • 实例9:查询device_id="001"并且(timestamp>1469098960并且timestamp<=1469102560)的数据中的pm25的最大值和时间点
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("timestamp")
        .start("timestamp", 1469098960)
        .end("timestamp", 1469102560)
        .max("pm25")
        .execute();

// 输出结果
Long timestamp = results.get(0).getLong("timestamp");
Double pm25 = result.get(0).getString("pm25");

类比SQL

SELECT `timestamp`, MAX(`pm25`) as _max_pm25 FROM `device_data` WHERE `device_id`='001' AND (`timestamp`>=1469098960 AND `timestamp`<=1469102560);
  • 实例10:查询device_id="001"在使用不同mode时的speed平均值
List<ACObject> results = ac.store("device_data", ctx).scan("device_id", "001")
        .select("mode", "speed")
        .groupBy("mode")
        .execute();

// 输出结果
for (ACObject result:results) {
    String mode = result.getString("mode");
    long speed = result.getLong("speed");
    System.out.Println(mode + ", " + speed)
}

类比SQL

SELECT `mode`, `speed`, AVG(`pm25`) as _avg_pm25 FROM `device_data` WHERE `device_id`='001' GROUP BY(`mode`);

多表数据查询

同时查询多个数据集的数据

执行多表查询的数据集,必须是非分区数据集,并且属于同一个数据空间

数据集实例

以商场的订单系统为例来说明

user数据集: 商场的用户信息,记录了用户的id, 名字,地址,电话号码

order数据集: 商场的订单数据,记录了订单ID,下订单的用户,商品ID,当时的价格,下订单的时间

MultiScan

查询多个数据集的数据

标准用法

// 如果符合条件的数据不存在,则返回一个空的数组
// 查询请求和结果中的列名,必须是完整的格式(表名.列表),不支持使用不完整的列名
List<ACObject> results = ac.store(ctx, "数据集1", "数据集2", "数据集n")
        .multiScan()
        .select(key_1, ..., key_n)
        .from("基准数据集")
        .join(join条件)
        .where(filter条件)
        .and(filter条件)
        .or(filter条件)
        .sum(key_1, ..., key_n)
        .avg(key_1, ..., key_n)
        .max(key_1, ..., key_n)
        .min(key_1, ..., key_n)
        .count()
        .orderByAsc(key_1, ..., key_n)
        .orderByDesc(key_1, ..., key_n)
        .offset(数值)
        .limit(数值)
        .execute();

注意事项

  • limit最大为1000, 每次最多返回1000行数据
  • 当前仅支持内联结
  • 支持多个(>=2)数据集的联表查询
  • 如果数据集的数据量很大,则不建议使用多表查询,而是通过使用多次查询来实现

错误码

通用错误码

使用实例

  • 实例1: 查询用户名为"jack"的地址和所有订单(订单ID, 商品ID, 下单价格)
ACContext ctx = ac.newContext();

ACFilter f1 = ac.filter().whereEqualTo("user.user_name", "jack");
ACFilter f2 = ac.filter().whereEqualToColumn("user.user_id", "order.user_id");
ACJoin j1 = ac.innerJoin("order").where(f2);

List<ACObject> results = ac.store(ctx, "user", "order").multiScan()
        .select("user.user_name", "user.user_address", "order.order_id", "order.commodity_id", "order.price")
        .from("user")
        .join(j1)
        .where(f1)
        .limit(100)
        .execute();

// 输出结果
for (ACObject result:results) {
    String userName = result.getString("user.user_name");
    String userAddress = result.getString("user.user_address");
    long userOrderId = result.getLong("order.order_id");
    long commodityId = result.getLong("order.commodity_id");
    long price = result.getLong("order.price");

    System.out.println(userName + ", " + userAddress + ", " + userOrderId + ", " + commodityId + ", " + price);
}

类比SQL

SELECT `user`.`user_name`, `user`.`user_address`, `order`.`order_id`, `order`.`commodity_id`, `order`.`price` 
    FROM `user`
    INNER JOIN `order` ON (`user`.`user_id` = `order`.`user_id`)
    WHERE (`user`.`user_name` = 'jack')
    LIMIT 1000;

常见问题

无法存储emojis表情

因为数据集用的是UTF-8字符集,所以无法存储emojis表情,但可以将emoji转化为Base64写入数据集,然后读取时,再转化回emojis

使用实例:

// emoji转Base64
String srcStr = "Here is a boy: \uD83D\uDC66\uD83C\uDFFF"; // emojis字符串
String desStr = Base64.encodeToString(srcStr.getBytes("UTF-8"), Base64.NO_WRAP); // emojis转Base64

// base64转emoji
String srcStr = "SGVyZSBpcyBhIGJveTog8J+RpvCfj78="; // base64字符串
Byte[] desData = Base64.decode(srcStr, Base64.NO_WRAP); // Base64转emojis
String desStr = new String(desData, "UTF-8");

通用错误码

SDK错误

Exception errorDesc 日志 说明
IllegalArgumentException param keys is invalid param key must not be null key名字不能为NULL
IllegalArgumentException param keys is invalid param key must be string, key[xxx] keyType[xxx] key名字必须是字符串
IllegalArgumentException param keys is invalid param value must not be null, key[xxx] value不能为NULL
IllegalArgumentException param keys is invalid param value type is not supported, key[xxx] value[xxx] valueType[xxx] value的数据类型不支持
IllegalArgumentException param keys is invalid count of param keys must not be 0 (key-value)数量不能为0
IllegalArgumentException param keys is invalid count of param keys must be even, count[xxx] (key-value)必须是一一对应,所以数量必须是偶数
IllegalArgumentException invalid put param param key must not be null put的key是null
IllegalArgumentException invalid put param param value must not be null put的value是null
IllegalArgumentException invalid put param param value type is not supported, key[xxx], value[xxx] valueType[xxx] put的value的数据类型不支持
IllegalArgumentException invalid filter param param key must not be null filter的key是null
IllegalArgumentException invalid filter param param value must not be null filter的value是null
IllegalArgumentException invalid filter param param value type is not supported, key[xxx], value[xxx] valueType[xxx] filter的value的数据类型不支持
IllegalArgumentException invalid expr param param key must not be null expr的key是null
IllegalArgumentException invalid expr param param value must not be null expr的value是null
IllegalArgumentException invalid expr param param value type is not supported, key[xxx], value[xxx] valueType[xxx] expr的value的数据类型不支持
IllegalArgumentException param filter must not be empty param filter must not be empty filter不能为空
IllegalArgumentException param key of select must not be empty param key of select must not be empty select key不能为空
IllegalArgumentException param startKeys is invalid param primaryKey must not be null startKey名字不能为NULL
IllegalArgumentException param startKeys is invalid param primaryKey must be string, key[xxx] keyType[xxx] startKey名字必须是字符串
IllegalArgumentException param startKeys is invalid param primaryValue must not be null, key[xxx] startValue不能为NULL
IllegalArgumentException param startKeys is invalid param primaryValue type is not supported, key[xxx] value[xxx] valueType[xxx] startValue的数据类型不支持
IllegalArgumentException param endKeys is invalid param primaryKey must not be null endKey名字不能为NULL
IllegalArgumentException param endKeys is invalid param primaryKey must be string, key[xxx] keyType[xxx] endKey名字必须是字符串
IllegalArgumentException param endKeys is invalid param primaryValue must not be null, key[xxx] endValue不能为NULL
IllegalArgumentException param endKeys is invalid param primaryValue type is not supported, key[xxx] value[xxx] valueType[xxx] endValue的数据类型不支持
IllegalArgumentException param offset must be >=0, offset[xxx] param offset must be >=0, offset[xxx] offset必须大于等于0
IllegalArgumentException param limit must be >=0 and <=1000, limit[xxx] param limit must be >=0 and <=1000, limit[xxx] limit必须>=0 and <=1000
IllegalArgumentException param key of orderBy is conflict, key[xxx] param key of orderBy is conflict, key[xxx] orderBy的列设置的排序方式不一致
IllegalArgumentException param key of aggregate must not be empty param key of aggregate must not be empty aggregate指定的key不能为空
IllegalArgumentException param key of select must not be empty param key of select must not be empty select key 不能为null

云端错误

Exception errorCode errorMsg errorDesc/日志 说明
ACServiceException 3002 invalid param context is not set 没有设置context
ACServiceException 3002 invalid param majorDomain is not set 没有设置majorDomain
ACServiceException 3002 invalid param common user is not allowed to use store 普通终端用法无法直接使用store
ACServiceException 3002 invalid param class is not set 没有设置数据集
ACServiceException 3002 invalid param param offset must be >=0 参数offset必须>=0
ACServiceException 3002 invalid param param limit must be >=0 and <=1000 参数limit必须>=0并且<=1000
ACServiceException 3004 not allowed common user is not allowed to use store 普通用户不允许直接访问store
ACServiceException 3920 class not exist class[xxx] is not exist 数据集不存在
ACServiceException 3925 invalid value param value of key[xxx] must not be null value的值不能为null
ACServiceException 3925 invalid value param valueType of key[xxx] is not inconsistent with schema value的数据类型与schema中不一致
ACServiceException 3927 invalid filter param key[xxx] of filter is not exist in schema filter的key在schema中不存在
ACServiceException 3927 invalid filter param filter value of key[xxx] must not be null filter的value不能为null
ACServiceException 3927 invalid filter param filter valueType is not inconsistent with schema filter的value的数据类型与schema不一致
ACServiceException 3927 invalid filter param not supported filter connector[xxx] 不支持的filter connector
ACServiceException 3927 invalid filter param filter is not set filter没有设置
ACServiceException 3928 invalid expr param param expr(set, inc, dec) is empty 表达式参数不存在
ACServiceException 3928 invalid expr param expr key[xxx] must not be null 表达式key是null
ACServiceException 3928 invalid expr param expr key[xxx] is not exist 表达式key在schema不存在
ACServiceException 3928 invalid expr param expr operator[xxx] is not supported 不支持的表达式运算符
ACServiceException 3928 invalid expr param expr value of key[xxx] must not be null 表达式的value是null
ACServiceException 3929 column not exist column[xxx] is not exist in schema column在schema中不存在
ACServiceException 3930 invalid partition key partitionKeys is not set 没有设置分区键
ACServiceException 3930 invalid partition key partitionKey[xxx] is not set 分区键的某一个key没有设置
ACServiceException 3932 invalid primary key primaryKey[xxx] is not set 主键列不存在
ACServiceException 3934 invalid aggregate param keys of aggr[xxx] must not be empty 聚集函数指定的key不能为空
ACServiceException 3934 invalid aggregate param key[xxx] of aggr[xxx] is not exist in schema 聚焦函数指定的key在schema中不存在
ACServiceException 3934 invalid aggregate param not supported aggregate[xxx] 不支持的聚集函数
ACServiceException 3935 invalid groupBy param key[xxx] of groupBy is not exist in schema groupBy指定的key在schema中不存在
ACServiceException 3936 invalid orderBy param key[xxx] of orderBy is not exist in schema orderBy指定的key在schema中不存在
ACServiceException 3937 invalid select param key[xxx] of select is not exist in schema select的key在schema中不存在