我有一个数据库(couchDB),其中包含大约90,000个文档。这些文件非常简单:
{
"_id": "1894496e-1c9e-4b40-9ba6-65ffeaca2ccf",
"_rev": "1-2d978d19-3651-4af9-a8d5-b70759655e6a",
"productName": "Cola"
}
现在我希望有一天能够将此数据库与移动设备同步。显然,90k的文档不应该同时使用手机。这就是我编写过滤函数的原因。这些应该按“productName”过滤。首先在Jlang中稍后在Erlang中获得性能。这些Filter函数在JavaScript中如下所示:
{
"_id": "_design/local_filters",
"_rev": "11-57abe842a82c9835d63597be2b05117d",
"filters": {
"by_fanta": "function(doc, req){ if(doc.productName == 'Fanta'){ return doc;}}",
"by_wasser": "function(doc, req){if(doc.productName == 'Wasser'){ return doc;}}",
"by_sprite": "function(doc, req){if(doc.productName == 'Sprite'){ return doc;}}"
}
}
在Erlang中像这样:
{
"_id": "_design/erlang_filter",
"_rev": "74-f537ec4b6508cee1995baacfddffa6d4",
"language": "erlang",
"filters": {
"by_fanta": "fun({Doc}, {Req}) -> case proplists:get_value(<<\"productName\">>, Doc) of <<\"Fanta\">> -> true; _ -> false end end.",
"by_wasser": "fun({Doc}, {Req}) -> case proplists:get_value(<<\"productName\">>, Doc) of <<\"Wasser\">> -> true; _ -> false end end.",
"by_sprite": "fun({Doc}, {Req}) -> case proplists:get_value(<<\"productName\">>, Doc) of <<\"Sprite\">> -> true; _ -> false end end."
}
}
为了简单起见,还没有查询,只有“硬编码”字符串。过滤器都可以工作。问题是它们是减缓的方法。我稍后在Perl中用Java编写了一个测试程序来测试过滤文档所需的时间。这是我的一个Perl脚本:
$dt = DBIx::Class::TimeStamp->get_timestamp();
$content = get("http://127.0.0.1:5984/mobile_product_test/_changes?filter=local_filters/by_sprite");
$dy = DBIx::Class::TimeStamp->get_timestamp() - $dt;
$dm = $dy->minutes();
$dz = $dy->seconds();
@contArr = split("\n", $content);
$arraysz = @contArr;
$arraysz = $arraysz - 3;
$\="\n";
print($dm.':'.$dz.' with '.$arraysz.' Elements (JavaScript)');
现在是悲伤的部分。这些是我得到的时间:
2:35 with 2 Elements (Erlang)
2:40 with 10000 Elements (Erlang)
2:38 with 30000 Elements (Erlang)
2:31 with 2 Elements (JavaScript)
2:40 with 10000 Elements (JavaScript)
2:51 with 30000 Elements (JavaScript)
顺便说一下这些是分钟:秒。数字是过滤器返回的元素数,数据库中包含90k个元素。令人惊讶的是,Erlang过滤器根本不是更快。
要求所有元素只需要9秒。并创建了关于15的视图。但我不能在手机上使用传输所有文件(数量和安全性原因)。
有没有办法过滤视图以提高性能? 或者我的erlang过滤器函数有问题(我对JavaScript过滤器的时间并不感到惊讶)。
编辑: 正如pgras所指出的,this问题的回答中提到了这个问题的原因。为了让erlang过滤器运行得更快,我需要在下面使用“层”并将erlang直接编程到数据库中,而不是作为_design文档。但我真的不知道从哪里开始以及如何做到这一点。任何提示都会有所帮助。
答案 0 :(得分:3)
自从我问这个问题以来已经有一段时间了。但我想我会回过头来分享我们最终要解决的问题。
所以简短的回答是过滤速度无法真正得到改善。
原因在于过滤器的工作方式。如果检查数据库更改。他们在这里:
http://<ip>:<port>/<databaseName>/_changes
此文档包含属于您的数据库的所有更改。如果您在数据库中执行任何操作,则只需添加新行。当现在想要使用过滤器时,过滤器将从json解析为指定的语言,并用于此文件中的每一行。据我所知,要清楚每个行的解析也是如此。这不是很有效,也无法改变。
所以我个人认为,对于大多数用例,过滤器要慢,不能使用。这意味着我们必须找到解决这个问题的方法。我并不暗示我有一个普遍的解决方案。我可以说,对我们来说,可以使用视图而不是过滤器。与过滤器相比,视图在内部生成树,并且与光一样快。简单过滤器也存储在设计文档中,可能如下所示:
{
"_id": "_design/all",
"language": "javascript",
"views": {
"fantaView": {
"map": "function(doc) { \n if (doc.productName == 'Fanta') \n emit(doc.locale, doc)\n} "
}
}
}
其中fantaView是视图的名称。我想这个功能是自我解释的。所以这就是我们所做的,如果他遇到类似的问题,我希望它可以帮助别人。
答案 1 :(得分:0)
我可能错了,但过滤器函数应返回布尔值,因此请尝试将其更改为:
function(doc, req){ return doc.productName === 'Fanta';}
它可以解决您的性能问题......
修改强>
Here解释为什么它很慢(至少使用JavaScript)......
一种解决方案是使用视图选择要同步的文档的ID,然后通过指定要同步的doc_ids来启动同步。
例如视图将是:
function(doc){
emit(doc.productName, doc._id)
}
您可以使用_design / docs / _view / by_producName调用该视图吗?key =“Fanta”
然后使用找到的doc ids启动复制...
答案 2 :(得分:0)
通常,couchDB过滤器很慢。其他人已经解释了为什么他们很慢。我发现使用过滤器的唯一合理方法是使用“自”。否则,在一个相当大的数据库(我有47k文档,它们是复杂的文档)中,过滤器不起作用。我们通过从dev迁移到prod [几百个文档到~47k docs]来学习这个方法。我们还将设计更改为查询视图,因为我们需要像行为一样的连续反馈,所以我们使用了Spring的@Scheduled