2

Mongo 文档状态:

Mongo 多键功能可以自动索引值数组。

那很好。但是基于多键的排序呢?更具体地说,如何根据数组匹配百分比对集合进行排序

例如,我有一个模式[ 'fruit', 'citrus' ]和一个集合,如下所示:

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

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

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

现在,我想根据每个条目与标签模式的匹配百分比对集合进行排序。橙子必须先来,苹果第二,土豆最后。

最有效和最简单的方法是什么?

4

2 回答 2

4

从 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
 }

这应该比 map-reduce 方法快得多,原因有两个。首先是因为实现是本机 C++ 而不是 javascript。其次,因为 "$match" 将过滤掉根本不匹配的项目(如果这不是你想要的,你可以省略 "$match" 部分,并将 "$sum" 部分更改为1 或 0 取决于标签是否等于“水果”或“柑橘”或两者都不是)。

这里唯一需要注意的是,mongo 2.1 还不推荐用于生产。如果您在生产中运行,则需要等待 2.2。但是,如果您只是自己进行试验,则可以使用 2.1,因为聚合框架应该更高效。

于 2012-03-26T15:29:34.087 回答
2

注意:Mongo 2.0 及更早版本需要以下说明。对于更高版本,您应该考虑新的聚合框架。

我们在尝试模糊匹配我们索引的输入句子时做了类似的事情。每次获得匹配项时,您都可以使用 map reduce 发出对象 ID,并将它们相加。然后,您需要将结果加载到您的客户端并首先按最高值排序。

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' ],
        }   
    }   
);

您可以使用map reduce 调用中['fruit', 'citrus' ]的参数传递输入值,以便它们在上面的 map 函数中可用。scope{targetTerms: ['fruit', 'citrus' ]}

于 2012-03-23T17:47:34.813 回答