OnceDB 内存数据库引擎:像关系型数据库那样,查询、搜索、更新、全文索引海量 Redis 数据

2020-02-27 08:21:26 +08:00
 newghost

OnceDB 是基于 Redis 二次开发的全文搜索内存数据库,支持像 SQL 关系数据库和 NoSQL 无模式数据库那样管理数据。

OnceDB 并不改变 Redis 的数据存储结构,与 Redis 3.x 完全兼容,Redis 数据库文件可以直接在 OnceDB 中操作,并再返回 Redis 中使用。

Redis 特点

性能强劲

我们一直在开发能够运行在 arm 和 x86 平台上的管理软件。很多 arm 开发板运行在 TF 存储卡止。TF 卡的读写速度其实非常有限,读取、写入速度在 10~30M/s 之间,只有 Redis 这样的内存数据库,才能够在 arm 设备持续向外传送文件时,依然保持非常优异的并发能力,而不会造成 Web 服务不可用。

开发效率

Redis 中存放的只是一些基本的数据结构,只能通过复杂的方法实现数据索引、查询,所以如果只使用 Redis 数据库的话,开发效率非常低。所以一般以其它数据库为主,Redis 作为高性能缓存层来使用。

二次开发 Redis

为了充分利用 Redis 优异的性能,并能像 MySQL 或 MongoDB 数据库那样适应更多应用场景并提高开发效率。我们基于 Redis 进行了二次开发,添加了全文搜索,多条件查询,分析计算等功能。并通过辅助索引,提高在海量数据下搜索和查询的性能。该项目命名为 OnceDB, 支持 Windows 和 Linux,

快速安装 OnceDB

在 Github 上选择相应操作系统和芯片架构的安装包,解压即可运行。

https://github.com/OnceDoc/OnceDB/releases/

在 Windows 平台下,运行 oncedb-server.exe 即可启动服务。

OnceDB 辅助索引

OnceDB 通过有序列表( zset )实现辅助索引,大幅提高在复杂查询条件下,搜索海量数据的性能。

OnceDB 可使用 upsert 或 insert 命令添加数据,并通过操作符来自动创建这些索引。

比如添加一条 user:dota 数据,并设置相应索引:

@ username 为主键字段
? 为 title 创建分组索引
* 为 skills 创建关键字索引

命令如下

upsert user username @ dota password = 123456 title ? SDEI skills * java,go,c
> OK

然后可使用 find 指令查询数据,如果是是索引字段,可通过操作符从索引中搜索,比如搜索包含 c 关键字的 user 数据,则使用 “*” 操作符。打印 username 和 password 字段,使用 "= *" 来表达:

find user 0 -1 username = * password = * skills * c
1) (integer) 1
2) "user:dota"
3) "dota"
4) "123456"
5) "java,go,c"

搜索结果第 1 行 “(integer) 1” 为符合条件的数据总数。如果使用全文搜索,则会返回 -1。

比如全文搜索包含 c 的数据, 可使用 "~" 操作符:

find user 0 -1 username = * password = * skills ~ c
1) (integer) -1
2) "user:dota"
3) "dota"
4) "123456"
5) "java,go,c"

返回的 -1 表明使用了全文搜索,全文搜索支持 “<, >, <=, >=' 等数值比较搜索。

更多指令帮助请参考: OnceDB 数据修改和查询帮助文档

OnceDB 驱动客户端( node.js )

OnceDB 并不在底层约束数据模式,而通过驱动层来动态定义数据表、字段、类型、索引等,改变 Schema 定义即可扩展现在有表和字段,从而实现模式的动态定义。

OnceDB 客户端已经发布,可通过 npm 可安装:npm install oncedb

安装完成后可,连接到本地 oncedb-server:

var oncedb = require('oncedb')()

在更新查询数据前,需要先定义 schema 数据模式,指定含有哪些字段,设置字段类型,索引等。比如上文的 user 数据,可定义成如下模式:

oncedb.schema('user', {
    username  : 'id'
  , password  : ''
  , title     : 'index'
  , skills    : 'keywords'
});

然后可以通过 oncedb.upsert 更新数据。

oncedb.upsert('user', { username: 'dota', password: '123456', title: 'SDEI', skills: 'java,go,c' }, function(err) {
  // done
})

然后查询数据,此时会自动根据 schema 中的定义,从相应索引查询数据。

oncedb.select('user', { skills: 'c' }, function(err, rows) {
   console.log('rows.count', rows.count)
   console.log(rows)
})

async / await 同步语法

可使用 util.promisify 格式化接口,将回调改造成 async/ await 同步语法:

const util    = require('util')
const oncedb  = require('oncedb')()

const update  = util.promisify(oncedb.update).bind(oncedb)
const select  = util.promisify(oncedb.select).bind(oncedb)

然后上面的 callback 模式就可改写成顺序模式:

// 更新数据
await upsert('user', { username: 'dota', password: '123456', title: 'SDEI', skills: 'java,go,c' })
// 查询数据
let rows = await select('user', { skills: 'c' })

console.log('rows.count', rows.count)
console.log(rows)

输出结果:

rows.count 1
[
  {
    _key: 'user:dota',
    skills: [ 'java', 'go', 'c' ],
    username: 'dota',
    password: '123456',
    title: 'SDEI'
  }
]

此时可根据 rows.count 来判断是不是启用了索引搜索,如果是 -1,则代表使用了全文搜索。

更多帮助请参考: OnceDB Node.JS 客户端使用帮助

2876 次点击
所在节点    程序员
10 条回复
JG
2020-02-27 08:48:42 +08:00
源码只开源了个 README,楼主是做嵌入式设备的?如果要在 arm 上用 redis 做持久化目前自带的持久化功能存 TF 卡上性能能接受吗?还是用的什么其他数据库做的持久化?
itskingname
2020-02-27 10:17:57 +08:00
NoSQL 的语法分明比 SQL 好用得多易读易写,楼主非要让 SQL 进来插一脚。
newghost
2020-02-27 10:30:27 +08:00
@JG

性能可以,Web 使用的也是全缓存的架构, 持久化时没有感觉,对性能无影响。
newghost
2020-02-27 10:32:23 +08:00
@itskingname

指令只是借鉴了一下 sql 的写法,并不是真的 SQL,底层指令 Redis 原来的命令协议一样。驱动层跟 NoSQL 差不多。
dk7952638
2020-02-27 10:55:35 +08:00
有点厉害,战略性 star 一下,期待以后能开源
itskingname
2020-02-27 14:09:34 +08:00
@newghost 我的意思就是说,SQL 的这些语句写法,比 Redis 原来的命令可读性、易用性差。
newghost
2020-02-27 21:42:05 +08:00
@itskingname

同意,我们也只是在命令名称上参考了一下,本质完全不同
newghost
2020-02-27 21:42:25 +08:00
@dk7952638

以后可能会开源
4IoNut698v3Xgc2p
2020-03-11 16:28:57 +08:00
强烈支持,大概看了下官网,准备过两天深度测试下企业这个,目前有一个疑问:打印出库的支持自定义尺寸么?毕竟有个公司可能用 A4,而也有很多打 3 联那种横版。
newghost
2020-03-12 09:19:16 +08:00
@praming

你说提报表组件? 目前只支持自宝义尺寸,还不支持连打。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/647916

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX