【问题标题】:Mongodb find best matchMongodb找到最佳匹配
【发布时间】:2013-04-08 16:35:35
【问题描述】:

我想构建一个查询,返回数据库中最匹配的文档。

即我想查找包含以下字段的文档 - “动物”:“狗” “颜色”:“棕色” “图案”:“点” “大小”:“小”

如果没有包含上述所有字段及其对应值的文档,我希望查询返回最佳匹配。 f.e {“动物”:“狗”,“颜色”:“棕色”,“尺寸”:“小”}

我可以在 mongo db 中实现递归查询吗?如果是这样,怎么做? 我应该使用 mapReduce,如果是,如何使用? 人们可以将此问题更多地视为推荐系统问题,我想推荐最适合给定值的项目(文档),如果有人知道实现上述方法的好方法,我将不胜感激

我正在使用 mongodb mongoose 和 nodejs。

谢谢。

【问题讨论】:

  • 只是一个想法——您也许可以使用聚合框架来匹配字段,并为匹配的数量保留一个计数(分数),然后对其进行排序 (docs.mongodb.org/manual/tutorial/aggregation-examples) . (而且,不,你不能在本地进行“递归查询”)。

标签: node.js mongodb mongoose recommendation-engine


【解决方案1】:

我不确定递归查询的性能影响,但这样的事情应该可以工作。它会从查询中删除最后一个属性,如果没有找到匹配项,则会重试:

var AnimalSchema = new mongoose.Schema({
    atype: { type: String },
    color: {type:String},
    pattern: {type:String},
    size : {type:String}
});

var Animal = mongoose.model('Animal',AnimalSchema);

//test data
//var dalmation = new Animal({
//    atype:'dog',
//    color: 'black and white',
//    pattern: 'spots',
//    size: 'big'
//});

//dalmation.save(function(err){
//    var yorkie = new Animal({
//        atype:'dog',
//        color:'brown',
//        pattern:'mixed',
//        size:'small'
//    });
//    yorkie.save(function(yer){
//         bestMatch({'atype':'dog','size':'big','color':'brown'},function(err,animal){
//             console.log(err,animal);
//         })
//    });
//});

function bestMatch(params,cb){
    Animal.findOne(params,function(err,animal){
        if (err || !animal){
           var keys = Object.keys(params);
           if (keys.length){
               delete params[keys.pop()];
               bestMatch(params,cb);
           }else{
               cb('No matches',null);
           }
        }else{
            cb(null,animal);
        }
    });
}

bestMatch({'atype':'dog','size':'big','color':'brown'},function(err,animal){
    console.log(err,animal);
});

【讨论】:

  • 我希望看到使用聚合框架的答案。很高兴看到一个!
【解决方案2】:

鉴于您似乎只是在搜索文本字段,一种可能性是在 MongoDB 2.4 中使用新的(目前是“实验性的”)text search feature。这允许您在一个或多个字段上创建全文索引,包括 field weighting 以确保相关性。

例如:

db.collection.ensureIndex(
    // Fields to index
    {
        animal:  "text",
        color:   "text",
        pattern: "text",
        size:    "text"
    },

    // Options
    {
        name: "best_match_index",

        // Adjust field weights (default is 1)
        weights: {
            animal: 5,  // Most relevant search field
            size:   4   // Also relevant
       }
    }
)

Results 将根据相关字段权重按照与评分相关的顺序返回。

请注意,搜索关键字也是stemmed,因此如果您期望完全匹配,这可能会产生一些意想不到的结果。您可以将您的术语放在双引号中,以利用phrase matching 进行更具体的匹配。

【讨论】:

  • 我已经尝试了您的建议,但出现“索引过多”错误
  • @Liatz:你有多少索引(db.collection.getIndexes().length)?此错误表明您在集合上的索引过多或尝试创建多个文本索引(2.4 仅允许每个集合一个文本索引)。
  • 哪个版本支持多索引? (我需要在同一个集合中使用 4-5 个索引和权重)
  • 您可以有多个常规索引,但在 MongoDB 2.4 中,全文索引目前仅限于每个集合一个(该功能仍被视为“测试版”)。您使用的是哪个版本的 MongoDB?
  • @Liatz:文本搜索功能仅适用于 MongoDB 2.4,目前仅限于单个 text 索引(但您可以有多个非文本索引)。所写的示例将为每个字段使用不同的权重,这可以满足您所追求的相关性。如果您收到“索引过多”错误,这表明您要么尝试创建多个文本搜索索引,要么已达到每个集合 64 个索引的限制(这似乎不太可能)。如果您尝试在同一个集合上创建 4-5 个 text 索引,则尚不支持。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 2020-11-04
相关资源
最近更新 更多