在整个集合的字符串字段中查找最常用的词
Finding most commonly used word in a string field throughout a collection
假设我有一个类似于以下内容的 Mongo 集合:
[
{ "foo": "bar baz boo" },
{ "foo": "bar baz" },
{ "foo": "boo baz" }
]
是否可以确定哪些词在 foo
字段中出现的频率最高(最好使用计数)?
例如,我喜欢这样的结果集:
[
{ "baz" : 3 },
{ "boo" : 2 },
{ "bar" : 2 }
]
最近关闭了一个 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
}
在 MongoDB 3.4 中使用 $split
operator to split your string into an array of substring as mentioned here and because we need to $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 } }
)
哪个returns:
{
"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()
方法声明。
假设我有一个类似于以下内容的 Mongo 集合:
[
{ "foo": "bar baz boo" },
{ "foo": "bar baz" },
{ "foo": "boo baz" }
]
是否可以确定哪些词在 foo
字段中出现的频率最高(最好使用计数)?
例如,我喜欢这样的结果集:
[
{ "baz" : 3 },
{ "boo" : 2 },
{ "bar" : 2 }
]
最近关闭了一个 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
}
在 MongoDB 3.4 中使用 $split
operator to split your string into an array of substring as mentioned here and because we need to $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 } }
)
哪个returns:
{
"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()
方法声明。