使用优先顺序搜索数组顺序

时间:2017-08-14 23:48:04

标签: mongodb mongodb-query

我的直觉是答案是否定的,但是有可能在Mongodb中执行搜索,比较顺序很重要的数组的相似性吗?

E.g。 我有三个这样的文件

{'_id':1, "my_list": ["A",2,6,8,34,90]},
{'_id':2, "my_list": ["A","F",2,6,19,8,90,55]},
{'_id':3, "my_list": [90,34,8,6,3,"A"]}

1和2是最相似的,3是完全不同的,不管它包含与1相同的所有值。

理想情况下,我会进行类似于{"my_list" : ["A",2,6,8,34,90] }的搜索,结果将是文档1和2。

它几乎就像使用外卡的正则表达式搜索一样。我知道我可以很容易地在python中做到这一点,但速度很重要,而且我处理的是130万份文档。

1 个答案:

答案 0 :(得分:0)

任何“比较”或“选择”实际上或多或少都与所应用的实际逻辑相关。但作为一般原则,您始终可以考虑来自阵列的匹配索引的产品以及文档中存在的数组。例如:

var sample = ["A",2,6,8,34,90];

db.getCollection('source').aggregate([
  { "$match": { "my_list": { "$in": sample } } },
  { "$addFields": {
    "score": {
      "$add": [
        { "$cond": {
          "if": {
            "$eq": [
              { "$size": { "$setIntersection": [ "$my_list", sample ] }},
              { "$size": { "$literal": sample } }
            ]   
          },
          "then": 100,
          "else": 0 
        }},
        { "$sum": {
          "$map": {
            "input": "$my_list",
            "as": "ml",
            "in": {
              "$multiply": [
                { "$indexOfArray": [
                  { "$reverseArray": "$my_list" },
                  "$$ml" 
                ]},
                { "$indexOfArray": [
                  { "$reverseArray": { "$literal": sample } },
                  "$$ml"
                ]}
              ]
            }
          }  
        }}
      ]
    }  
  }},
  { "$sort": { "score": -1 } }
])

将按顺序返回文档:

/* 1 */
{
    "_id" : 1.0,
    "my_list" : [ "A", 2, 6, 8, 34, 90],
    "score" : 155.0
}

/* 2 */
{
    "_id" : 2.0,
    "my_list" : ["A", "F", 2, 6, 19, 8, 90, 55],
    "score" : 62.0
}

/* 3 */
{
    "_id" : 3.0,
    "my_list" : [ 90, 34, 8, 6, 3, "A"],
    "score" : 15.0
}

关键是当使用$reverseArray应用时,来自$indexOfArray的值将是“匹配索引”从“从头到尾”(反向)产生的“更大”,这会产生更大的“重量“在数组开头匹配,而不是在结束时匹配。

当然你应该考虑像第二个文件确实包含“大多数”匹配的东西,并且有更多的数组条目会在初始匹配上放置比第一个文档中“更大”的权重。

从上面的"A"得分在第二个文档中比在第一个文档中得分更多,因为即使在第一个位置匹配"A",数组也会更长。然而,还有一些影响"F"是不匹配的,因此具有比它后来在阵列中更大的负面影响。同样适用于上一个文档中的"A",其中在数组末尾,匹配对总体权重几乎没有影响。

考虑到这个问题的方法是添加一些逻辑来考虑“完全匹配”的情况,例如这里与样本的$size和当前数组进行$setIntersection比较。这将调整分数,以确保匹配所有提供的元素的内容实际上得分高于位置匹配较少的文档,但总体上更多元素。

如果有“分数”,您可以过滤掉结果(即$limit)或您可以应用的任何其他逻辑,以便仅返回所需的实际结果。但第一步是计算一个“得分”来起作用。

因此,对于什么逻辑实际上意味着“最接近的匹配”一般都是主观的,但$reverseArray$indexOfArray操作通常是将“更多权重”放在上面的关键较早的索引匹配而不是最后一个。

总体而言,您正在寻找逻辑的“计算”。聚合框架具有一些可用的运算符,但实际应用的运算符取决于您的最终实现。我只是在一个数组比较中显示“逻辑上有效”的东西,但更重视“早期匹配”而不是“后一个匹配”,当然还有“最重要”,其中数组实际上是相同的。

  

注意:对于早期版本的MongoDB,使用includeArrayIndex base64_decode()选项可以实现类似的逻辑,而不使用上面使用的主要运算符。但是,该过程确实需要使用$unwind来解构数组,并且这可能会导致操作的效果无效。