从mongo检索数据花费的时间太长,即使对于小数据集也是如此。对于更大的数据集,我们会得到javascript引擎的内存不足错误。我们尝试了几种模式设计和几种检索数据的方法。如何优化mongodb/mapreduce函数/mongowire以更快地检索更多数据?
我们对MongoDB还不是很有经验,因此不确定我们是否遗漏了优化步骤,或者只是使用了错误的工具。
1。背景
为了绘图和回放,我们希望随着时间的推移存储多个对象的更改。目前我们每个项目有几十个对象,但我们需要存储数千个对象。对象可能每秒更改一次,也可能长时间不更改。delphi后端通过mongowire和superobjects对mongodb进行写入和读取,数据显示在web前端。
2。模式设计
我们将对象的变化存储在每小时记录中的分钟秒毫秒对象中。模式设计如所述。样品:
O:目标1,
日期:$日期,
v:{0:{0:{0:{speed:8,rate:0.8}},1:{0:{0:{speed:9}},…}
我们把索引放在{dt: -1, o: 1}和{o:1}上。
三。检索数据
我们使用mapreduce基于分钟秒毫秒对象构造一个新日期,并将该对象放回v:
O:目标1,
日期:$日期,
v:{速度:8,速率:0.8}
在mapreduce函数之前,文档的平均大小约为525kb,并且已经更新了约29000次。对这样一个文档进行mapreduce后,结果约为746kb。
3.1使用MapReduce通过Mongo Shell检索数据
我们使用以下映射函数:
function mapF(){
for (var i = 0; i < 3600; i++){
var imin = Math.floor(i / 60);
var isec = (i % 60);
var min = ''+imin;
var sec = ''+isec;
if (this.v.hasOwnProperty(min) && this.v[min].hasOwnProperty(sec)) {
for (var ms in this.v[min][sec]) {
if (imin !== 0 && isec !== 0 && ms !== '0' && this.v[min][sec].hasOwnProperty(ms)) {// is our keyframe
var currentV = this.v[min][sec][ms];
//newT is new date computed by the min, sec, ms above
if (toDate > newT && newT > fromDate) {
if (fields && fields.length > 0) {
for (var p = 0, length = fields.length; p < length; p++){
//check if field is present and put it in newV
}
if (newV) {
emit(this.o, {vs: [{o: this.o, dt: newT, v: newV}]});
}
} else {
emit(this.o, {vs: [{o: this.o, dt: newT, v: currentV}]});
}
}
}
}
}
}
};
db.collection.mapReduce( mapF,reduceF,
{out: {inline: 1},
query: {o: {$in: objectNames]}, dt: {$gte: keyframeFromDate, $lt: keyframeToDate}},
sort: {dt: 1},
scope: {toDate: toDateWithinKeyframe, fromDate: fromDateWithinKeyframe, fields: []},
jsMode: true});
o和dt使用键模式吗?FMongoWire.Get('$cmd',BSON([
'mapreduce', ‘collection’,
'map', bsonJavaScriptCodePrefix + FMapVCRFunction.Text,
'reduce', bsonJavaScriptCodePrefix + FReduceVCRFunction.Text,
'out', BSON(['inline', 1]),
'query', mapquery,
'sort', BSON(['dt', -1]),
'scope', scope
]));
最佳答案
哎呀,真是个问题!首先:我不是MongoDB的专家。我写tmongowire是为了了解一点mongodb。另外,我真的(真的)不喜欢包装器有过多的重载来做相同的事情,但是对于所有类型的特定类型。很久以前程序员没有泛型,但我们有变体。所以我基于变体构建了一个mongodb包装器(和ibsondocument)。这就是说,我显然做了一些人们喜欢用的东西,通过保持它的简单性能相当好。(我最近没有花太多时间在这上面,但最重要的是迎合了版本3以来的新身份验证方案。)
现在,关于你的具体设置。你说你用mapreduce从500kb到700kb?我认为有迹象表明你在工作中使用了错误的工具。我不确定默认的mongo shell与您在TMongoWire.Get上执行相同操作时有什么不同,但是如果我假设mapreduce在通过连线发送响应之前首先组装响应,那么性能就会下降。
所以我的建议是:考虑使用tmongowirequery是对的。它提供了一种快速处理数据的方法,因为服务器会将数据流化,但还有更多。
我强烈建议使用数组来存储秒列表。即使不是所有秒都有数据,也要在没有数据的秒上存储null,这样每分钟数组就有60个项。这就是为什么:
在设计tmongowirequery时出现的一个细节是,假设您一次处理一个(bson)文档,并且文档的内容大致相似,至少在值名上是这样。因此,通过在枚举响应时使用同一个ibsondocument实例,您实际上不必取消分配和重新分配所有这些变量,从而节省了大量时间。
这适用于简单的文档,但实际上在数组上也很好。这就是我创建ibsondocumentenumerator的原因。您需要在预期的文档数组位置预先加载带有ibsondocumentenumerator的ibsondocument实例,并且您需要以与tmongowirequery大致相同的方式处理该数组:使用相同的ibsondocument实例枚举它,因此当后续的documeNT具有相同的密钥,不必重新分配密钥就节省了时间。
不过,在您的情况下,您仍然需要通过连线拉取整个小时的数据,以便选择所需的秒数。正如我之前所说,我不是MongoDB专家,但我怀疑有更好的方法来存储这样的数据。或者每秒使用一个单独的文档(我想这会让索引做更多的工作,MongoDB可以采用这个插入率),或者使用一个特定的查询构造,以便MongoDB知道如何将秒数组缩短为您请求的数据(这就是$splice所做的吗?)
下面是一个如何在{name:"fruit",items:[{name:"apple"},{name:"pear"}]}这样的文档上使用ibsondocumentenumerator的示例。
q:=TMongoWireQuery.Create(db);
try
q.Query('test',BSON([]));
e:=BSONEnum;
d:=BSON(['items',e]);
d1:=BSON;
while q.Next(d) do
begin
i:=0;
while e.Next(d1) do
begin
Memo1.Lines.Add(d['name']+'#'+IntToStr(i)+d1['name']);
inc(i);
end;
end;
finally
q.Free;
end;
关于performance - 我们如何改进MongoDB MapReduce函数,该函数需要很长时间才能检索数据并导致内存不足错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30774069/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为