levelDB数据库使用及实例 - 高性能nosql存储数据库

LevelDB是google公司开发出来的一款 超高性能kv存储引擎,以其惊人的读性能和更加惊人的写性能在轻量级nosql数据库中鹤立鸡群. 此开源项目目前是支持处理十亿级别规模Key-Value型数据持久性存储的C++ 程序库。在优秀的表现下对于内存的占用也非常小,他的大量数据都直接存储在磁盘上.可以理解为以空间换取时间.

任何东西都不是十全十美的,LevelDB也有它的局限性:

LevelDB 只是一个 C/C++ 编程语言的库, 不包含网络服务封装, 所以无法像一般意义的存储服务器(如 MySQL)那样, 用客户端来连接它, 使用者应该封装自己的网络服务器.

node.js下如何使用LevelDB ?

node.js环境下使用需要npm 包 levelUP,levelDown 来支持. npm install levelUP levelDown 或者你也可以这样 npm install level 提醒:levelup 版本最好用0.10.0或者更低版本,最新版本和leveldown编译时出问题. npm 安装指定版本依赖包 所以这样比较安全 npm install [email protected] leveldown

如何使用?

api定义非常简单. var levelup = require(‘levelup‘); var db = levelup(‘./yijiebuyi‘); //这里的路径就是物理存储数据的文件路径,建议不要放到项目中. 下面是常用的获取,设置api (引用自 github node-levelup https://github.com/rvagg/node-levelup)

    // put a key & value
    db.put(‘name‘, ‘LevelUP‘, function (err) {
        if (err) return console.log(‘Ooops!‘, err) // some kind of I/O error

        // fetch by key
    db.get(‘name‘, function (err, value) {
        if (err) return console.log(‘Ooops!‘, err) // likely the key was not found

        // ta da!
        console.log(‘name=‘ + value)
    })
})

一介布衣博客 采用了node.js + leveldb 方式,上面的这个数据库封装类也是一介布衣博客使用的一个通用帮助文件.

关于levelDB的api我简单做了一个封装,代码如下:

//设置
function put(key, value, callback) {
    if (key && value) {
        db.put(key, value, function (error) {
            callback(error);
        })
    } else {
        callback(‘no key or value‘);
    }
}

//获取
function get(key, callback) {
    if (key) {
        db.get(key, function (error, value) {
            callback(error, value);
        })
    } else {
        callback(‘no key‘, key);
    }
}
//删除
function del(key, callback) {
    if (key) {
        db.del(key, function (error) {
            callback(error);
        })
    } else {
        callback(‘no key‘);
    }
}
//批量操作
function batch(arr, callback) {
    if (Array.isArray(arr)) {
        var batchList = [];
        arr.forEach(item)
        {
            var listMember = {};
            if (item.hasOwnProperty(‘type‘)) {
                listMember.type = item.type;
            }
            if (item.hasOwnProperty(‘key‘)) {
                listMember.key = item.key;
            }
            if (item.hasOwnProperty(‘value‘)) {
                listMember.value = item.value;
            }
            if (listMember.hasOwnProperty(‘type‘) && listMember.hasOwnProperty(‘key‘) && listMember.hasOwnProperty(‘value‘)) {
                batchList.push(listMember);
            }
        }
        if (batchList && batchList.length > 0) {
            db.batch(batchList, function (error) {
                callback(error, batchList);
            })
        } else {
            callback(‘array Membre format error‘);
        }
    } else {
        callback(‘not array‘);
    }
}
//查找 (支持前置匹配)
function find(find, callback) {
    var option = {keys: true, values: true, revers: false, limit: 20, fillCache: true};
    if (!find)
        return callback(‘nothing‘, null);
    else {
        if (find.prefix) {
            option.start = find.prefix;
            option.end = find.prefix.substring(0, find.prefix.length - 1)
                + String.fromCharCode(find.prefix[find.prefix.length - 1].charCodeAt()+1);}if(find.limit)
            option.limit = find.limit;

        db.createReadStream(option).on(‘data‘,function(data){
            data&&callback(data.key, data.value);}).on(‘error‘,function(err){}).on(‘close‘,function(){}).on(‘end‘,function(){return callback(null,Date.now());});}}

exports.put = put;
exports.get=get;
exports.del=del;
exports.find = find;
exports.batch = batch;

代码注释的不详细,我直接拷贝过来的,方法名基本保持和api一致,大家应该能看明白 里面的 get ,put ,delete 都非常好理解,就是根据key去查询value ,插入一对key和value ,根据key删除value. find 方法可能不是特别好理解,在levelDB存储复杂数据结构中讲到用前置匹配的方法来查询索引正是用到了createReadStream 方法,这是原生api里的方法,我利用这个api封装成了 find() 方法.下面主要说一下前置匹配.

createReadStream 方法的前置匹配

回顾一下,我库里有如下key-value 键值对 abc --> 111 abd --> 333 abm --> 777 abw --> 999 那么我可以用createReadStream方法查询出以 ab开头的key 对应的所有value,安装key的读取顺序把value一个一个返回.我们贴出createReadStream调用代码:

db.createReadStream()
  .on(‘data‘, function (data) {    console.log(data.key, ‘=‘, data.value)
  })
  .on(‘error‘, function (err) {    console.log(‘Oh my!‘, err)
  })
  .on(‘close‘, function () {    console.log(‘Stream closed‘)
  })
  .on(‘end‘, function () {    console.log(‘Stream closed‘)
  })

它监听了一个读取流,要触发如下事件 on(‘data’ 将读取到的value按照读取顺序返回. on(‘error’ 发生错误时要做什么 on(‘close’ 关闭流时要做什么 on(‘end’ 流结束时做什么 其实这个api可以接受一个参数,参数可以指定key的开始位置 ,结束位置,然后就可以做到前置匹配,我把此方法封装了一下,在levelup使用方法一文中已经贴出了代码,下面再单独把此方法的封装贴一下

function find(putoption, callback) {
    var option = {keys: true, values: true, revers: false, limit: 20, fillCache: true};
    if (!putoption)
        return callback(‘nothing‘, null);
    else {
        if (putoption.prefix) {
            option.start = find.prefix;
            option.end = find.prefix.substring(0, find.prefix.length - 1)
                + String.fromCharCode(find.prefix[find.prefix.length - 1].charCodeAt() + 1);
        }

        if (putoption.limit)
            option.limit = find.limit;

        db.createReadStream(option).on(‘data‘,function (data) {
            data&&callback(data.key, data.value);
        }).on(‘error‘,function (err) {
            }).on(‘close‘,function () {
            }).on(‘end‘, function () {
                return callback(null, Date.now());
            });
    }
}

putoption 是外部出入的参数对象, option 是内部组合的参数对象, createReadStream 可以指定读取key的开始位置(如 option.start ),结束位置(option.end ),以及读取多少条记录 (option.limit)

使用场景,就拿一介布衣博客博文存储的数据结构来说起:

一介布衣 博客中有nosql分类,点击nosql应该加载此分类下的所有博文并分页. 首先,博文的存储类型如下 key: blog.fse89fw8fwe89fwe98fweiwe9f value: {_id:’fse89fw8fwe89fwe98fweiwe9f’,title:’levelDB存储复杂数据结构’,content:’省略500字’,category:’nosql’,tag:’nosql,levelDB,levelDB存储结构’,create_time:13987546090,click:10}

如上,key为了全部全局唯一 所以用常量 blog.+博文唯一ID value 是一个字符串,我们读出来后需要反序列化成json来使用,包括唯一ID,标题,内容,类别,标签,创建时间和点击数

到这里并没有结束,你还需要做很多工作,比如我根据类别查询博客,根据标签查询博客,根据时间统计,排序等… 所有的kv数据库貌似都是根据key查询value ,而不能逆向查询 (如果有,请告诉我) levelDB也是,所以我们下面要创建一系列的索引来支撑上面的查询工作.

索引的key本人规定 .开头,只是为了维护,你可以命名自己的索引是 芝麻开门 开头或者更奇葩的都行. 类别索引 key : .category.nosql:fse89fw8fwe89fwe98fweiwe9f value : fse89fw8fwe89fwe98fweiwe9f

这个索引的作用就是,通过 nosql 我要找到属于这个类别的博文ID,然后根据ID找到博文 说明一下,key组成结构 常量 .category + 类别名 .nosql + 博文ID fse89fw8fwe89fwe98fweiwe9f value 组成结构 很简单,就是一个博文ID

你也许有疑问:

1.key里面为啥要有 前置常量 .category ,因为我还有标签的索引 .tag 开头的,只是为了区分 2.既然 category 后面已经加上 nosql 类别,为啥还要加一个 博文ID,因为保证此索引是唯一的,我明天继续写一篇关于 levelDB 的文章,他的类别还是 nosql,如果没有这个博文ID,那么就把今天的key完全覆盖了.我的索引是没有意义的. 3.你的索引就是为了查找 博文ID,我需要通过 key 来查找 value,这不是骑着毛驴找毛驴吗? 开始这个问题确实让人迷糊,首先你要同意上面第二点的说明,接着我们来说明如何在没有博文ID的情况下使用此索引找到博文ID 因为levelDB有一项强大的功能,前置匹配,他可以用key的子集去匹配类似的key,注意这里有个前提,必须的从key的0位置开始,就是从头匹配 比如 key是 abcdef 你可以用 a 匹配到这个key,用ad匹配到,用 abc,abcd,abcde 都可以.但是不能用 bcdef来匹配,这样是不行的.

再回头看第三个问题,我根据类别找博文的时候是用下面的key .category.nosql: 用这个key 我可以匹配到 N个key ,这些key对应的博文ID 都是nosql相关的,然后我再遍历博文ID获取博文

时间: 2024-10-23 03:37:53

levelDB数据库使用及实例 - 高性能nosql存储数据库的相关文章

什么时候该使用NoSQL存储数据库?

原文地址:http://www.jdon.com/39240 文章总结以下几点:1.频繁写,很少读统计数据,比如点击率,应该使用基于内存的in-memory的key/value存储数据库如Redis, 或者update-in-place 文本存储如MongoDB. 2.大数据Big Data (如天气数据 业务分析数据) 可以使用分布式数据库系统如Hadoop. 3.二进制数据(如MP3s 和PDFs文档) ,直接存储直接发送给客户端浏览器,如Amazon S3. 4.短暂数据 (如web se

发布一个参考ssdb,用go实现的类似redis的高性能nosql:ledisdb

起因 ledisdb是一个参考ssdb,采用go实现,底层基于leveldb,类似redis的高性能nosql数据库,提供了kv,list,hash以及zset数据结构的支持. 我们现在的应用极大的依赖redis,但随着我们用户量越来越大,redis的内存越来越不够用,并且replication可能还会导致超时问题.虽然后续我们可以通过添加多台机器来解决,但是在现有机器配置下面,我们仍希望单台机器承载更多的用户.另外,因为业务的特性,我们其实并不需要将所有的数据放到内存,只需要存放当前活跃用户.

HTML5 indexedDB前端本地存储数据库实例教程 (转载)

一.indexedDB为何替代了Web SQL Database? 跟小朋友的教育从来没有什么“赢在起跑线”这种说法一样,在前端领域,也不是哪来先出来哪个就在日后引领风骚的. HTML5 indexedDB和Web SQL Database都是本地数据库数据存储,Web SQL Database数据库要出来的更早,然并卵.从2010年11月18日W3C宣布舍弃Web SQL database草案开始,就已经注定Web SQL Database数据库是明日黄花. 未来一定是indexedDB的,从

如何在一个实例下并存行存储和列存储数据库

相关概念 BLU Acceleration BLU Acceleration 是 DB2 10.5 最新特性,与传统的行存储数据方式不同,数据是按照列来进行组织存储的,即采用列式存储.BLU 除了列存储表特性外,它的数据跳读,SIMD 和类哈弗曼的压缩算法等特性方便在内存中完成数据处理,简化并且加速了数据分析的工作量.同时不再需要索引.MQT 等,这样易于实施并可以自行调优,提高了 CPU 的使用率,以及降低了 IO. IBM Data Server Manager IBM 最新推出的管理多种平

服务的扩展性(如何创建具有可扩展性的服务实例,缓存以及数据库)

转自:http://www.cnblogs.com/loveis715/p/5097475.html 在编写一个应用时,我们常常考虑的是该应用应该如何实现特定的业务逻辑.但是在逐渐发展出越来越多的用户后,这些应用常常会暴露出一系列问题,如不容易增大容量,容错性差等等.这常常会导致这些应用在市场的拓展过程中无法快速地响应用户的需求,并最终失去商业上的先机. 通常情况下,我们将应用所具有的用来避免这一系列问题的特征称为非功能性需求.相信您已经能够从字面意义上理解这个名词了:功能性需求用来提供对业务逻

大数据时代的 9 大Key-Value存储数据库

在过去的十年中,计算世界已经改变.现在不仅在大公司,甚至一些小公司也积累了TB量级的数据.各种规模的组织开始有了处理大数据的需求,而目前关系型数据库在可缩放方面几乎已经达到极限. 一个解决方案是使用键值(Key-Value)存储数据库,这是一种NoSQL(非关系型数据库)模型,其数据按照键值对的形式进行组织.索引和存储.KV存储非常适合不涉及过多数据关系业务关系的业务数据,同时能有效减少读写磁盘的次数,比SQL数据库存储拥有更好的读写性能. 本文就为你介绍9种用于大数据处理的免费键值存储数据库.

(转)[转]大数据时代的 9 大Key-Value存储数据库

在过去的十年中,计算世界已经改变.现在不仅在大公司,甚至一些小公司也积累了TB量级的数据.各种规模的组织开始有了处理大数据的需求,而目前关系型数据库在可缩放方面几乎已经达到极限. 一个解决方案是使用键值(Key-Value)存储数据库,这是一种NoSQL(非关系型数据库)模型,其数据按照键值对的形式进行组织.索引和存储.KV存储非常适合不涉及过多数据关系业务关系的业务数据,同时能有效减少读写磁盘的次数,比SQL数据库存储拥有更好的读写性能. 本文就为你介绍9种用于大数据处理的免费键值存储数据库.

浅尝key-value数据库(一)——一览NoSQL

浅尝key-value数据库(一)——一览NoSQL 最近由于一个项目的关系,研究了一下key-value数据库这个最近很火的概念.本系列从项目需求的角度分析并测试了几个key-value数据库的性能. key-value数据库,又称作NoSQL数据库,他的最基本的基础原理就是CAP. CAP是2000年PODC上Eric Brewer提出的一个概念,即 C -> Consistency; A -> Availability; P -> Tolerance to network Part

mongodb 分布式文档存储数据库

简述: MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的. 他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型. Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引. 在高负载的