Mongoose - 根据分数或权重在三个字段中搜索文本

时间:2015-08-18 05:12:21

标签: node.js mongodb mongoose mongodb-query

我在MongoDB上使用Mongoose。这就是我的模型的样子。

var BookSchema = new Schema({
  name: String,
  viewCount: { type: Number, default: 0 },
  description: {
    type: String,
    default: 'No description'
  },
  body: {
    type: String,
    default: ''
  }
    }
});

我需要在Name, Description, Body个字段上搜索一些文字。到目前为止,这就是我正在做的事情。它的工作:

Book.find().or([{ 'name': { $regex: term, $options: "$i" }}, { 'description': { $regex: term, $options: "$i" }}, { 'body': { $regex: term, $options: "$i" }}]).exec(
    function (err, topics) {
      if (err) {
        return handleError(res, err);
      }
      return res.status(200).json(books);
    });

问题:我需要提出一些机制,我将权重/得分分配给所有字段(Name,Description,Body),name具有最高权重{{1}权重比名称少,description权重最小。当结果出现时,我想按分数/重量对结果进行排序。

到目前为止,我已经研究过link& weights,但不确定获得所需结果的最佳方法是什么。我也想了解,我是否需要在每次搜索时创建权重,或者一次性活动&如何用Mongoose实现权重?

1 个答案:

答案 0 :(得分:3)

只要您正在搜索整个单词,"text index"search确实是最佳选择。

在架构定义中添加文本索引非常简单:

BookSchema.index(
    {
         "name": "text",
         "description": "text",
         "body": "text"
    },
    {
        "weights": {
            "name": 5,
            "description": 2
        }
    }
)

这允许您使用" set"执行简单搜索。加权到田野:

Book.find({ "$text": { "$search": "Holiday School Year" } })
    .select({ "score": { "$meta": "textScore" } })
    .sort({ "score": { "$meta": "textScore" } })
    .exec(function(err,result) {

    }
);

如果每个匹配的术语都会被认为是与该领域相关的,那么它就会给出最大的权重和出现次数。

分配权重附加到"索引",因此定义只执行一次,无法更改。另一个限制是在"文本搜索"不看"部分"话。例如" ci"不匹配" City"或者" Citizen",对于这样的事情,你需要一个正则表达式。

如果您需要更多的灵活性,或者通常必须能够动态更改结果的权重,那么您需要像聚合框架或mapReduce这样的东西。

然而,聚合框架无法执行"logical" match操作(它可以通过$match运算符进行过滤,但不能过滤"正则表达式"逻辑"匹配) #34;根据你的条款。你可以使用单个单词和" exact"但如果这适合,请匹配。

Book.aggregate(
    [
        { "$match": {
            "$or": [
                { "name": /Holiday/ },
                { "description": /Holiday/ },
                { "body": /Holiday/ }
            ]
        }},
        { "$project": {
            "name": 1,
            "description": 1,
            "body": 1,
            "score": {
                "$add": [
                    { "$cond": [{ "$eq": [ "$name", "Holiday" ] },5,0 ] },
                    { "$cond": [{ "$eq": [ "$description", "Holiday" ] },2,0 ] },
                    { "$cond": [{ "$eq": [ "$body", "Holiday" ] },1,0 ] }
                ]
            }
        }},
        { "$sort": { "score": -1 } }
    ],
    function(err,results) {

    }
)

由于聚合管道使用数据结构来查询您可以将每个执行的权重参数更改为您目前需要的任何内容。

MapReduce有一个类似的原则,你可以在其中包含一个计算的"得分"在作为主要元素发出的主键的一部分中。 MapReduce自然地将此键发出的所有输入排序为优化,以便为reduce函数提供信号。但是你不能进一步排序或限制"这样的结果。

通常您可以选择查看并确定哪种最适合您的情况。