Ho una pipeline di elaborazione dati con fasi ben definite e confini IO. Posso scegliere una lingua per soddisfare le esigenze di questo design. Inizia con InputObject . Alla fine di ogni fase, ci sono alcuni dati aggiuntivi derivati da alcuni o tutti i risultati dei passaggi precedenti e il InputObject . Cioè, StageN estende Stage e produce un ResultsObjN immutabile, che estende Result . Una volta completata la pipeline, l'output finale a cui sono interessato è un sottoinsieme di tutti i risultati di ogni passaggio:
InputObject
|
|
v
-----------
| Stage 1 | <-- Tunable Parameters
-----------
|
|
InputObject
ResultsObj1
|
|
v
-----------
| Stage 2 | <-- Tunable Parameters
-----------
|
|
InputObject
ResultsObj1
ResultsObj2
|
|
v
...
Attualmente sto modellando ogni fase come oggetto Stage . Spiegherò presto cosa intendo per parametri "sintonizzabili"
- Ogni
Stageha ogni parametro sintonizzabile come attributi esposti da getter e setter. - Ogni
Stageè costruita con le sue dipendenze di input. - Ogni
Stageha un metodo per calcolare il risultato in base ai parametri sintonizzabili
Ecco in quasi-UML:
--------------------------------------------------
| <<abstract>> |
| Stage |
|--------------------------------------------------|
|--------------------------------------------------|
| +computeResult() : Result |
--------------------------------------------------
Ad esempio, Stage3 calcola ResultObj3 utilizzando InputObject e i risultati di Stage2 . Ci sono 2 parametri che possono essere impostati per cambiare i risultati.
--------------------------------------------------
| Stage3 |
|--------------------------------------------------|
| -param1 : Int |
| -param2 : Float |
|--------------------------------------------------|
| +Stage3(raw : InputObject, corners : ResultObj2) |
| +get/setParam1() |
| +get/setParam2() |
| +computeResult() : ResultObj3 |
--------------------------------------------------
Vorrei riutilizzare questo modello di pipeline di elaborazione, con fasi diverse in quantità diverse con diverse dipendenze di input. I parametri sintonizzabili possono essere ottimizzati da un ottimizzatore automatico o da un umano che utilizza alcune UI. In entrambi i casi, seguono lo stesso processo di feedback. Qui è lo stadio di sintonizzazione 3:
ResultObj3 performStage(InputObject raw, ResultObj2 corners):
1. Stage processor = new Stage3(raw, corners)
2. ResultObj result = processor.computeResult()
3. while (notAcceptable(result)):
4. tuneParams(processor, result) // tune to "more acceptable" params
5. result = processor.computeResult()
6. return result
Ritengo che il processo di ottimizzazione debba essere eseguito per ogni fase da un esecutore di code, ma non sono ancora sicuro su come sistemare il crescente insieme di risultati tipizzati in modo diverso o i diversi requisiti di costruzione di ogni fase.
Esempio di pipeline
Il punto di questa pipeline è leggere un insieme di coordinate da un CSV (in String raw ) e passare la stringa attraverso una pipeline che analizzerà la stringa, raggrupperà i punti e traccerà i cluster. I dati del cluster e le immagini di trama vengono estratti dalla pipeline dopo l'esecuzione.
La stringa viene analizzata in una raccolta di oggetti Point nello stage "ExtractPoints" . Quella collezione è raggruppata / segmentata in un insieme di oggetti Cluster nello stage "ClusterPoints" . I dati Point e Cluster vengono utilizzati per tracciare visivamente i punti in un oggetto immagine Plot allo stage "PlotClusters" .
QueuedPipeline pipeline = new QueuedPipeline()
String raw = readFile("points.csv")
pipeline.setInput(raw)
// addStage() takes the name of the stage, the stage runner, and the names of the stages it needs results from
pipeline.addStage("ExtractPoints", new StageTuner(PointExtractor, ), [])
pipeline.addStage("ClusterPoints", new StageTuner(PointClusterer), ["ExtractPoints"])
pipeline.addStage("PlotClusters", new StageTuner(ClusterPlotter), ["ExtractPoints", "ClusterPoints"])
// tune and execute each stage with the StageTuners
PipelineResultList results = pipeline.run()
// pipeline is done, collect the interesting results
Result pointClusters = results.getResult("ClusterPoints")
Result clusterPlot = results.getResult("PlotClusters")
saveClusterFile(pointClusters)
saveCllusterPlotImage(clusterPlot)
- Le classi
PointExtractor,PointClusterereClusterPlotterereditano tutte daStage. - Ogni
StageTunerprende la classe diStageper mettere a punto e implementare il ciclo di feedback sopra. - Le variabili
pointClusterseclusterPlotssono diResulttipo
Problema
Ma il semplice passaggio di classi per la costruzione è un mal di testa in alcune lingue. Inoltre, non sono sicuro di come generare e impostare genericamente i parametri di ogni sottoclasse Stage a causa del diverso numero / tipo di parametri - forse ogni sottoclasse Stage ha bisogno di una sottoclasse StageRunner corrispondente. Infine, la fusione di Result di oggetti con il tipo di cui ho bisogno nelle ultime due funzioni sembra pericolosa. ... ma questi sono solo i sintomi del mio vero problema: tutto comincia a diventare complesso e confuso per quello che mi aspettavo fosse un problema semplice.
Sto definendo male i miei oggetti e comportamenti? O non è così semplice come pensavo? Qualcos'altro interamente?