2016-08-25 54 views
2

mongoose(和/或mongodb)中是否有函数/方法可用于基于相关性对查询结果进行排序(匹配查询参数的最大数量)?按相关性排序的性能问题

下面的示例是我目前使用的(查询使用$in:[],否则相同) - 我的集合非常小,因此性能很好,但对于较大的集合,它会显着减慢速度。

或者,如果有更好的执行方法(猫鼬/ mongodb之外),我很乐意了解它。

例子:

var docs = [ 
    { 
     fruits: ['apple', 'orange', 'tomato'], 
     colors: ['blue', 'green'], 
     // relevance: 3 
    }, 
    { 
     fruits: ['apple', 'carrot'], 
     colors: ['red', 'green'], 
     // relevance: 2 
    } 
] 

var query = {fruits: ['apple', 'orange'], colors: ['green']} 

docs.forEach(function(doc){ 
    var relevance = 0 
    Object.keys(query).forEach(function(_query){ 
     var arrays = [doc[_query], query[_query]] 
     var result = arrays.shift().filter(function(v) { 
      return arrays.every(function(a) { 
       return a.indexOf(v) !== -1; 
      }); 
     }); 
     relevance += result.length 
    }) 
    doc.relevance = relevance 
}) 

结果:

var docs = [ 
    { 
     fruits: ['apple', 'orange', 'tomato'], 
     colors: ['blue', 'green'], 
     relevance: 3 
    }, 
    { 
     fruits: ['apple', 'carrot'], 
     colors: ['red', 'green'], 
     relevance: 2 
    } 
] 
+0

你能还添加预期的输出? – Shrabanee

+0

在总是包含两个项目的数组上使用'array.shift()'和'arrays.every'几乎没有意义。 – Bergi

+0

@Bergi在查询中可以使用十几个数组,可以使用'.shift()'和'.every()'来覆盖动态构建的查询。 – brod

回答

0

你可以用聚集做到这一点:

db.getCollection('docs').aggregate([ 
 
{$match: {fruits: {$in: ['apple', 'orange']}, colors: {$in: ['green']}}}, 
 
{$project: { 
 
    relevance: { 
 
     $sum: [ 
 
      {$cond: {if: { "$setIsSubset": [['orange'], "$fruits" ]}, then: 1, else: 0}}, 
 
      {$cond: {if: { "$setIsSubset": [['apple'], "$fruits" ]}, then: 1, else: 0}}, 
 
      {$cond: {if: { "$setIsSubset": [['green'], "$colors" ]}, then: 1, else: 0}}] 
 
    }, 
 
    doc: '$$ROOT'}} 
 
])

结果:

/* 1 */ 
 
{ 
 
    "_id" : ObjectId("57be8a9b65d2835e960df543"), 
 
    "relevance" : 3, 
 
    "doc" : { 
 
     "_id" : ObjectId("57be8a9b65d2835e960df543"), 
 
     "fruits" : [ 
 
      "apple", 
 
      "orange", 
 
      "tomato" 
 
     ], 
 
     "colors" : [ 
 
      "blue", 
 
      "green" 
 
     ] 
 
    } 
 
} 
 

 
/* 2 */ 
 
{ 
 
    "_id" : ObjectId("57be8aa865d2835e960df544"), 
 
    "relevance" : 2, 
 
    "doc" : { 
 
     "_id" : ObjectId("57be8aa865d2835e960df544"), 
 
     "fruits" : [ 
 
      "apple", 
 
      "carrot" 
 
     ], 
 
     "colors" : [ 
 
      "red", 
 
      "green" 
 
     ] 
 
    } 
 
}