MongoDB:通过索引加速聚合操作,还是寻找其他解决方案?

3

好的,MongoDB专家,请看一下我的集合:

[{
  "_id" : "item_0",
  "Name" : "Item 0",
  "Description" : "Some description for this item...",
  "Properties" : {
    "a" : 5.0,
    "b" : 0.0,
    "c" : 6.0,
    "d" : 6.0,
    "e" : 2.0,
    "f" : 0.0,
    "g" : 9.0,
    "h" : 3.0,
    "i" : 4.0,
    "j" : 5.0
  }
},
{ // 5.000-10.000 more items... }
]

我正在使用这个聚合函数来对一组选定的属性(在本例中为a、b、c和d)进行乘法运算,然后按它们的乘积进行排序。
{
    "aggregate": "item",
    "pipeline": [
        {
            "$project": {
                "_id": 1,
                "Name": 1,
                "s": {
                    "$multiply": [
                        "$Properties.a",
                        "$Properties.b",
                        "$Properties.c",
                        "$Properties.d"
                    ]
                }
            }
        },
        {
            "$sort": {
                "s": -1
            }
        },
        {
            "$limit": 100
        }
    ]
}

现在这个方法还算有效,但是当条目和属性数量增加时,执行聚合的时间会大大增加!有更好(更高效)的方法来实现类似的功能吗?查找最高产品(一组属性的倍数)必须快速。如果有一种方法可以对此进行索引,并具有所有不同属性组合,并将它们缓存或其他方式?索引需要一些时间也没关系,只要查询快速即可!感谢您的帮助,我非常感激!
1个回答

4
考虑到您对更快速搜索和高效性的要求,我认为更好的方法是使用Map/Reduce与输出集合(至少在聚合框架支持使用集合作为输出之前)。
特别地,使用输出集合有几个优点:
- 您可以具有灵活的索引和排序 - 结果不必实时计算每个查询 - 您不受16Mb BSON文档大小内联结果的限制
您可以使用Map/Reduce的merge 输出选项来更新输出集合中的计算结果(本质上,这将是您的缓存)。
根据各种属性更新的频率,我建议基于“上次更新”时间戳或其他允许您确定何时需要重新计算值的标准进行增量式处理。这将使您在集合增长时保持批处理大小更易管理。

正如Sammaye所提到的,有一个开放的功能请求,要求聚合框架支持一个$out选项,以将结果保存到输出集合中。请参阅MongoDB问题跟踪器中的SERVER-2353来投票支持该功能或关注更新。 - Stennie
这个想法是,每当用户进行搜索时,他都会像上面的示例一样选择几个属性 - 它们可以随时更改(如果用户搜索其他内容)。属性的值不会改变。使用map/reduce仍然可能实现吗?我的意思是,这将要求我存储每个不同的选定属性组合的结果,对吗? - Mickel
嗯...如果你想从索引结果中进行选择,你就必须预先计算组合。这在M/R中是可能的,但组合的数量可能会很大,根据你的使用情况而定(例如,任意选择20个属性中的任意组合,或者总是选择5个属性的组合)。你的要求存在一个问题,那就是为了找到匹配项,服务器必须计算所有文档的属性,然后进行内存排序以找到前N个结果。由于你的目标是优化速度,我建议重新考虑你的架构,并思考是否有更好的方式来表示数据。 - Stennie
进一步思考您在上面评论中提供的更新用例信息...如果您的实际目标是具有20个属性的10,000个项目,则从RAM使用方面来看,这可能不是一个大型数据集。与其猜测它可能会很慢,不如进行一些使用测试。如果整个数据集适合内存,并且您必须迭代它才能获得结果,那么您很可能已经接近最优了。 - Stennie
是的,我必须在生产环境中进一步测试这个。我的笔记本电脑可以在大约170毫秒内搜索2000个文档,这实际上相当不错。我之所以首先问这个问题,是因为每次“选择”/查询属性更改时,在每个文档上执行乘法似乎有点不必要。我认为这个解决方案将与C#服务器端的一些缓存结合使用效果很好。感谢您的建议! - Mickel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接