CouchDB - фильтровать последний журнал для каждого зарегистрированного экземпляра из списка - PullRequest
3 голосов
/ 04 марта 2011

Я мог бы использовать некоторую помощь для фильтрации различных значений из представления 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 должен перебирать весь список файлов журналов (который может стать довольно длинным).

Полагаю, мне нужна функция приведения, но я не могу найти примеров. или объяснения, которые я мог бы приспособить к своей проблеме.

Итак, я ищу представление (pure couchdb), которое выдает только последний журнал для данного устройства.

1 Ответ

6 голосов
/ 06 марта 2011

Вот что я делаю.Это пограничное злоупотребление CouchDB, однако я добился большого успеха.

Обычно reduce вычисляет сумму, или число, или что-то в этом роде.Тем не менее, думать о снижении как отборочном турниреМногие ценности входят. Только одно выходит.Сокращение!Повторяйте снова и снова, и вы получите окончательного победителя (повторное сокращение).В этом случае победителем становится журнал с последней отметкой времени.

Конечно, полусредние не могут бороться с тяжеловесами.Должны быть лиги и весовые категории.Имеет смысл только для определенных документов сражаться с некоторыми другими подобными документами.Это именно то, что будет делать параметр Reduce group .Это обеспечит попадание в стальную клетку нашего кровавого спортсмена только одинаково подобранного гладиатора.(Кофе начинает работать.)

Сначала выведите все журналы, набранные устройством.Выдаваемый value является просто копией документа.

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

Затем напишите функцию сокращения, которая возвращает последнюю отметку времени всех заданных значений.Если вы видите бой двух гладиаторов из разных лиг (два бревна из разных систем), остановите бой!Что-то пошло не так (кто-то запросил без правильного 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.

Наконец, «остановить бой» не является обязательным. Вы всегда можете просто вернуть документ с последней отметкой времени. Однако я предпочитаю сохранять его там, потому что в подобных ситуациях я хочу посмотреть, являюсь ли я картой- неправильное уменьшение, и нулевой вывод - моя большая подсказка.

...