这个问题几乎归结为这个“分面搜索,多个多值字段,按重量排序而非计数”。
我有大约10M个事件,每个事件都有多个版本,每个版本都由标签描述。有5种标签类型(地点,发言人,参与者,主题,行业)。
{
title: "CES",
editions: [
{
date: "2013-02-01",
tags: [ {label: "Eric Schmidt", type: "speaker", "popularity": 50}, {label: "Paris", type: "place", "popularity": 30} ]
},
{
date: "2012-01-23",
tags: [ ... ]
}
]
}
现在,想象一下包含4个部分的左手菜单:
Places
------------
Paris
London
New York
[more]
Speakers
----------
Google
Facebook
Marc Zuckerberg
[more]
等等。
每当用户点击标签时,我希望菜单反映结果并允许他进一步向下钻取(分面搜索)。扭曲的是,当决定在每个部分的前三个标签中显示“Google”vs“Eric Schmidt”vs“Foursquare”时,我想确保根据[匹配事件的数量]显示最流行的标签更高] * [标签流行度]。这意味着,如果“Foursquare”有3个匹配事件,而“Eric Schmidt”只有一个匹配事件,它应首先显示Foursquare,得分为3 * 50 = 150,而Schmidt为1 * 100。
另外,理想情况下,如果我选择“Google”,那么对于“发言人”部分,系统不应该返回Google以外的发言人,即使匹配的事件也列出了“Zuckerberg”,其中人气极高,为200。因此,返回的标签应位于每个部分中当前选择的“下方”,并且它们的排序应基于上述评分逻辑。
{
event: "CES",
date: "2013-02-01",
tags: [ {label: "Eric Schmidt", type: "speaker", "popularity": 50, path: ",Tech Companies,Google,"}, {label: "Paris", type: "place", "popularity": 30, path: ",Europe,France,"} ]
},
{
event: "CES",
date: "2012-01-23",
tags: [ ... ]
}
* 每个标记类型一个查询(每个请求5个查询)*
db.events.aggregate(
{
'$match': {'tags.label': {'$all': ["selected tag 1", "selected tag2", ...]}}
},
{
'$unwind': '$tags'
},
// group by events, so we can later sum each tag's popularity only once per event, not per event edition
{
'$group': {
'_id': '$event',
'taglistUnqiue': {
'$addToSet': {
'label': '$tags.label',
'type': '$tags.type',
'popularity': '$tags.popularity'
}
}
}
},
{
'$unwind': '$taglist'
},
{
'$match': {
'taglist.type': "speaker",
/* haven't tested this path-matching, but it should work
to only get the tags that are in the bottom tree
of the current selected speaker tag */
'taglist.path': /^,selected speaker tag,/,
}
},
{
'$group': {
'_id': '$taglist.label',
'score': {
'$sum': '$taglist.popularity'
}
}
});
好的,这应该在算法上有效,但是在性能方面,它肯定不适用于50M事件版本,每个版本都有数千个可能的标签。
有人能想到另一种方法吗?除了使用“Map / Reduce”之外,这种方法是否可以以任何方式进行优化,我理解这种方法对于每个用户来说都是无法动态执行的?
答案 0 :(得分:0)
取决于您的搜索需要“实时”的方式,您是否考虑过使用增量map / reduce?
http://docs.mongodb.org/manual/tutorial/perform-incremental-map-reduce/