【问题标题】:Finding most commonly used word in a string field throughout a collection在整个集合中的字符串字段中查找最常用的单词
【发布时间】:2016-08-03 17:45:55
【问题描述】:

假设我有一个类似于以下的 Mongo 集合:

[
  { "foo": "bar baz boo" },
  { "foo": "bar baz" },
  { "foo": "boo baz" }
]

是否可以确定在foo 字段中最常出现的单词(最好是计数)?

例如,我喜欢这样的结果集:

[
  { "baz" : 3 },
  { "boo" : 2 },
  { "bar" : 2 }
]

【问题讨论】:

    标签: string mongodb mapreduce aggregation-framework mongodb-aggregation


    【解决方案1】:

    最近关闭了一个 JIRA issue $split 运算符,用于聚合框架的 $project 阶段。
    有了它,您可以创建这样的管道

    db.yourColl.aggregate([
        {
            $project: {
                words: { $split: ["$foo", " "] }
            }
        },
        {
            $unwind: {
                path: "$words"
            }
        },
        {
            $group: {
                _id: "$words",
                count: { $sum: 1 }
            }
        }
    ])
    

    结果应该是这样的

    /* 1 */
    {
        "_id" : "baz",
        "count" : 3.0
    }
    
    /* 2 */
    {
        "_id" : "boo",
        "count" : 2.0
    }
    
    /* 3 */
    {
        "_id" : "bar",
        "count" : 2.0
    }
    

    【讨论】:

    • 这看起来真的很完美,谢谢。我会尽快对其进行测试,如果它按预期工作,请点击接受按钮。
    • @DAXaholic 我该如何处理同样的问题,但它是包含其他分隔符(如逗号)的文章?谢谢
    【解决方案2】:

    在 MongoDB 3.4 中使用$split 运算符将字符串拆分为子字符串数组的最佳方法是here 提到的,因为我们需要$unwind 数组在管道中向下,我们需要使用$facet 运算符在子管道中执行此操作以获得最大效率。

    db.collection.aggregate([
        { "$facet": { 
            "results": [ 
                { "$project": { 
                    "values": { "$split": [ "$foo", " " ] }
                }}, 
                { "$unwind": "$values" }, 
                { "$group": { 
                    "_id": "$values", 
                    "count": { "$sum": 1 } 
                }} 
            ]
        }}
    ])
    

    产生:

    {
        "results" : [
            {
                "_id" : "boo",
                "count" : 2
           },
           {
                "_id" : "baz",
                "count" : 3
           },
           {
                "_id" : "bar",
                "count" : 2
           }
       ]
    }
    

    从 MongoDB 3.2 开始,唯一的方法是使用mapReduce

    var reduceFunction = function(key, value) { 
        var results = {}; 
        for ( var items of Array.concat(value)) { 
            for (var item of items) {
                results[item] = results[item] ? results[item] + 1 : 1;
            } 
        }; 
        return results; 
    }
    
    db.collection.mapReduce(
        function() { emit(null, this.foo.split(" ")); }, 
        reduceFunction, 
        { "out": { "inline": 1 } } 
    )
    

    返回:

    {
        "results" : [
            {
                "_id" : null,
                "value" : {
                    "bar" : 2,
                    "baz" : 3,
                    "boo" : 2
                }
            }
        ],
        "timeMillis" : 30,
        "counts" : {
            "input" : 3,
            "emit" : 3,
            "reduce" : 1,
            "output" : 1
        },
        "ok" : 1
    }
    

    如果您的 MongoDB 版本不支持 for...of 语句,您应该考虑在 reduce 函数中使用 .forEach() 方法。

    【讨论】:

      猜你喜欢
      • 2014-12-14
      • 2011-09-27
      • 2011-05-08
      • 1970-01-01
      • 2011-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多