Sobes.tech
Senior

Кагаздардын жаңыртуулары кызматка келет message Document { string Url = 1; // Кагаздын URL, анын уникалдуу идентификатору uint64 PubDate = 2; // жарыяланган убакыт uint64 FetchTime = 3; // бул кагаздын жаңыртуусун алуу убактысы, версия идентификатору катары каралышы мүмкүн. Жуп (Url, FetchTime) уникалдуу. string Text = 4; // кагаздын тексті uint64 FirstFetchTime = 5; // башында жок, толтурулушу керек } Кагаздар каалаган тартипте келип калышы мүмкүн (жаңыртуулар жасалган тартипте эмес), жана дублдик билдирүүлөр болушу мүмкүн. Чыгышта, ошол эле билдирүүлөрдү түзүү керек, бирок төмөнкү эрежелер боюнча оңдолгон талаалар менен (төмөндө көрсөтүлгөндөр, Url талаасы менен бирдей топтогон документтер үчүн): Text жана FetchTime талаалары, азыркыга чейин алынган эң чоң FetchTime менен бирдей болушу керек. PubDate талаасы, эң кичинекей FetchTime менен бирдей болушу керек. FirstFetchTime талаасы, эң кичинекей FetchTime маанисине барабар болушу керек. Башкача айтканда, ар бир учурда FetchTime боюнча сорттолгон биринчи версиядан PubDate жана FirstFetchTime, жана акыркы версиядан Text алынады. Коддогу интерфейс мындайча ишке ашырылышы мүмкүн: type Processor interface { Process(doc *Document) (*Document, error) } Бул код Kafka же окшош кезекчеден билдирүүлөрдү окуган жана натыйжаны дагы кезекке жазган кызматта иштейт. Эгер Process Null кайтарса, эч нерсе кезекке жазылбайт.

sobes.tech AI

AIден жооп

Для реализации интерфейса 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 и возвращать скорректированные документы согласно правилам.