SIndex 论文笔记:A Scalable Learned Index for String Keys

SIndex: A Scalable Learned Index for String Keys
—— 一种针对字符串的可计量学习索引

(上海交通大学 并行和分布式系统研究所)

基于当前学习索引研究热点聚焦在数字key 的查询,而不能有效执行变长字符串索引,论文团队提出了SIndex,一种针对变长字符串的并发学习索引。技术的核心是字符串分组内使用共享前缀,并使用各个关键独特的部分进行模型训练。通过在现实世界和综合数据集上的评估,结果显示SIndex 可以比其他索引结构高出91% 的性能。

随着变长字符串长度的增加,算术运算和内存访问的“挑战性”会逐步增加,此外,模型的精度还有下降的趋势,这会引发更多次的数据访问。一个直观的解决方案就是使用深度神经网络来提升位置预测精度,以期减小数据的访问次数。然而,这种方法的使用开销巨大…

受到现有字符串索引的启发,SIndex 利用共同前缀来提升查找效率。特别地,SIndex 使用公有前缀贪心地将key 聚类分组。然后,在每个组中,SIndex 使用每个key 独特的部分作为特征进行模型训练。

论文有三点贡献:

  • 提出了支持变长字符串的学习索引
  • 这种创新的学习索引在效率上有保证
  • 在现实数据集中得到了验证

下图展示了XIndex 和MassTree 在变长字符串下只读(1a)和读写(1b)情况下的性能对比:
随着字符串长度的增加,XIndex 的读写性能均显著下降。
有三点原因导致了性能下降:

  • 随着字符串长度的增加,模型耗费显著增加。即使是线性模型,128byte 时候的时间消耗也是8byte 时候时间消耗的23 倍
  • 模型的误差也随着字符串的增加而增加,从8byte 到128 byte,平均误差从24 增长到68,意味着在预测pos 之后,还需要多增
static void Main(string[] args) { //容器 string[,] classDB = new string[20, 2]; string[,] studentDB = new string[50, 4]; int studentCount = 0; //计数器 int classCount = 0; //框架 结构 while (true) { Console.WriteLine("1.班级管理 2 学生管理 3 exit"); int mark = Znsd.GetInt(); if (mark == 1) { classCount = ClassManage(classDB,classCount, studentDB, studentCount); } else if (mark == 2) { studentCount = StudentManage(classDB, classCount,studentDB,studentCount); } } } public static int ClassManage(string[,] classDB, int classCount, string[,] studentDB, int studentCount) { while (true) { Console.WriteLine("班级 1 增加 2 删除 3 修改 4 查询"); int mark = Znsd.GetInt(); if (mark == 1) { classCount = ClassInsert(classDB, classCount); } else if (mark == 2) { classCount = ClassDelete(classDB, classCount, studentDB, studentCount); } else if (mark == 3) { ClassUpdate(classDB, classCount, studentDB, studentCount); } else if (mark == 4) { ClassSelect(classDB, classCount); } else if (mark == 5) { break; } } return classCount; } public static int StudentManage(string[,] classDB, int classCount, string[,] studentDB, int studentCount) { while (true) { Console.WriteLine("学生 1 增加 2 删除 3 修改 4 查询"); int mark = Znsd.GetInt(); if (mark == 1) { studentCount = StudentInsert(classDB, classCount, studentDB, studentCount); } else if (mark == 2) { studentCount = StudentDelete( studentDB, studentCount); } else if (mark == 3) { StudentUpdate(studentDB, studentCount); } else if (mark == 4) { StudentSelect(classDB, classCount, studentDB, studentCount); } else if (mark == 5) { break; } } return studentCount; } public static int ClassInsert(string[,] classDB, int classCount) { //增加逻辑 Console.WriteLine("请输入班级编号:"); string id = Znsd.GetString(); //校验 //思路:拿着id到数组里挨个去找是否有相同的 int index = -1; for (int i = 0; i < classCount; i++) { //for就能够将数组里的每一个都拿出来stuDB[i,0] if (classDB[i, 0].Equals(id)) { index = i;//把行号 赋值给index 0 1 2 3 4 } } if (index == -1)//没有重复的 { Console.WriteLine("请输入班级描述:"); string desc = Znsd.GetString(); //将数据放入到容器 classDB[classCount, 0] = id; classDB[classCount, 1] = desc; classCount++; } else { Console.WriteLine("班级编号重复,已存在"); } return classCount; } public static int ClassDelete(string[,] classDB, int classCount, string[,] studentDB, int studentCount) { //删除 Console.WriteLine("请输入你要删除的班级编号:"); string id = Znsd.GetString(); //有才可以删除 //校验 //思路:拿着id到数组里挨个去找是否有相同的 int index = -1; for (int i = 0; i < classCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (classDB[i, 0].Equals(id)) { index = i;//把行号 赋值给index 0 1 2 3 4 } } if (index == -1)//没有重复的 { Console.WriteLine("班级编号meiyou找到 不能删"); } else { //找到了 删除 for (int i = index; i < classCount - 1; i++) { //一列一列的覆盖 classDB[i, 0] = classDB[i + 1, 0]; classDB[i, 1] = classDB[i + 1, 1]; } classCount--; //删除对应班级的学生 //??? for (int i = studentCount - 1; i >= 0; i--) { if (id.Equals(studentDB[i, 0])) { for (int j = i; j < studentCount - 1; j++) { studentDB[j, 0] = studentDB[j + 1, 0]; studentDB[j, 1] = studentDB[j + 1, 1]; studentDB[j, 2] = studentDB[j + 1, 2]; studentDB[j, 3] = studentDB[j + 1, 3]; } studentCount--; } } } return classCount; } public static void ClassUpdate(string[,] classDB, int classCount, string[,] studentDB, int studentCount) { Console.WriteLine("请输入你要修改的班级编号:"); string id = Znsd.GetString(); //校验 //思路:拿着id到数组里挨个去找是否有相同的 int index = -1; for (int i = 0; i < classCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (classDB[i, 0].Equals(id)) { index = i;//把行号 赋值给index 0 1 2 3 4 } } if (index == -1)//没有重复的 { Console.WriteLine("班级编号 meiyou找到 不能xiugai"); } else { //如何修改 Console.WriteLine("请输入新的班级编号:"); string newId = Znsd.GetString(); int flag = -1; for (int i = 0; i < classCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (classDB[i, 0].Equals(newId)) { flag = i;//把行号 赋值给index 0 1 2 3 4 } } if (flag == -1) { Console.WriteLine("请输入描述:"); string desc = Znsd.GetString(); //覆盖 classDB[index, 0] = newId; classDB[index, 1] = desc; //在学生数组里 对应的哪个班级编号也要修改 //??? for (int i = 0; i < studentCount; i++) { if (id.Equals(studentDB[i, 0])) { studentDB[i, 0] = newId; } } } else { Console.WriteLine("新的班级编号存在了。"); } } } public static void ClassSelect(string[,] classDB, int classCount) { for (int i = 0; i < classCount; i++) { Console.WriteLine("班级编号:{0};班级描述:{1}", classDB[i, 0], classDB[i, 1]); } } public static int StudentInsert(string[,] classDB, int classCount, string[,] studentDB, int studentCount) { Console.WriteLine("请输入这个学生要进入到哪个班级:"); string cid = Znsd.GetString(); //校验 //思路:拿着id到数组里挨个去找是否有相同的 int index = -1; for (int i = 0; i < classCount; i++) { //for就能够将数组里的每一个都拿出来stuDB[i,0] if (classDB[i, 0].Equals(cid)) { index = i;//把行号 赋值给index 0 1 2 3 4 } } if (index == -1)//没有重复的 { Console.WriteLine("班级编号bu存在"); } else { //增加逻辑 Console.WriteLine("请输入学号:"); string sid = Znsd.GetString(); //校验 //思路:拿着id到数组里挨个去找是否有相同的 int sindex = -1; for (int i = 0; i < studentCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (studentDB[i, 0].Equals(sid)) { sindex = i;//把行号 赋值给index 0 1 2 3 4 } } if (sindex == -1)//没有重复的 { Console.WriteLine("请输入姓名:"); string sname = Znsd.GetString(); Console.WriteLine("请输入年龄:"); string sage = Znsd.GetString(); //将数据放入到容器 studentDB[studentCount, 0] = cid; studentDB[studentCount, 1] = sid; studentDB[studentCount, 2] = sname; studentDB[studentCount, 3] = sage; studentCount++; } else { Console.WriteLine("学号重复,已存在"); } } return studentCount; } public static int StudentDelete( string[,] studentDB, int studentCount) { //删除 Console.WriteLine("请输入一个学号:xxx"); string id = Znsd.GetString(); //有才可以删除 //校验 //思路:拿着id到数组里挨个去找是否有相同的 int index = -1; for (int i = 0; i < studentCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (studentDB[i, 0].Equals(id)) { index = i;//把行号 赋值给index 0 1 2 3 4 } } if (index == -1)//没有重复的 { Console.WriteLine("学号meiyou找到 不能删"); } else { //找到了 删除 for (int i = index; i < studentCount - 1; i++) { //一列一列的覆盖 studentDB[i, 0] = studentDB[i + 1, 0]; studentDB[i, 1] = studentDB[i + 1, 1]; studentDB[i, 2] = studentDB[i + 1, 2]; } studentCount--; } return studentCount; } public static void StudentUpdate(string[,] studentDB, int studentCount) { Console.WriteLine("请输入你要修改的学号:"); string id = Znsd.GetString(); //校验 //思路:拿着id到数组里挨个去找是否有相同的 int index = -1; for (int i = 0; i < studentCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (studentDB[i, 0].Equals(id)) { index = i;//把行号 赋值给index 0 1 2 3 4 } } if (index == -1)//没有重复的 { Console.WriteLine("学号meiyou找到 不能xiugai"); } else { //如何修改 Console.WriteLine("请输入新的学号:"); string newId = Znsd.GetString(); int flag = -1; for (int i = 0; i < studentCount; i++) { //for就能够将数组里的每一个都拿出来studentDB[i,0] if (studentDB[i, 0].Equals(newId)) { flag = i;//把行号 赋值给index 0 1 2 3 4 } } if (flag == -1) { Console.WriteLine("请输入姓名:"); string name = Znsd.GetString(); Console.WriteLine("请输入年龄:"); string age = Znsd.GetString(); //覆盖 studentDB[index, 0] = newId; studentDB[index, 1] = name; studentDB[index, 2] = age; } else { Console.WriteLine("新的学号存在了。"); } } } public static void StudentSelect(string[,] classDB, int classCount, string[,] studentDB, int studentCount) { for (int i = 0; i < classCount; i++) { Console.WriteLine("班级编号:{0};班级描述:{1}", classDB[i, 0], classDB[i, 1]); for (int j = 0; j < studentCount; j++) { if (classDB[i, 0].Equals(studentDB[j, 0])) { Console.WriteLine(" 学号:" + studentDB[j, 1] + ";姓名:" + studentDB[j, 2]); } } } 请结合这个程序,写出和此程序一样的结构
06-28
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值