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

Dan*_*Dan 9 regex performance mongodb aggregation-framework

假设我有这些字段的集合:

{
    "category" : "ONE",
    "data": [
        {
            "regex": "/^[0-9]{2}$/",
            "type" : "TYPE1"
        },
        {
            "regex": "/^[a-z]{3}$/",
            "type" : "TYPE2"
        }
        // etc
    ]
}
Run Code Online (Sandbox Code Playgroud)

所以我的输入是"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}$
Run Code Online (Sandbox Code Playgroud)

CSᵠ*_*CSᵠ 2

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

这个方向的一些想法:

  • 正则表达式接受长度(固定、最小、最大)
  • POSIX风格字符类[:alpha:][:digit:][:alnum:]等)
  • 树状文档结构(umm)

实现其中每一个都会增加插入的复杂性(代码和/或手动输入),并且还会增加在searchterm查询之前描述的一些开销。

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

300 个类别 @ 100-150 个正则表达式/类别 => 30k 到 45k 个正则表达式

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

在这种方法中,我将尝试最大限度地减少要以相反的方式存储/查询的文档总数,而不是您最初提出的“架构”。
注意:此演示中仅包含字符串长度以进行缩小,这对于手动输入来说可能很自然,因为它可以加强对正则表达式的视觉检查

考虑regexes用文档重写集合,如下所示:

{
   "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"
  ]
} 
Run Code Online (Sandbox Code Playgroud)

..每个唯一的正则表达式都是它自己的文档,具有它所属的类别(每个类别可扩展为多种类型)

演示聚合代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

返回'abc'查询:

[
   "ONE/TYPE2"
] 
Run Code Online (Sandbox Code Playgroud)

这将仅针对这两个文档运行:

{
   "regex": "^2[4-9][2,3]$",
   "types": [
     "ONE/TYPE5",
     "TWO/TYPE2",
     "SIX/TYPE8"
  ]
},
 {
   "regex": "^[a-z][3]$",
   "types": [
     "ONE/TYPE2"
  ]
} 
Run Code Online (Sandbox Code Playgroud)

通过长度3和类别缩小ONE

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