【问题标题】:Mongoose - Search for text in three fields based on score or weightageMongoose - 根据分数或权重在三个字段中搜索文本
【发布时间】:2015-11-10 21:26:38
【问题描述】:

我在 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 的权重最高,description 的权重少一点比名称和body 的权重最小。当结果出来时,我想按分数/权重对结果进行排序。

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

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query


    【解决方案1】:

    只要您要搜索整个单词,"text index"search 确实可能是这里的最佳选择。

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

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

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

    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 运算符过滤,但不能过滤“逻辑”匹配)。如果合适的话,你可以使用单个单词和“精确”匹配。

    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 函数的优化。但是,您不能进一步排序或“限制”这样的结果。

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

    【讨论】:

    • @SharpCoder 您提出的每个问题都可以直接在内容中回答,其中提供了详细信息的链接(如关于“textScore”)。我建议您再次阅读回复,尝试一下并阅读链接。
    • 你提到了Assigning the weights is attached to the "index", so the definition is done once and cannot be changed。这个人,我只需要创建一个索引吗??
    • @SharpCoder 你只创建一次索引,除非你打算删除索引并重新定义它的内容。您确实应该阅读此内容,而不是在 cmets 中提出更多问题,甚至发布更多问题。这里有足够多的示例信息让您忙一阵子。
    • 我收到TypeError: Invalid sort value: {$meta: textScore } 错误。我正在使用 mongoDB 2.6 版。任何想法我可能会出错!
    • @SharpCoder 您需要按照示例和参考文档中的说明“引用”它们。
    猜你喜欢
    • 1970-01-01
    • 2017-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-03
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    相关资源
    最近更新 更多