2016-08-25 5 views
2

Есть ли функция/метод в mongoose (и или mongodb), которая может использоваться для сортировки результатов запросов на основе релевантности (наибольшее количество подходящих параметров запроса)?Сортировка по релевантности проблем с производительностью

Пример ниже - это то, что я использую в данный момент (запрос использует $in:[], в противном случае то же самое) - моя коллекция довольно маленькая, поэтому производительность прекрасна, но в больших коллекциях она резко замедляет работу.

В качестве альтернативы, если есть более эффективный метод (за пределами mongoose/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

Использование 'arrays.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" 
 
     ] 
 
    } 
 
}

Смежные вопросы