Монго настраиваемая мультиключевая сортировка - PullRequest
2 голосов
/ 22 марта 2012

Mongo Docs Состояние:

Функция нескольких ключей Mongo может автоматически индексировать массивы значений.

Это хорошо. Но как насчет сортировки по мультиключам? В частности, как отсортировать коллекцию по проценту совпадений с массивом ?

Например, у меня есть шаблон [ 'fruit', 'citrus' ] и коллекция, которая выглядит следующим образом:

{
    title: 'Apples',
    tags: [ 'fruit' ]
},

{
    title: 'Oranges',
    tags: [ 'fruit', 'citrus' ]
},

{
    title: 'Potato',
    tags: [ 'vegetable' ]
}

Теперь я хочу отсортировать коллекцию в соответствии с процентом совпадения каждой записи в шаблоне тегов. Апельсины должны стоять первыми, яблоки - вторыми, картошка - последними.

Какой самый эффективный и простой способ сделать это?

Ответы [ 2 ]

4 голосов
/ 26 марта 2012

Начиная с MongoDB 2.1, аналогичные вычисления могут выполняться с использованием структуры агрегации. Синтаксис что-то вроде

db.fruits.aggregate(
     {$match : {tags : {$in : ["fruit", "citrus"]}}}, 
     {$unwind : "$tags"}, 
     {$group : {_id : "$title", numTagMatches : {$sum : 1}}}, 
     {$sort : {numTagMatches : -1}} )

, который возвращает

 {
   "_id" : "Oranges",
   "numTagMatches" : 2
 },
 {
   "_id" : "Apples",
   "numTagMatches" : 1
 }

Это должно быть намного быстрее, чем метод уменьшения карты по двум причинам. Во-первых, потому что реализация является родным C ++, а не javascript. Во-вторых, потому что «$ match» отфильтрует элементы, которые не совпадают вообще (если это не то, что вы хотите, вы можете пропустить часть «$ match» и изменить часть «$ sum» на 1 или 0 в зависимости от того, равен ли тег «фрукты» или «цитрусовые» или нет).

Единственное предостережение: монго 2.1 пока не рекомендуется для производства. Если вы работаете в производстве, вам нужно подождать 2.2. Но если вы просто экспериментируете самостоятельно, вы можете поиграть с 2.1, поскольку структура агрегации должна быть более производительной.

2 голосов
/ 23 марта 2012

Примечание : Следующее объяснение требуется для Mongo 2.0 и более ранних версий.Для более поздних версий вы должны рассмотреть новую структуру агрегации.

Мы делаем нечто подобное, пытаясь найти нечеткое совпадение с входным предложением, которое мы индексируем.Вы можете использовать карту уменьшает, чтобы испускать идентификатор объекта каждый раз, когда вы получаете совпадение, и они суммируют их.Затем вам нужно будет загрузить результаты в ваш клиент и отсортировать сначала по наибольшему значению.

db.plants.mapReduce(
    function () {
        var matches = 0;
        for (var i = 0; i < targetTerms.length; i++) {
            var term = targetTerms[i];
            for (var j = 0; j < this.tags.length; j++) {
                matches += Number(term === this.tags[j]);
            }   
        }   
        emit(this._id, matches);
    },  

    function (prev, curr) {
        var result = 0;
        for (var i = 0; i < curr.length; i++) {
            result += curr[i];
        }   
        return result;
    },  

    {   
        out: { inline: 1 },

        scope: {
            targetTerms: [ 'fruit', 'oranges' ],
        }   
    }   
);

Вы должны передать свои входные значения ['fruit', 'citrus' ], используя параметр scope в карте, уменьшить вызов до {targetTerms: ['fruit', 'citrus' ]}, чтобы они были доступны в функции карты выше.

...