首页 > Berkeley DB XML, Ying Cai > Berkeley DB Xml 2.5 新特性详解一: 概述

Berkeley DB Xml 2.5 新特性详解一: 概述

2009年9月15日 蔡瀛

2009年9月14日,Berkeley DB Xml 发布了最新的2.5版本 (包含最新发布的Berkeley DB 4.8版本),此版本增加了新功能,并对上一个版本的所有bug进行了修复,是一个更快更加稳定的版本,推荐大家升级。下载地址在:http://www.oracle.com/technology/software/products/berkeley-db/index.html。 Berkeley DB Xml 2.5 新特性主要有一下几个方面:

1. 自建索引
2. 在wholeDocument存储模式下的压缩存储
3. Debugging API 和 debug 命令
4. 用户自定义XQuery external 函数
5. XmlResults 增强
6. 更高效的节点存储模式

接下来我们具体了解一下这些新特性:

1. 自建索引

自建索引是Berkeley DB Xml 2.5版的重大改进之一,他的主要功能是自动建立索引无需用户手动添加。在Berkeley DB XMl 2.5中,如果对XmlContainer打开了自建索引功能(通过XmlContainer.setAutoIndexing()方法 或者XmlIndexSpecification.setAutoIndexing()方法),当发现有新的叶子element结点或叶子attribute结点时,XmlContainer会对新的结点增加两个索引。 这两个索引分别是node-*-equality-string 和 node-*-equality-double(*表示结点名字),在默认情况下自建索引功能是被打开的。

下面我们来看一个列子,看自建索引是如何生效的

ying@bdbcn3:~$ dbxml

dbxml> createcontainer test.dbxml
Creating node storage container

dbxml> putdocument 1.xml "<root><a att1='test'>test</a><b/></root>" s
Document added, name = 1.xml

dbxml> listindex
Index: node-element-equality-string node-element-equality-double for node {}:a
Index: node-attribute-equality-string node-attribute-equality-double for node {}:att1
Index: node-element-equality-string node-element-equality-double for node {}:b
Index: unique-node-metadata-equality-string for node {http://www.sleepycat.com/2002/dbxml}:name
4 indexes found.

2. whole document 模式压缩存储

在Berkeley DB Xml 2.5中对whole document存储模式添加了压缩储存功能。经过压缩可以提高文档的储存速度和降低存储空间大小。 默认情况下使用unix系统的zlib进行压缩和解压,用户也可以使用自己的压缩和解压缩算法(通过实现XmlCompression接口)。

经过测试,在存储100万个4k大小的文档的XmlContainer,启用压缩的大小为398,516k,不使用压缩的大小为893,500k,可以节省大约55%的空间。

ying@bdbcn3:~$ du -sk *.dbxml
398516  Compressed.dbxml
893500  Uncompressed.dbxml

如果用户需要使用自己的压缩算法,可以实现XmlCompression接口, 主要实现compress()方法用于压缩,decompress()方法用于解压缩。 具体例子请参考安装包中example/cxx/misc/compression.cpp或者后续文章。

3. Debugging API和debug命令

DB XML shell 增加了一个debug命令, 启动shell后键入debug命令会进入debug模式, 可以用来调试XQuery语句。

例子:

dbxml> debug "collection('test.dbxml')/root/a"

debug> help

Command Summary
---------------

backtrace     - Prints a stack trace of the currently evaluating query
break         - Sets a break point
breakpoints   - Lists the break points set
continue      - Continues execution of the query
disable       - Disables the break point indentified by the numeric argument
enable        - Enables the break point indentified by the numeric argument
optimizeFocus - Enables or disable focus optimisations
frame         - Changes the current frame
help          - Print help information.  Use 'help commandName' for extended help
lazy          - Enables or disable lazy evaluation optimisations
list          - Prints the query at the current frame
next          - Skips query execution to the end of the current sub-expression
projection    - Enables or disable document projection optimisations
query         - Executes a query in the context of the current frame
queryplan     - Prints the query plan for the expression at the current frame
quit          - Exits the debugger
run           - Runs the query. If the query is already running it will be re-started
step          - Skips query execution forward one sub-expression

debug> run
<a att1="test">test</a>

Query completed.

Debugging API调用是通过实现XmlDebugListener接口,实现此接口的各个方法可以监控XQuery执行的每个过程。Debugging API的使用可以参考example/cxx/misc/debug.cpp或者后续文章。

4. 用户自定义XQuery externl函数

新增加的XmlExternalFunction类允许用户使用C++,Java或者Python实现XQuery的external函数( 什么是XQuery external 函数)。用户只需要继承XmlExternalFunction,并实现execute()方法。 execute()方法中包括了用户需要实现函数的功能。具体例子请参考包含于发布包的example/cxx/misc/extrenalFunction.cpp, 或者这篇文章。

5. XmlResults增强

XmlResults类增加了三个方法,用来操作“离线”的XmlResults对象。
a.XmlResults.asEventWriter(), 可以通过这个方法创建一个XmlEventWriter对象。 用这个XmlEventWriter对象可以向XmlResults中写入数据创建自己需要的XmlResults

b.XmlResults.copyResults(), 通过这个方法可以拷贝生成一个持久的XmlResults对象,不会因为container关闭而失效。
c.XmlResults.concatResults(),通过这个方法可以把两个XmlResults对象连接起来形成一个新的XmlResults对象,当然返回的对象也和container的生命周期无关。
具体的使用可以参考后续文章。

6. Node存储模式增强

改进了node储存的算法,使得在node储存的模式下XmlContainer的文件大小进一步减小。

结束语

Berkeley DB Xml 2.5版是一个更好更快的版本,本系列文章将会对前5个新特性一一通过例子说明,谢谢各位同学关注。

  1. 天门冬
    2009年10月30日13:50 | #1

    你好,在Berkeley DB Xml查询时,能只针对某个文档来查询吗?
    如:collection(‘TEST_REPO.dbxml’)/TESTRecord查询时会查询所有的文档记录。我如果只想让它查key为111的文档的记录。应该要怎么实现呢?

  2. 雨人
    2009年10月31日15:17 | #2

    你好,我最近正在使用BDB,感觉很好用,但出现几个小问题,想请教一下你们(可能发在评论里边不太合适,但实在是找不到其它可以提问的地方,请见谅)。
    我的问题是:
    我建立了一个本地BDB库,模式为DB_DUPSORT,BTREE类型,同时我设置了set_dup_compare函数(我自己写的比较函数).我的使用模式是从一个MySQL表中读入数据,然后写入本地BDB中,MySQL表中的数据可能每天都会被Update,所以我每天都希望从MySQL中读表然后更新本地BDB中的数据。现在碰到的问题是:当我第二次更新的时候,就会出现以下消息:”Duplicate data items are not supported with sorted data”,同时发现本地的BDB并没有被更新。按照BDB文档中的说法,应该是如果设置了DUP模式,那么相同KEY中比较相同的DATA应该会被新DATA覆盖(而相同DATA的比较应该是由设置好的比较函数比较的),但结果是旧DATA并没有被新DATA覆盖!
    以上是对问题的描述,还请教各位BDB之父,这是怎么回事儿?我应该如何使用才能达到我的目的?

  3. 蔡瀛
    2009年11月2日12:48 | #3

    @天门冬
    Berkeley DB Xml支持XQuery, XQuery可以针对一个文档也可以针对n个文档,举个列子:collection()//node[@id="5"]

  4. davidzhao
    2009年11月2日12:56 | #4

    如果设置了DB_DUPSORT,那么你就不可以存储完全相同的两条key/data pair。所以你遇到了那个”Duplicate data items are not supported with sorted data” 错误消息。

    当设置了DB_DUP后,如果put的时候key相同,那么这条key/data pair被当作一条新的key/data pair存入数据库。这时候,如果数据库当中已有一条完全相同的key/data pair,那么put就失败返回了。

    结论是:如果你要存储的数据集含有完全相同的key/data pair,你就不可一设置DB_DUPSORT,只能设置DB_DUP。

  5. QQ
    2009年12月8日21:06 | #5

    您好:
    我是一个学生,现在在准备毕业课题。我想在内容管理系统方面做些工作,里面涉及到一些元数据(用xml来存储)的存储和查询,我想用BDB XML来管理这些xml文件。但我不清楚BDB数据库对于数据类型方面有没有什么规定,是否能存储一些大容量的数据。例如我建了一个key,能否对于value的类型有所约束。还有就是能不能告诉我一些关于BDB数据库是如何存储的(如是如何物理存储结构或逻辑存储结构)。谢谢!

  6. 蔡瀛
    2009年12月10日12:40 | #6

    你后面的问题似乎和BDB XML的关系不大,BDB对value是没有类型限制的。关于存储的结构在BDB的reference guide里面有解释。

  7. savez
    2010年1月6日09:25 | #7

    你好,我想问一下,dbxml最大能存储一个多大的文档?

  8. 蔡瀛
    2010年1月6日17:01 | #8

    如果用Whole doc的模式,一个文档可以最大到4GB。 如果是Node模式,可以几乎达到Berkeley DB的最大存储指 256TB。

  9. 小伍
    2010年4月14日16:55 | #9

    你好,我遇到这个问题没有解决。请问下面这是什么原因呢?
    unable to allocate memory for mutex; resize mutex region
    EJB5070: Exception creating stateless session bean : [{0}]
    java.lang.OutOfMemoryError: Not enough space: unable to allocate memory for mutex; resize mutex region
    at com.sleepycat.db.internal.db_javaJNI.DbEnv_open(Native Method)
    at com.sleepycat.db.internal.DbEnv.open(DbEnv.java:313)
    at com.sleepycat.db.EnvironmentConfig.openEnvironment(EnvironmentConfig.java:999)
    at com.sleepycat.db.Environment.(Environment.java:29)

  10. 蔡瀛
    2010年4月15日13:20 | #10

    @小伍
    从异常来看需要增加mutex的数量,在java里面可以使用如下两个方法, 修改以后可能要把原来的环境删除。
    EnvironmentConfig.setMaxMutexes(int maxMutexes)
    EnvironmentConfig.setMutexIncrement(int mutexIncrement)
    http://www.oracle.com/technology/documentation/berkeley-db/xml/java/com/sleepycat/db/EnvironmentConfig.html

  11. 小伍
    2010年4月16日09:34 | #11

    Hi,你好。
    我把环境删除了(__db.*文件),但是我再运行程序的时候,出错了。
    file unknown has LSN 1/49917, past end of log at 1/28
    Commonly caused by moving a database from one database environment
    to another without clearing the database LSNs, or by removing all of
    the log files from a database environment
    E:\testing\data\InstartXmlData.dbxml: unexpected file type or format
    E:\testing\data\InstartXmlData.dbxml: unexpected file type or format
    file unknown has LSN 1/49917, past end of log at 1/28
    Commonly caused by moving a database from one database environment
    to another without clearing the database LSNs, or by removing all of
    the log files from a database environment
    E:\testing\data\InstartXmlData.dbxml: unexpected file type or format
    E:\testing\data\InstartXmlData.dbxml: unexpected file type or format
    2010-4-16 9:34:50 com.wondersgroup.dbxml.DBXML setXmlContainer
    严重: null
    com.sleepycat.dbxml.XmlException: Error: Invalid argument, errcode = DATABASE_ERROR
    at com.sleepycat.dbxml.dbxml_javaJNI.XmlManager_openContainer__SWIG_2(Native Method)
    at com.sleepycat.dbxml.XmlManager.openContainer(XmlManager.java:585)
    at com.sleepycat.dbxml.XmlManager.openContainer(XmlManager.java:218)

  12. 小伍
    2010年4月19日11:04 | #12

    HI,你好,帮我看下上面的问题吧。
    我发现我的代码如果设成xmlContainerConfig.setTransactional(false);环境删除了,可以自动再生成。
    但是我现在是需要使用事务,删除了环境之后,就报错了!

  13. 蔡瀛
    2010年4月19日13:25 | #13

    @小伍
    这个问题是由于log文件被删除了,导致log里面的LSN和数据库文件里面的不一致。试试看这样做:用dbxml_dump把container的内容dump 出来,然后删除原来环境下面的东西,然后在重新建立环境和container,在用dbxml_load把原来的内容导入进去。

  14. 小伍
    2010年4月21日09:55 | #14

    我用dbxml_dump好像也不行哦,好像还是那个问题!
    E:\testing\data>dbxml_dump -f E:\testing\bak\InstartXmlData.dbxml InstartXmlData.dbxml
    dbxml_dump: file unknown has LSN 1/49917, past end of log at 1/28
    dbxml_dump: Commonly caused by moving a database from one database environment
    dbxml_dump: to another without clearing the database LSNs, or by removing all of
    dbxml_dump: the log files from a database environment
    dbxml_dump: InstartXmlData.dbxml: unexpected file type or format
    dbxml_dump: dump InstartXmlData.dbxml: Error: Invalid argument

  15. 蔡瀛
    2010年4月21日10:59 | #15

    @小伍
    那就需要重新设置lsn了,可以使用db_load命令(BDB的一个工具),具体的命令形式如下: db_load -r lsn InstartXmlData.dbxml 或者在你的程序里面调用这个函数Environment.resetLogSequenceNumber(String filename, bool encrypted). 做完上面这个重置lsn的步骤以后,你需要把原来环境的所有文件都删除,然后重写建立环境重新打开container文件。你在事务的环境里面运行的时候,不能删除log文件(log.000000001形式的)。如果要删除log文件需要使用db_archive工具,具体的使用可以查看文档。

  16. 小伍
    2010年4月22日09:39 | #16

    你好,我做了一个测试:
    我先putDocument往DBXML里面存了A和B两个文档。然后我把环境删除(__db.*文件,保留log.000000001)。我再读取文档A和B的时候,发现这两个文档不存在了。
    这是不是我的数据已经没有了,还是怎么了?

  17. 蔡瀛
    2010年4月26日13:08 | #17

    你在什么情况下删除那些文件,什么情况下读取。

  18. littlebird
    2010年8月20日09:59 | #18

    你好,我刚刚接触DBXML。我发现,如果在Java EE环境下,需要把%DBXML%bin下的四个lib开头的dll文件拷入%JEE服务器%bin目录下,否则会报找不到好像是Lab_Java48这个类的异常,但是在Java SE环境下,调用DBXML的jar包中的api就没问题。请问,那四个lib开头的dll文件有什么用?是为了告诉Jee服务器(我用的是Glassfish)DBXML安装位置吗?但是知道安装位置又有什么用呢?数据库操作需要的jar包不都已经引入工程了么。或者是为了调用操作系统的底层函数(比如文件操作等,我用的是windows)?如能得到答复答,非常感谢!

  19. 蔡瀛
    2010年8月20日14:09 | #19

    @littlebird DB XML的Java API是对C++ API的包装,由JNI的方式实现,所有的底层功能是由dll来完成。使用Java API的时候需要这些dll所在的目录在PATH环境变量中。或者可以由java的 -Djava.library.path= 参数来指定。

  20. littlebird
    2010年8月28日10:54 | #20

    @蔡瀛
    你好,非常感谢您的回复!我在PATH环境变量中已经添加了%DB XML%路径,可能是Glassfish没有读环境变量吧。再次感谢!

  21. cars
    2010年11月10日17:44 | #21

    你好:我想问一下Berkeley DB的索引实现基本原理,索引是和数据在同一文件中吗?在一个bdb环境下建立多个相同的数据库,是不是会提高bdb的存储和查询效率,我个人认为bdb的索引和数据在同一文件中,这样建立多个相同的数据库时更新索引的范围就限制在了一个数据库文件中,减少了索引更新所消耗的时间(比更新一个大的索引),不知道是不是这样的?谢谢

  22. 赵汝聪
    2010年11月22日11:19 | #22

    您好,在回答你的问题前,请问所指的是”BDB”的索引,还是”DBXML”的索引。这两者实现上是不同的。

    另外请问“相同的数据库”具体所指?一般说来保持多个数据库的一致性需要额外的开销,不会提高存储效率。

  23. Edward
    2010年11月22日14:58 | #23

    您好,我想使用bdbxml与spring集成, 有没有类似的代码实现了呢?谢谢。

  24. Edward
    2010年11月24日12:59 | #24

    怎么我的回复还没有通过审核显示出来?
    另外再问一下,有cocoon + bdb xml的实现例子吗?

  25. 赵汝聪
    2010年11月29日13:48 | #25

    @Edward
    你好。Berkeley DB XML支持Java接口,因此只要在服务器上安装部署好Berkeley DB XML(包括jar文件及对应的库文件),即可在框架中调用DBXML的Java接口。
    请参照文档:http://download.oracle.com/docs/cd/E17276_01/html/toc.htm
    欢迎进一步提问,谢谢。

  26. Edward
    2010年11月30日09:01 | #26

    你好,我正在使用bdbxml, 我现在自己实了现一些xquery module,但是应该放在文件系统的什么路径下面。能够通过import module namespace tm=’http://brians.org/temperature’ at ‘temperature.xq’;引入。我现在这条语句报了cannot read query content from F:\bdbxml/dbxml:/temperature.xq [xqst0059]错误, 但是import module namespace my=”http://brians.org/temperature” at “file:///F:/bdbxml/temperature.xq”;这样却能成功,我应该怎么去配置呢?
    谢谢。

  27. Edward
    2010年11月30日09:13 | #27

    另外bdbxml有没有可能解析xquery和exist db 或者 marklogic 一样?即:
    bdbxm一定需要这样的语句collection(“mondail.dbxml”)//country/name才能找出country/name,
    但是marklogic只要//country/name就行了,而且我不关心数据在collection(“mondail.dbxml”)里面或者其他地方,我只想要知道所有的country/name。

    请赐教,谢谢。

  28. 赵汝聪
    2010年11月30日11:29 | #28

    @Edward
    你好,”F:\bdbxml”是Windows下的路径格式,在xml中应该用你后面的这种路径格式:file:///f:/dbxml/temperature.xq
    对于相对路径(前提是xq文件在当前路径下),可用file://temperature.xq

  29. 赵汝聪
    2010年11月30日12:55 | #29

    @Edward
    可以使用XmlQueryContext::setDefaultCollection来设置当前的collection. 然后在该QueryContext下只需要用collection()访问即可,不需要指定名字。
    DbXml Java API和DbXml shell里面也有对应的函数/指令,作用是一样的。

  30. Larry
    2010年12月5日20:33 | #30

    您好: 目前使用dbxml 2.5.16版本 on windows(c language)
    在執行dbEnv::open這個函式總是出現error
    訊息如下:
    Directory (null) not in environment list.
    illegal flag specified to DB_ENV->remove
    Invalid argument
    DB_ENV->dbremove: method not permitted before handle’s open method
    即使設定的環境路徑為C:\\也是不行。

  31. Larry
    2010年12月5日22:24 | #31

    @Larry
    後來看了一下, 觀察了一下使用db_env_create產生出來的環境變數。
    發現DB_ENV::set_cachesize –> set_env_create_directory(__db_env*, const char *)
    DB_ENV::open –> __env_remove

    ……
    簡單說就是從某一個function pointe開始,每個function pointer會對應到後一個function pointer的函式。不知道是不是使用了不正確的函式庫??

  32. 赵汝聪
    2010年12月6日16:57 | #32

    @Larry
    你好,有可能是编译时的库和运行时库没有对应上。比如说编译DbXml时使用的是db4.8版本,但系统同时还安装了一个老版本(比如说db4.6)。那么运行的时候链到了老版本库上就有可能会有问题。
    请检查一下系统环境中有没有安装有老版本的DbXml/BDB。并且用工具查看DbXml是否链接到了预期中的目标库(如Windows中用Dependency Walker, Linux中用ldd)。

本文的评论功能被关闭了.
Դ