我在mongodb中收集了一个名为users的集合。它看起来像这样:
db.users.find() =>
{
{
_id: 1,
products: [1, 2, 3, 4, 5]
},
{
_id: 2,
products: [4, 5, 6, 7, 8]
},
{
_id: 3,
products: [10, 11, 12]
}
}
产品数组包含用户购买的产品ID。我想做一些查询/ mapreduce /东西来为每个用户获得“推荐产品”,如下所示:
// result = some kind of query/mapreduce/... on the users collection
print(result) =>
[
{ key: 1, values: [6, 7, 8]},
{ key: 2, values: [1, 2, 3]}
]
我的逻辑是这样的: 用户1购买了产品4和5.对于用户2也是如此。因此,用户1购买的其他产品(1,2,3)对用户2来说是一个很好的推荐。
产品(6,7,8)对于用户2是一个很好的推荐。没有其他用户购买过用户3购买的产品,因此没有针对用户3的推荐。
我怎么能这样做?有没有人可以给我看一个例子?
答案 0 :(得分:1)
您将永远无法在单个操作中演示所有用户的完整结果。纯粹的原因是mapReduce或聚合框架实际上并没有那样工作,因为你无法以这种方式比较文档。
但是您可以基于每个用户执行此操作,或者如果您希望这些结果位于另一个集合中,那么您需要对每个用户进行迭代才能进行比较。
我最喜欢的方法是使用聚合框架,并且速度最快。但它需要MongoDB 2.6或更高版本才能工作:
var compare = [1, 2, 3, 4, 5];
db.colection.aggregate([
// Get intersections and differences to the current user purchases
{ "$project": {
"matched": {
"$setIntersection": [
"$products",
compare
]
},
"matchedSize": { "$size": {
"$setIntersection": [
"$products",
compare
]
}},
"difference": {
"$setDifference": [
"$products",
compare
]
},
"differenceSize": { "$size": {
"$setDifference": [
"$products",
compare
]
}}
}},
// Filter where there are no differences or no intersection on the same
// products purchased
{ "$match": {
"matchedSize": {"$gt": 0 },
"differenceSize": { "$gt": 0 }
}},
// Unwind the differences array
{ "$unwind": "$difference" },
// Combine all the other results to a single set
{ "$group": {
"_id": null,
"recommend": { "$addToSet": "$difference" }
}}
])
所以它很好并且不言自明。这在早期版本中是可能的,但这个过程非常复杂。
或者你可以用mapReduce做到这一点,但是你需要定义一些函数;
首先是一个映射器:
var mapper = function () {
function intersection(a, b) {
var result = new Array();
while( a.length > 0 && b.length > 0 ) {
if (a[0] < b[0] ) { a.shift(); }
else if (a[0] > b[0] ) { b.shift(); }
else /* they're equal */
{
result.push(a.shift());
b.shift();
}
}
return result;
}
function difference(a, b) {
return a.filter(function(x) { return b.indexOf(x) < 0 });
}
var result = {
intersect: intersection( this.products, compare ),
diff: difference( this.products, compare )
};
if ( result.intersect.length > 0 && result.diff.length > 0 )
emit( null, result.diff );
};
然后是减速器:
var reducer = function (key,values) {
var reduced = [];
values.forEach(function(value) {
value.forEach(function(el) {
if ( reduced.indexOf(el) < 0 )
reduced.push(el);
});
});
return { value: reduced };
};
还有一个终结函数:
var finalize = function (key,value) {
if ( value.hasOwnProperty('value') )
value = value.value;
return value;
};
并调用mapReduce:
db.purchase.mapReduce(
mapper,
reduce,
{
"scope": { "compare": [ 1, 2, 3, 4, 5 ] },
"finalize": finalize,
"out": { "inline": 1 }
}
)
因此,有一些方法,一旦您获得给定用户的产品列表,您就可以获得比较推荐的项目。为每个用户单独执行此操作,或者在适合您需要的地方迭代并存储该批次。