V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
newghost
V2EX  ›  程序员

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

  •  1
     
  •   newghost ·
    newghost · 2020-02-27 08:21:26 +08:00 · 2749 次点击
    这是一个创建于 1510 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 客户端使用帮助

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

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

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

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

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

    你说提报表组件? 目前只支持自宝义尺寸,还不支持连打。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5485 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 42ms · UTC 06:57 · PVG 14:57 · LAX 23:57 · JFK 02:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.