目录
目录
1、KV类型接口
2、Prefix类型
2.1 Tair中的Prefix 和 Redis中的 hash 的区别
3、计数器类型
4、List列表类型
5、Set集合类型
6、Map散列类型
7、Hash类型
8、Map 与 Hash的联系与区别
基本数据类型,存储key->value 的映射,key的length小于1k,value的size小于10KB
存储类型为pkey + skey => value,
我们可以存一组以pkey为主key,skey为子key的数据,这组数据拥有相同前缀,它们在磁盘上连续存放
接口 |
行为 |
demo |
---|---|---|
prefixPut |
写入一个以pkey为主的key,一组skey |
example.prefixPut("user_", "123", "Alice"); example.prefixPut("user_", "456", "Bob"); 学生id -> value学生名字 |
prefixGet |
获取某个主key下的若干子Key的值 |
String user123 = example.prefixGet("user_", "123"); 获取 user_123 的value学生名字 |
getRange |
给一个Key的区间,获取这个区间内所有的skey和对应的value |
Map 获取 user中学生id大于100小于999的kv 组合 |
getRangeKey |
给一个Key的区间,只获取这个区间内所有的skey |
String[] rangeKeys = example.getRangeKey("user_100", "user_999"); 同上,只要key |
getRangeValue |
给一个Key的区间,只获取这个区间内所有的skey对应的value |
String[] rangeValues = example.getRangeValue("user_100", "user_999"); 同上,只要value |
import java.util.HashMap;
import java.util.Map;
public class Example {
private Map storage = new HashMap<>();
// 存储带有前缀的数据
public void prefixPut(String prefix, String key, String value) {
String prefixedKey = prefix + key;
storage.put(prefixedKey, value);
}
// 根据前缀和键获取数据
public String prefixGet(String prefix, String key) {
String prefixedKey = prefix + key;
return storage.get(prefixedKey);
}
// 获取范围内的键值对
public Map getRange(String startKey, String endKey) {
Map result = new HashMap<>();
for (String key : storage.keySet()) {
if (key.compareTo(startKey) >= 0 && key.compareTo(endKey) <= 0) {
result.put(key, storage.get(key));
}
}
return result;
}
// 获取范围内的键
public String[] getRangeKey(String startKey, String endKey) {
List keysInRange = new ArrayList<>();
for (String key : storage.keySet()) {
if (key.compareTo(startKey) >= 0 && key.compareTo(endKey) <= 0) {
keysInRange.add(key);
}
}
return keysInRange.toArray(new String[0]);
}
// 获取范围内的值
public String[] getRangeValue(String startKey, String endKey) {
List valuesInRange = new ArrayList<>();
for (String key : storage.keySet()) {
if (key.compareTo(startKey) >= 0 && key.compareTo(endKey) <= 0) {
valuesInRange.add(storage.get(key));
}
}
return valuesInRange.toArray(new String[0]);
}
public static void main(String[] args) {
Example example = new Example();
example.prefixPut("user_", "123", "Alice");
example.prefixPut("user_", "456", "Bob");
String user123 = example.prefixGet("user_", "123");
System.out.println("User 123: " + user123);
Map rangeData = example.getRange("user_100", "user_999");
System.out.println("Range Data: " + rangeData);
String[] rangeKeys = example.getRangeKey("user_100", "user_999");
String[] rangeValues = example.getRangeValue("user_100", "user_999");
System.out.println("Range Keys: ");
for (String key : rangeKeys) {
System.out.println(key);
}
System.out.println("Range Values: ");
for (String value : rangeValues) {
System.out.println(value);
}
}
}
数据结构:
prefixPut
是一种将多个键值对存储在一个桶(Bucket)中的机制。这个桶可以理解为一个存储区域,包含了以相同前缀的键值对,这样的设计可以提高存储效率和检索速度。hset
是哈希(Hash)数据结构中的一种操作。哈希是一个键值对的集合,每个键都与多个字段和对应的值相关联。适用场景:
prefixPut
适合需要高效地存储和检索以相同前缀的多个键值对的场景,例如用户属性或配置项。hset
适用于将相关字段和值组织在一个地方,以便于检索和管理,例如存储用户的个人信息。键名的关系:
prefixPut
中,多个键名有相同的前缀,这个前缀用来将它们关联到同一个桶中。hset
中,多个字段是属于同一个哈希的,这个哈希通过一个键名来标识。用途:
prefixPut
用于优化存储效率和检索速度,特别是当有许多相关键值对需要存储时,避免数据碎片。hset
用于存储多个字段和对应的值,便于组织和检索复杂的数据,适用于哈希结构。操作复杂度:
prefixPut
涉及将多个键值对组织到一个桶中,通常更适用于批量操作,但可能需要考虑桶内数据的平衡。hset
更适用于单个字段和值的操作,对单个字段的读写是O(1)的常数时间,但在一些情况下,哈希结构可能不如其他数据结构高效。对某个key对应的计数器原子的进行加减操作,计数器可以为int, double, uint64_t 等类型,两种不同的计数器类型不能作用于同一个key,由于存储格式不同,计数器的读写需要通过setCount和getCount接口,而不能使用普通的put和get接口。
很简单理解:你int类型的计数器,你put一个 3.5进去,肯定要抛异常。
接口 |
行为 |
---|---|
incr |
将某个key的计数器原子加一 |
decr |
将某个key的计数器原子减一 |
getCount |
获取某个计数器当前值 |
setCount |
设置某个计数器的当前值 |
import com.aliyun.openservices.tair.*;
import com.aliyun.openservices.tair.impl.DefaultTairManager;
public class TairExample {
public static void main(String[] args) {
String serverAddress = "xxxxx"; // Tair服务器地址
String namespace = "your_namespace"; // 命名空间
int groupId = 0; // Group ID
// 创建Tair客户端
TairManager tairManager = new DefaultTairManager(serverAddress, namespace, groupId);
// 用户ID
String userId = "user123";
// 假设点赞一次
tairManager.incr(userId + "_likes"); // 自增点赞数量
// 获取点赞数量
long likesCount = tairManager.getCount(userId + "_likes"); // 获取点赞数量
// 假设取消点赞一次
tairManager.decr(userId + "_likes"); // 自减点赞数量
// 获取点赞数量
long updatedLikesCount = tairManager.getCount(userId + "_likes"); // 获取更新后的点赞数量
// 假设记录点赞次数统计
long totalLikesCount = 1000;
tairManager.setCount(userId + "_total_likes", totalLikesCount); // 设置点赞次数统计
// 获取点赞次数统计
long retrievedTotalLikesCount = tairManager.getCount(userId + "_total_likes"); // 获取点赞次数统计
// 关闭Tair客户端
tairManager.close();
}
}
key -> [value1,value2,value3,...]
命令 |
行为 |
---|---|
list_apppend |
向list列表后面追加元素 |
list_get |
从某个位置向后取若干元素 |
list_get_and_remove |
同list_get, 取到的元素会进行删除 |
list_remove |
从某个位置向后删除若干个元素 |
list_removeall |
删除整个List的所有元素 |
import com.alibaba.tair.api.*;
import com.alibaba.tair.api.impl.DefaultTairManager;
import java.util.List;
public class StudentListDemo {
public static void main(String[] args) {
// 配置Tair客户端
TairManager tairManager = new DefaultTairManager();
tairManager.init(); // 初始化Tair客户端
// 定义namespace
String namespace = "student_list_namespace";
// 模拟学生信息
String[] studentNames = {"John Doe", "Alice Smith", "Bob Johnson"};
// 使用 list_append 将多个学生信息添加到列表中
for (String studentName : studentNames) {
tairManager.listAppend(namespace, "students", studentName);
}
// 使用 list_get 获取列表中的学生信息
List studentsList = tairManager.listGet(namespace, "students", 0, -1);
System.out.println("Students List: " + studentsList);
// 使用 list_get_and_remove 获取列表中的学生信息,并同时从列表中移除
String removedStudent = tairManager.listGetAndRemove(namespace, "students", 0);
System.out.println("Removed Student: " + removedStudent);
// 使用 list_remove 从列表中移除指定学生信息
tairManager.listRemove(namespace, "students", "Alice Smith");
// 使用 list_removeall 从列表中移除所有学生信息
tairManager.listRemoveAll(namespace, "students");
// 关闭Tair客户端
tairManager.close();
}
}
一组无序的元素集合
命令 |
行为 |
---|---|
sadd |
添加元素到已知集合 |
scard |
获取一个集合的所有元素 |
sismember |
判断给定元素是否属于此集合 |
srem |
删除集合中的某个元素 |
srem_all |
删除整个集合中的元素 |
map即就是hash类型的数据结构,是一种key-value形式的字典数据类型,存储了多个键值对之间的映射
命令 |
行为 |
---|---|
map_put |
向map写入一组kv |
map_get |
从指定map中获取若干kv |
map_getall |
获取map中的全部kv |
map_remove |
删除指定map中的若干kv |
map_removeall |
删除map中的所有元素 |
map_setnx |
向指定Map中写入数据。如果写入的子key已存在,则返回失败 |
map_exist |
判断某个子key是否存在给定map中 |
import com.aliyun.openservices.tair.Client;
import com.aliyun.openservices.tair.Result;
import com.aliyun.openservices.tair.common.ClientConfig;
import com.aliyun.openservices.tair.common.auth.DefaultCredentialProvider;
import com.aliyun.openservices.tair.common.auth.DefaultCredentials;
import com.aliyun.openservices.tair.common.domain.result.FullDataType;
import com.aliyun.openservices.tair.common.domain.result.GetResult;
import com.aliyun.openservices.tair.common.domain.result.MapItem;
import com.aliyun.openservices.tair.ext.impl.DefaultTairManager;
import com.aliyun.openservices.tair.impl.DefaultKVCache;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TairMapExample {
public static void main(String[] args) {
// 初始化Tair客户端
ClientConfig config = new ClientConfig();
config.setIoThreadNum(2);
config.setConTimeoutMs(1000);
config.setRwTimeoutMs(500);
DefaultTairManager tairManager = new DefaultTairManager();
tairManager.setConfigServerList("your_config_server_address");
tairManager.setGroupName("your_group_name");
tairManager.setNamespace("your_namespace");
tairManager.init();
DefaultKVCache cache = (DefaultKVCache) tairManager.getCache("your_cache_name");
// 向Tair中存储学生信息
Map studentInfo = new HashMap<>();
studentInfo.put("name", "Alice");
studentInfo.put("age", "20");
studentInfo.put("major", "Computer Science");
cache.mapPut("student_1", studentInfo);
// 从Tair中获取学生信息
GetResult
命令 |
行为 |
---|---|
hset |
设置Hash中的字段(键)和对应的值 |
hget |
获取指定字段的值。 |
hexists | 检查指定字段是否存在于Hash中。 |
hdel |
从Hash中删除一个或多个指定字段。 |
hincrBy |
将Hash中指定字段的值递增一个指定的步长。 |
hkeys |
获取Hash中所有字段(键)的名称。 |
hvals |
获取Hash中所有字段的值。 |
hgetAll |
获取Hash中所有字段和对应值的键值对。 |
import com.aliyun.openservices.tair.Client;
import com.aliyun.openservices.tair.Result;
import com.aliyun.openservices.tair.common.ClientConfig;
import com.aliyun.openservices.tair.common.auth.DefaultCredentialProvider;
import com.aliyun.openservices.tair.common.auth.DefaultCredentials;
import com.aliyun.openservices.tair.common.domain.result.FullDataType;
import com.aliyun.openservices.tair.common.domain.result.GetResult;
import com.aliyun.openservices.tair.common.domain.result.MapItem;
import com.aliyun.openservices.tair.ext.impl.DefaultTairManager;
import com.aliyun.openservices.tair.impl.DefaultKVCache;
import java.util.List;
import java.util.Map;
public class TairHashMethodsExample {
public static void main(String[] args) {
// 初始化Tair客户端
ClientConfig config = new ClientConfig();
config.setIoThreadNum(2);
config.setConTimeoutMs(1000);
config.setRwTimeoutMs(500);
DefaultTairManager tairManager = new DefaultTairManager();
tairManager.setConfigServerList("your_config_server_address");
tairManager.setGroupName("your_group_name");
tairManager.setNamespace("your_namespace");
tairManager.init();
DefaultKVCache cache = (DefaultKVCache) tairManager.getCache("your_cache_name");
// 使用hget获取学生姓名
String studentName = cache.hget("student_1", "name");
System.out.println("Student Name: " + studentName);
// 使用hset设置学生年龄
cache.hset("student_1", "age", "20");
// 使用hexists检查字段是否存在
boolean exists = cache.hexists("student_1", "age");
System.out.println("Age exists: " + exists);
// 使用hdel删除字段
cache.hdel("student_1", "age");
// 使用hincrby对数字字段进行增加
cache.hincrBy("student_1", "score", 10);
// 使用hkeys获取所有字段名
List fieldNames = cache.hkeys("student_1");
System.out.println("Field Names: " + fieldNames);
// 使用hvals获取所有字段值
List fieldValues = cache.hvals("student_1");
System.out.println("Field Values: " + fieldValues);
// 使用hgetall获取所有字段和值
Map fieldAndValues = cache.hgetAll("student_1");
System.out.println("Field and Values: " + fieldAndValues);
// 关闭Tair客户端
tairManager.close();
}
}
从功能上来说,Tair 中的 Hash 结构可以用来替代 Map 结构,因为 Hash 结构可以看作是 Map 结构的一种特例。在 Tair 中,Hash 结构和 Map 结构都可以用来存储键值对的数据,但它们有一些区别:
存储方式:Hash 结构的存储方式更紧凑,适合存储大量的键值对数据,而 Map 结构更具灵活性,适合存储少量的数据项。
内部实现:Tair 中的 Hash 结构在内部实现上可能会更高效,适合存储大量的键值对。而 Map 结构在存储少量数据时更方便。
功能扩展:Map 结构的功能更丰富,支持的操作更多,比如 mapGetAll
可以一次性获取所有键值对,而 Hash 结构的类似功能需要使用多个命令来完成。
虽然 Hash 结构可以替代 Map 结构,但在使用时还是要根据具体的业务需求来选择。如果你的数据量较大且需要高效的存储和访问,可以考虑使用 Hash 结构。如果数据量相对较小且需要更灵活的操作,可以选择 Map 结构。同时,考虑到代码的可读性和维护性,也可以根据业务需求选择更符合语义的数据结构。