CouchDB - 从列表中筛选每个记录实例的最新日志

时间:2011-03-04 18:55:18

标签: python couchdb mapreduce couchdbkit

我可以使用一些帮助从couchdb视图中过滤不同的值。 我有一个数据库,用于存储包含计算机信息的日志。 定期将计算机的新日志写入db。

有点简化我存储这样的条目:

{
   "name": "NAS",
   "os": "Linux",
   "timestamp": "2011-03-03T16:26:39Z",
}
{
   "name": "Server1",
   "os": "Windows",
   "timestamp": "2011-02-03T19:31:31Z",
}
{
   "name": "NAS",
   "os": "Linux",
   "timestamp": "2011-02-03T18:21:29Z",
}

到目前为止,我正在努力通过不同的条目过滤此列表。 我想收到的是每个设备的最新日志文件。

我有这样的观点:

function(doc) {
    emit([doc.timestamp,doc.name], doc);
}

我用python(couchdbkit)查询这个视图,到目前为止我提出的最佳解决方案看起来像这样:

def get_latest_logs(cls):
    unique = []
    for log in cls.view("logs/timestamp", descending=True):
        if log.name not in unique_names:
            unique.append(log)
    return unique

好的......这很有效。但我有强烈的感觉,这不是最好的解决方案,因为python需要迭代整个日志文件列表(可能会变得很长)。

我想我需要一个reduce功能,但我找不到任何例子  或解释我可以适应我的问题。

所以,我正在寻找的是一个(纯粹的couchdb)视图,它只会吐出给定设备的最新日志。

1 个答案:

答案 0 :(得分:6)

这是我的工作。这是边缘CouchDB滥用,但我已经取得了很大的成功。

通常,reduce会计算总和,或计数等。但是,将reduce视为淘汰赛。许多价值观都在流传。只有一个值出现。减少!一遍又一遍地重复,你有最终的赢家(重新减少)。在这种情况下,具有最新时间戳的日志是赢家。

当然,welterweights无法对抗重量级人物。必须有联赛和重量级。只有某些文档与某些其他类似文档进行战斗才有意义。这正是reduce 参数的作用。它将确保只有均匀匹配的角斗士进入我们的血液运动中的钢笼。 (咖啡正在踢。)

首先,发出设备键入的所有日志。发出的value只是文档的副本。

function(doc) {
    emit(doc.name, doc);
}

接下来,编写reduce函数以返回所有给定值的最新时间戳。如果你看到来自不同联赛的两个角斗士之间的斗争(来自不同系统的两个日志),请停止战斗!出了点问题(有人在没有正确的group值的情况下查询。)

function(keys, vals, re) {
    var challenger, winner = null;
    for(var a = 0; a < vals.length; a++) {
        challenger = vals[a];
        if(!winner) {
            // The title is unchallenged. This value is the winner.
            winner = challenger;
        } else {
            // Fight!
            if(winner.name !== challenger.name) {
                // Stop the fight! He's gonna kill him!
                return null; // With a grouping query, this will never happen.
            } else if(winner.timestamp > challenger.timestamp) {
                // The champ wins! (Nothing to do.)
            } else {
                // The challenger wins!
                winner = challenger;
            }
        }
    }

    // Today's champion lives to fight another day.
    return winner;
}

(注意,时间戳比较可能是错误的。您可能需要转换为Date。)

现在,当您使用?group=true查询视图时,CouchDB只会使用相同的key(您的计算机名称)减少(找到之间的赢家)值。

(您也可以将数组作为键发出,这样可以提供更多的灵活性。您可以emit([doc.name, doc.timestamp], doc)代替。所以您可以通过系统查看所有日志,例如?reduce=false&startkey=["NAS", null]&endkey=["NAS", {}]或者您可以按系统查看?group_level=1的最新日志。

最后,“停止战斗”的东西是可选的。您可以随时返回带有最新时间戳的文档。但是,我更喜欢将它保留在那里,因为在类似的情况下,我想看看我是否正确地减少了地图,并且null减少输出是我的大线索。