需要更好的 JSON 模式来验证稀疏矩阵数据对象

Need better JSON Schema to validate sparse matrix data object

我需要验证 JavaScript 中的复杂对象。

对象基于字典:

var dict = {'1':true,'2':true,'3':true};

成对的对象存储矩阵(通常不完整):

var obj = {'1':{
        '1': 'str1',
        '2': 'str2',
        '3': 'str3',
    },'2':{
        '1': 'str1',
        '2': 'str2',
    }
};

我使用 AJV 验证器制作验证模式。

架构要求:

  1. 第一级对象仅包含字典中的属性。
  2. 二级对象仅包含字典中的属性。
  3. 数据是一个字符串

正在生成架构:

var dict = {'1':true,'2':true,'3':true};

var subProperties = R.map(function(item){
  return {
    'type' : 'string',
    "minLength": 1,
  }
}, dict);
var root = {
  "type" : "object",
  "additionalProperties" : false
};
root.properties = R.map(function(item){
  return {
    "type" : "object",
    'properties' : subProperties,
    "additionalProperties" : false
  };
}, dict);

console.log(root)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/4.9.0/ajv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

此模式运行良好,但问题在于性能。当字典包含 200 个元素时,编译此模式需要 10 秒(验证快,编译慢)。此外,它会不时抛出内存异常。是否可以做出更好的验证模式?

考虑到您正在验证 40000 个属性,内存异常在这里并不奇怪。您的验证函数代码大小应在 30Mb 左右。

您可以使用我添加到 v5/6 proposals and that is available in ajv-keywords 包中的 属性Names 关键字。

var dict = ['1', '2', '3'];
var schema = {
  type: 'object',
  propertyNames: { enum: dict },
  additionalProperties: {
    type: 'object',
    propertyNames: { enum: dict },
    additionalProperties: {
      type: 'string',
      minLength: 1
    }
  }
};

var ajv = require('ajv')();
require('ajv-keywords')(ajv, 'propertyNames');

var validate = ajv.compile(schema);

此架构很小,但功能相同。

您可以使用当前标准版本中存在的 patternProperties 关键字实现相同的效果(使用 es6 属性 语法):

var names = '^(1|2|3)$';
var schema = {
  type: 'object',
  additionalProperties: false,
  patternProperties: {
    [names]: {
      type: 'object',
      additionalProperties: false,
      patternProperties: {
        [names]: {
          type: 'string',
          minLength: 1
        }
      }
    }
  }
};

属性名称看起来更简单,我认为应该更快。

通过映射 items 结果不是 1 而是 N 模式(即,如果您有 200 个项目,将创建 200 个模式,其唯一目的是验证密钥) .

另一种方法是使用 patternProperties 和一个巨大的 200 键长 RegExp 或者更简单,只需手动验证对象。

var dict = {'1':true,'2':true,'3':true};

var monsterRegex = '^' + Object.keys(dict).join('|') + '$'

var valSchema = {
  type: 'string',
  minLength: 1
}
var keySchema = {
  type: 'object',
  additionalProperties: false,
  patternProperties: {}
}
keySchema.patternProperties[monsterRegex] = valSchema

var objSchema = {
  type: 'object',
  additionalProperties: false,
  patternProperties: {}
}
objSchema.patternProperties[monsterRegex] = keySchema

console.log(objSchema)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/4.9.0/ajv.min.js"></script>