Sobes.tech
Senior

Les mises à jour des documents arrivent au service message Document { string Url = 1; // URL du document, son identifiant unique uint64 PubDate = 2; // heure de publication déclarée du document uint64 FetchTime = 3; // heure de réception de cette mise à jour du document, peut être considérée comme un identifiant de version. La paire (Url, FetchTime) est unique. string Text = 4; // texte du document uint64 FirstFetchTime = 5; // initialement absent, doit être rempli } Les documents peuvent arriver dans n'importe quel ordre (pas dans l'ordre de leur mise à jour), et il peut également y avoir des messages en double. Il est nécessaire de former en sortie des messages identiques, mais avec des champs corrigés selon les règles suivantes (tout ce qui est indiqué ci-dessous concerne un groupe de documents avec le même champ Url): Le champ Text et FetchTime doivent être ceux du document avec le plus grand FetchTime reçu jusqu'à présent. Le champ PubDate doit être celui du message avec le plus petit FetchTime. Le champ FirstFetchTime doit être égal à la valeur minimale de FetchTime. Autrement dit, à chaque instant, nous prenons PubDate et FirstFetchTime du premier version reçu jusqu'à présent (si on les trie par FetchTime), et Text de la dernière. L'interface dans le code peut être implémentée ainsi: type Processor interface { Process(doc *Document) (*Document, error) } Ce code fonctionnera dans un service qui lit des messages d'une file (Kafka ou similaire), et écrit également le résultat dans la file. Si Process retourne Null, rien n'est écrit dans la file.

sobes.tech IA

Réponse de l'IA

Для реализации интерфейса Processor в Go нужно хранить состояние по каждому Url, чтобы на каждый входящий документ обновлять агрегированное состояние и возвращать скорректированное сообщение.

Основная идея:

  • Для каждого Url хранить:
    • минимальный FetchTime (для PubDate и FirstFetchTime)
    • максимальный FetchTime (для Text и FetchTime)
    • PubDate, Text, FirstFetchTime, соответствующие этим минимальному и максимальному FetchTime

При получении нового документа:

  • Если для Url нет записи — создать с данными из документа
  • Иначе обновить минимальный и максимальный FetchTime и соответствующие поля при необходимости
  • Вернуть агрегированный документ с нужными полями

Пример реализации:

import (
    "errors"
    "sync"
)

type Document struct {
    Url            string
    PubDate        uint64
    FetchTime      uint64
    Text           string
    FirstFetchTime uint64
}

type Processor interface {
    Process(doc *Document) (*Document, error)
}

type docState struct {
    minFetchTime uint64
    maxFetchTime uint64
    pubDate      uint64
    text         string
    firstFetch   uint64
}

type processorImpl struct {
    mu    sync.Mutex
    state map[string]*docState
}

func NewProcessor() Processor {
    return &processorImpl{
        state: make(map[string]*docState),
    }
}

func (p *processorImpl) Process(doc *Document) (*Document, error) {
    if doc == nil {
        return nil, errors.New("input document is nil")
    }

    p.mu.Lock()
    defer p.mu.Unlock()

    st, ok := p.state[doc.Url]
    if !ok {
        // первый документ для данного Url
        p.state[doc.Url] = &docState{
            minFetchTime: doc.FetchTime,
            maxFetchTime: doc.FetchTime,
            pubDate:      doc.PubDate,
            text:         doc.Text,
            firstFetch:   doc.FetchTime,
        }
        return &Document{
            Url:            doc.Url,
            PubDate:        doc.PubDate,
            FetchTime:      doc.FetchTime,
            Text:           doc.Text,
            FirstFetchTime: doc.FetchTime,
        }, nil
    }

    updated := false

    // Обновляем минимальный FetchTime и PubDate, FirstFetchTime
    if doc.FetchTime < st.minFetchTime {
        st.minFetchTime = doc.FetchTime
        st.pubDate = doc.PubDate
        st.firstFetch = doc.FetchTime
        updated = true
    }

    // Обновляем максимальный FetchTime и Text
    if doc.FetchTime > st.maxFetchTime {
        st.maxFetchTime = doc.FetchTime
        st.text = doc.Text
        updated = true
    }

    // Если пришло сообщение с FetchTime, который уже есть, но текст или PubDate отличаются,
    // можно игнорировать, так как пара (Url, FetchTime) уникальна, либо обновлять по логике.

    if !updated {
        // Данные не изменились, можно вернуть nil, чтобы не писать в очередь
        return nil, nil
    }

    return &Document{
        Url:            doc.Url,
        PubDate:        st.pubDate,
        FetchTime:      st.maxFetchTime,
        Text:           st.text,
        FirstFetchTime: st.firstFetch,
    }, nil
}

Таким образом, сервис будет поддерживать актуальное агрегированное состояние для каждого Url и возвращать скорректированные документы согласно правилам.