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

Sha*_*der 2 mongoose mongodb node.js 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: ''
  }
    }
});
Run Code Online (Sandbox Code Playgroud)

我需要在多个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);
    });
Run Code Online (Sandbox Code Playgroud)

问题:我需要想出一些机制,将权重/分数分配给权重最高的所有字段 ( Name,Description,Body),namedescription重比名称少一点,权重body最小。当结果出来时,我想按分数/权重对结果进行排序。

到目前为止,我已经研究了这个链接权重,但不确定获得所需结果的最佳方法是什么。我还想了解,我是否需要在每次搜索时都创建权重或它是一次性活动以及如何使用 Mongoose 实现权重?

Bla*_*ven 5

一个“文本索引”搜索确实有可能在这里是最好的选择,只要你正在寻找完整的单词。

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

BookSchema.index(
    {
         "name": "text",
         "description": "text",
         "body": "text"
    },
    {
        "weights": {
            "name": 5,
            "description": 2
        }
    }
)
Run Code Online (Sandbox Code Playgroud)

这允许您通过“设置”字段的权重来执行简单的搜索:

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

    }
);
Run Code Online (Sandbox Code Playgroud)

每个匹配的术语将被考虑与它被发现的领域相比,该领域给出了最大的权重和出现次数。

分配权重附加到“索引”,因此定义完成一次,不能更改。另一个限制是“文本搜索”不查看“部分”单词。例如,“ci”与“City”或“Citizen”不匹配,对于这种情况,您需要一个正则表达式。

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

然而,聚合框架无法对您的术语执行“正则表达式”的“逻辑”匹配操作(它可以通过$match运算符过滤,但不能过滤“逻辑”匹配)。如果适合,您可以使用单个单词和“精确”匹配。

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) {

    }
)
Run Code Online (Sandbox Code Playgroud)

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

MapReduce 共享一个类似的原则,您可以在作为前导元素发出的主键的一部分中包含计算出的“分数”。MapReduce 自然地对这个键发出的所有输入进行排序,作为馈送到 reduce 函数的优化。但是,您不能进一步排序或“限制”这样的结果。

这些通常是您查看并决定最适合您的情况的选项。