3

couchdbビューから個別の値をフィルタリングするためのヘルプを使用できます。コンピューターに関する情報を含むログを格納するデータベースがあります。コンピューターの新しいログが定期的にデータベースに書き込まれます。

少し単純化して、次のようなエントリを保存します。

{
   "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はログファイルのリスト全体を反復処理する必要があるため(かなり長くなる可能性があるため)、これは最善の解決策ではないという強い気持ちがあります。

削減機能が必要だと思いますが、問題に適応できる例や説明を実際に見つけることができませんでした。

したがって、私が探しているのは(純粋なcouchdb)ビューであり、特定のデバイスの最新のログのみを吐き出します。

4

1 に答える 1

6

これが私がすることです。これは境界的なCouchDBの悪用ですが、私は多くの成功を収めています。

通常、reduce合計、カウント、またはそのようなものを計算します。ただし、reduceはエリミネーショントーナメントと考えてください。多くの値が入ります。1つだけが出てきます。削減!何度も繰り返すと、最終的な勝者が得られます(再削減)。この場合、最新のタイムスタンプを持つログが勝者です。

もちろん、ウェルター級はヘビー級と戦うことはできません。リーグと体重別階級が必要です。特定のドキュメントが他の特定の同様のドキュメントと戦うことは意味があります。これは、reducegroupパラメーターが行うこととまったく同じです。それは、均等にマッチした剣闘士だけが私たちのブラッドスポーツのスチールケージに入ることを確実にします。(コーヒーが入っています。)

まず、デバイスによってキー設定されたすべてのログを発行します。放出されたのvalueは単に文書のコピーです。

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

次に、指定されたすべての値の最新のタイムスタンプを返すreduce関数を記述します。異なるリーグの2人の剣闘士(異なるシステムの2つのログ)間の戦いを見つけたら、戦いを止めてください!何かがうまくいかなかった(誰かが正しい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、CouchDBkeyは、マシン名である同じ値の値のみを削減(勝者を見つける)します。

(配列をキーとして発行することもできます。これにより、柔軟性が少し向上します。emit([doc.name, doc.timestamp], doc)代わりに、のようなクエリを使用してシステムごとにすべてのログを表示したり、。を使用?reduce=false&startkey=["NAS", null]&endkey=["NAS", {}]してシステムごとに最新のログを表示したりできます?group_level=1

最後に、「戦いを止める」ものはオプションです。常に最新のタイムスタンプを持つドキュメントを返すことができます。ただし、同様の状況で、マップリデュースが正しくないかどうかを確認したいので、そこに保持することを好みます。ヌルリデュース出力が私の大きな手がかりです。

于 2011-03-06T05:01:46.937 に答える