Fabric支持两种类型的状态数据库:LevelDBCouchDBLevelDB默认嵌入在peer节点中,用于将合约数据存储为简单的key-value,仅支持键、键范围和组合键查询。CouchDB是可选的状态数据库,支持以JSON格式在账本中建模存储数据,且支持富查询。CouchDB同样支持在合约中部署索引,以便高效查询和对大型数据集的支持。

LevelDB是以二进制的形式存储数据。

只有基于内容的JSON查询才能发挥出CouchDB的优势,即合约数据必须以JSON格式来存储,这就要求在部署区块链网络之前就确定要使用LevelDB还是CouchDB(因为数据兼容性的问题,不支持节点从LevelDB切换到CouchDB,且网络中各个节点都必须使用相同类型的状态数据库)。CouchDB支持JSON格式和二进制形式的数据存储,但二进制的数据仅支持支持键、键范围和组合键查询。

启用CouchDB

CouchDB 是独立于节点运行的一个数据库进程。在安装、管理和操作的时候有一些额外 的注意事项。有一个可用的 Docker 镜像 CouchDB 并且我们建议它和节点运行在同一个服务器上。我们需要在每一个节点上安装一个 CouchDB 容器,并且更新每一个节点的配置文件 core.yaml ,将节点指向 CouchDB 容器。 core.yaml 文件的路径必须在环境变量 FABRIC_CFG_PATH 中指定:

  • 对于 Docker 的部署,在节点容器中 FABRIC_CFG_PATH 指定的文件夹中的 core.yaml 是预先配置好的。如果你要使用 docker 环境,你可以通过重写 docker-compose-couch.yaml 中的环境变量来覆盖 core.yaml
  • 对于原生的二进制部署, core.yaml 包含在发布的构件中。

编辑 core.yaml 中的 stateDatabase 部分。将 stateDatabase 指定为 CouchDB 并且填写 couchDBConfig 相关的配置。在 Fabric 中配置 CouchDB 的更多细节,请参阅 CouchDB 配置

创建一个索引

索引可以让数据库不用在每次查询的时候都检查每一行,可以让数据库运行的更快和更高效。 一般来说,对频繁查询的数据进行索引可以使数据查询更高效。为了充分发挥 CouchDB 的优 势 – 对 JSON 数据进行富查询的能力 – 并不需要索引,但是为了性能考虑强烈建议建立 索引。另外,如果在一个查询中需要排序,CouchDB 需要在排序的字段有一个索引。

没有索引的情况下富查询也是可以使用的,但是会在 CouchDB 的日志中抛出一个没 有找到索引的警告。如果一个富查询中包含了一个排序的说明,需要排序的那个字段 就必须有索引;否则,查询将会失败并抛出错误。

为了演示构建一个索引,我们将会使用来自 Marbles sample. 的数据。 在这个例子中, Marbles 的数据结构定义如下:

type marble struct {
         ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database
         Name       string `json:"name"`    //the field tags are needed to keep case from bouncing around
         Color      string `json:"color"`
         Size       int    `json:"size"`
         Owner      string `json:"owner"`
}

在这个结构体中,( docType, name, color, size, owner )属性 定义了和资产相关的账本数据。 docType 属性用来在链码中区分可能需要单独查询的 不同数据类型的模式。当时使用 CouchDB 的时候,建议包含 docType 属性来区分在链 码命名空间中的每一个文档。(每一个链码都需要有他们自己的 CouchDB 数据库,也就是 说,每一个链码都有它自己的键的命名空间。)

在 Marbles 数据结构的定义中, docType 用来识别这个文档或者资产是一个弹珠资产。 同时在链码数据库中也可能存在其他文档或者资产。数据库中的文档对于这些属性值来说都是 可查询的。

当为链码查询定义一个索引的时候,每一个索引都必须定义在一个扩展名为 *.json 的文本文件中,并且索引定义的格式必须为 CouchDB 索引的 JSON 格式。

需要以下三条信息来定义一个索引:

  • fields: 这些是常用的查询字段
  • name: 索引名
  • type: 它的内容一般是 json

例如,这是一个对字段 foo 的一个名为 foo-index 的简单索引。

{
    "index": {
        "fields": ["foo"]
    },
    "name" : "foo-index",
    "type" : "json"
}

可选地,设计文档( design document )属性 ddoc 可以写在索引的定义中。design document 是 CouchDB 结构,用于包含索引。索引可以以组的形式定义在设计文档中以提升效率,但是 CouchDB 建议每一个设计文档包含一个索引。

小技巧

当定义一个索引的时候,最好将 ddoc 属性和值包含在索引内。包含这个 属性以确保在你需要的时候升级索引,这是很重要的。它还使你能够明确指定 要在查询上使用的索引。

这里有另外一个使用 Marbles 示例定义索引的例子,在索引 indexOwner 使用了多个字段 docTypeowner 并且包含了 ddoc 属性:

{
  "index":{
      "fields":["docType","owner"] // Names of the fields to be queried
  },
  "ddoc":"indexOwnerDoc", // (optional) Name of the design document in which the index will be created.
  "name":"indexOwner",
  "type":"json"
}

在上边的例子中,如果设计文档 indexOwnerDoc 不存在,当索引部署的时候会自动创建 一个。一个索引可以根据字段列表中指定的一个或者多个属性构建,而且可以定义任何属性的 组合。一个属性可以存在于同一个 docType 的多个索引中。在下边的例子中, index1 只包含 owner 属性, index2 包含 owner 和 color 属性, index3 包含 owner、 color 和 size 属性。另外,注意,根据 CouchDB 的建议,每一个索引的定义 都包含一个它们自己的 ddoc 值。

{
  "index":{
      "fields":["owner"] // Names of the fields to be queried
  },
  "ddoc":"index1Doc", // (optional) Name of the design document in which the index will be created.
  "name":"index1",
  "type":"json"
}

{
  "index":{
      "fields":["owner", "color"] // Names of the fields to be queried
  },
  "ddoc":"index2Doc", // (optional) Name of the design document in which the index will be created.
  "name":"index2",
  "type":"json"
}

{
  "index":{
      "fields":["owner", "color", "size"] // Names of the fields to be queried
  },
  "ddoc":"index3Doc", // (optional) Name of the design document in which the index will be created.
  "name":"index3",
  "type":"json"
}

一般来说,你为索引字段建模应该匹配将用于查询过滤和排序的字段。对于以 JSON 格式 构建索引的更多信息请参阅 CouchDB documentation

关于索引最后要说的是,Fabric 在数据库中为文档建立索引的时候使用一种成为 索引升温 (index warming) 的模式。 CouchDB 直到下一次查询的时候才会索引新的或者更新的 文档。Fabric 通过在每一个数据区块提交完之后请求索引更新的方式,来确保索引处于 ‘热 (warm)’ 状态。这就确保了查询速度快,因为在运行查询之前不用索引文档。这个过程保 持了索引的现状,并在每次新数据添加到状态数据的时候刷新。

将索引添加到合约文件夹

当你完成索引之后,你需要把它打包到你的链码中,以便于将它部署到合适的元数据文件夹。你可以使用 peer lifecycle chaincode 命令安装链码。JSON 索引文件必须放在链码目录的 META-INF/statedb/couchdb/indexes 路径下。

下边的 Marbles 示例 展示了如何将索引打包到链码中。

Marbles Chaincode Index Package

这个例子包含了一个名为 indexOwnerDoc 的索引:

{"index":{"fields":["docType","owner"]},"ddoc":"indexOwnerDoc", "name":"indexOwner","type":"json"}

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin92
Github: mengbin92
cnblogs: 恋水无意