在MongoDB Collection中查找与RegEx数组匹配

时间:2014-10-17 18:17:22

标签: regex performance mongodb aggregation-framework

说我有这些字段的集合:

{
    "category" : "ONE",
    "data": [
        {
            "regex": "/^[0-9]{2}$/",
            "type" : "TYPE1"
        },
        {
            "regex": "/^[a-z]{3}$/",
            "type" : "TYPE2"
        }
        // etc
    ]
}

所以我的输入是“abc”所以我想获得相应的类型(或最佳匹配,尽管最初我假设RegExes是独占的)。有没有可能通过良好的性能实现这一目标? (这将排除迭代RegEx数组的每个项目)

请注意,如果可能,可以重新安排架构,因为该项目仍处于设计阶段。所以我们会欢迎替代品。

每个类别可以有大约100 - 150个RegExes。我计划有大约300个类别。 但我知道这些类型是相互排斥的。

一个类别的真实世界示例:

type1=^34[0-9]{4}$, 
type2=^54[0-9]{4}$, 
type3=^39[0-9]{4}$, 
type4=^1[5-9]{2}$, 
type5=^2[4-9]{2,3}$

2 个答案:

答案 0 :(得分:2)

描述RegEx( Divide et Impera )将极大地帮助限制需要处理的文档数量。

这方面的一些想法:

  • RegEx接受长度(固定,最小,最大)
  • POSIX样式字符类[:alpha:][:digit:][:alnum:]等。)
  • 树状文档结构(umm)

实现上述每一项都会增加Insertion的复杂性(代码和/或手动输入),以及在查询之前描述searchterm的一些开销。

在一个类别中拥有互斥类型可以简化事情,但类别之间又如何呢?

  

300个类别@ 100-150 RegExps / category => 30k至45k RegExps

......如果不是大多数,有些肯定会完全重复。

在这种方法中,我将尝试最小化以颠倒样式存储/查询的文档总数与初始提议的“模式”。 注意:此演示中仅包含字符串长度以缩小,这可能会自然而然地用于手动输入,因为它可以加强对RegEx的视觉检查

考虑使用Documents重新合并regexes Collection,如下所示:

{
   "max_length": NumberLong(2),
   "min_length": NumberLong(2),
   "regex": "^[0-9][2]$",
   "types": [
     "ONE/TYPE1",
     "NINE/TYPE6"
  ]
},
{
   "max_length": NumberLong(4),
   "min_length": NumberLong(3),
   "regex": "^2[4-9][2,3]$",
   "types": [
     "ONE/TYPE5",
     "TWO/TYPE2",
     "SIX/TYPE8"
  ]
},
{
   "max_length": NumberLong(6),
   "min_length": NumberLong(6),
   "regex": "^39[0-9][4]$",
   "types": [
     "ONE/TYPE3",
     "SIX/TYPE2"
  ]
},
{
   "max_length": NumberLong(3),
   "min_length": NumberLong(3),
   "regex": "^[a-z][3]$",
   "types": [
     "ONE/TYPE2"
  ]
} 

..每个唯一的RegEx作为它自己的文档,具有它所属的类别(可扩展到每个类别的多个类型)

演示聚合代码:

function () {

   match=null;
   query='abc';

   db.regexes.aggregate(
    {$match: {
        max_length: {$gte: query.length},
        min_length: {$lte: query.length},
        types: /^ONE\//
        }
    },
    {$project: {
        regex: 1, 
        types: 1, 
        _id:0
        }
    }
   ).result.some(function(re){ 
       if (query.match(new RegExp(re.regex))) return match=re.types;
   });
   return match;
}

返回'abc'查询:

[
   "ONE/TYPE2"
] 

这将只针对这两个文件:

{
   "regex": "^2[4-9][2,3]$",
   "types": [
     "ONE/TYPE5",
     "TWO/TYPE2",
     "SIX/TYPE8"
  ]
},
 {
   "regex": "^[a-z][3]$",
   "types": [
     "ONE/TYPE2"
  ]
} 

缩小了3的长度并且具有类别ONE

可以通过实现POSIX描述符进一步缩小范围(易于针对searchterm进行测试,但必须在数据库中输入2个RegExps)

答案 1 :(得分:0)

广度优先搜索。 如果您的输入以字母开头,您可以丢弃类型1,如果它还包含一个数字,您可以丢弃独占(仅限数字或仅字母)类别,如果它还包含符号,则只保留少数包含所有类型的类型三。然后按照上述建议了解其余类别。从某种意义上说,为选定数量的正则表达式类型设置输入类型和用例的案例。搜索到正确的。

或者您可以根据输入创建正则表达式模型,并将其与作为字符串存在的正则表达式模型列表进行比较以获取类型。这样你就不得不花费资源分析输入来为它构建正则表达式。