具有相关性的Mongo聚合匹配多个字段

时间:2013-12-27 19:43:57

标签: mongodb mongoose

根据this其他问题,我正在尝试根据用户的搜索输入收集包含关键字的条目。这是针对客户的站点,架构设置如下:

{
    fid: Number, // unique id for client's internal purposes
    email: String,
    password: String, // hashed
    name: {
        first: String,
        last: String
    },
    group: {
        name: String,
        description: String,
        type: String
    },
    bio: {
        short: String,
        long: String
    }
}

这是我的疑问:

db.users.aggregate(
    [{
        $match: {
            $or: [
                {
                    'name.first': {
                        $regex: userInput,
                        $options: 'i'
                     }
                },
                {
                    'name.last': {
                        $regex: userInput,
                        $options: 'i'
                    }
                },
                {
                    'bio.short': {
                        $regex: userInput,
                        $options: 'i'
                    }
                },
                {
                    'bio.long': {
                        $regex: userInput,
                        $options: 'i'
                    }
                }
            ]
        },
        { $unwind: { '$name.first', '$name.last', '$bio.short', '$bio.long' } },
        {
            $match: {
                $or: [
                    {
                        'name.first': {
                            $regex: userInput,
                            $options: 'i'
                         }
                    },
                    {
                        'name.last': {
                            $regex: userInput,
                            $options: 'i'
                        }
                    },
                    {
                        'bio.short': {
                            $regex: userInput,
                            $options: 'i'
                        }
                    },
                    {
                        'bio.long': {
                            $regex: userInput,
                            $options: 'i'
                        }
                    }
                ]
            }
        },
        { $group: { _id: '$fid', hitCount: { $sum: 1 } } },
        { $sort: { hitCount: -1 } }
    }]
);

对于这种类型的查询,我不断收到意外的逗号或结束花括号。我似乎无法找到我做错的事情(我已将我的mongodb.conf详细记录为11)。我哪里出错了,我甚至走在正确的道路上?我想用除密码字段之外的所有信息返回每个条目(对象?),我该如何过滤掉它?

1 个答案:

答案 0 :(得分:2)

case-insensitive $regex使用多个$or子句并不是非常有效 - 特别是如果要搜索大量数据。 MongoDB(与2.4一样)无法有效地使用不区分大小写的正则表达式的索引(标准索引区分大小写),并且对于大字符串,匹配每个字段内的任何位置将是代价高昂的比较。 $or子句是独立执行的,因此理想情况下,您希望在每个字段上都有一个索引(以避免完整的集合扫描),并且不区分大小写的$regex比较仍然是一个完整的索引扫描。

针对此用例的一个更好的方法是使用MongoDB 2.4+中提供的text indexes。文本索引不区分大小写,包括language-based word stemming,可以包含多个文本字段,并始终按相关性排序顺序返回结果。您还可以adjust the relative weights查看已编制索引的字段。

值得注意的是stemming与使用正则表达式不同。如果你想匹配单词,词干可以帮助减少公共语言根(即“运行”匹配“运行”)。

如果您匹配名称,您可能需要基于相似性或字符转置的模糊匹配方法。有关匹配名称的几种方法的详细说明,请参阅Efficient Techniques for Fuzzy and Partial matching in mongoDB