Feedback Consolidation Pattern
The aim of this recipe is to indicate how feedback consolidation can be applied at the message level. Feedbacks received from e.g. experts on a patient's condition can be published on a messaging channel and then checked by this recipe for consistency.
The messages are separated in two outputs, one for matching and one for contradicting opinions. In order for this to apply, the incoming message needs to have a set of fields to enable the comparison. Initially a model ID is useful in order to compare whether the same model is used for expert assistance. Then a set of IDs is included that indicates the patient, the specific test examination and the expert (e.g. doctor ID). The comparison is then made for messages that have the same patient and test ID. The ones that match are joined in one message and are compared with relation to the expert opinion. An indicative example appears.
{ "modelID": 4, "feedback": "ok", "testID": 1, "doctorID": 5, "patientID": 3 }
The condition of joining is the following:
msg.parts.id = msg.payload.imageID+msg.payload.patientID
[{"id":"fa5d8bc1d91e9134","type":"inject","z":"5d2d32acc5591747","name":"GOOD FEEDBACK","props":[{"p":"payload"},{"p":"routingKey","v":"activelearning.app1.model1","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"modelID\":4,\"feedback\":\"ok\",\"imageID\":1,\"doctorID\":5,\"patientID\":3}","payloadType":"json","x":170,"y":940,"wires":[["e6119a46b815c12e","0de11f879fda3761"]]},{"id":"aee36c513c25a05d","type":"function","z":"5d2d32acc5591747","name":"create parts","func":"msg.parts={};\nmsg.parts.id = msg.payload.imageID+msg.payload.patientID;\nmsg.parts.count=2;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":530,"y":1100,"wires":[["4469175c609b2986"]]},{"id":"4469175c609b2986","type":"join","z":"5d2d32acc5591747","name":"Join in One","mode":"auto","build":"array","property":"payload","propertyType":"msg","key":"comparisonField","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":750,"y":1100,"wires":[["c060845de5c1d46a","e4542c729bb3c791"]]},{"id":"c060845de5c1d46a","type":"debug","z":"5d2d32acc5591747","name":"debug 34","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":880,"y":1180,"wires":[]},{"id":"ec2d362d0bc3e89a","type":"inject","z":"5d2d32acc5591747","name":"BAD FEEDBACK","props":[{"p":"payload"},{"p":"routingKey","v":"activelearning.app1.model1","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"modelID\":4,\"feedback\":\"wrong\",\"imageID\":1,\"doctorID\":6,\"patientID\":2}","payloadType":"json","x":180,"y":980,"wires":[["e6119a46b815c12e"]]},{"id":"e4542c729bb3c791","type":"function","z":"5d2d32acc5591747","name":"compare feedbacks","func":"if ((msg.payload[0].feedback)==(msg.payload[1].feedback)) {\n return [msg,null];\n} else {\n return [null,msg];\n}\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":950,"y":1100,"wires":[["120b2d00836d1305"],["341745117b49659b"]]},{"id":"120b2d00836d1305","type":"debug","z":"5d2d32acc5591747","name":"NORMAL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1120,"y":1060,"wires":[]},{"id":"341745117b49659b","type":"debug","z":"5d2d32acc5591747","name":"ALERT","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1120,"y":1140,"wires":[]},{"id":"eb36a511c7513007","type":"comment","z":"5d2d32acc5591747","name":"Feedback Consolidation Pattern","info":"","x":190,"y":820,"wires":[]},{"id":"0de11f879fda3761","type":"debug","z":"5d2d32acc5591747","name":"debug 37","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":440,"y":880,"wires":[]},{"id":"bb12b82d05721bca","type":"amqp-in","z":"5d2d32acc5591747","name":"","broker":"8a0706320fa877e8","prefetch":0,"noAck":true,"exchangeName":"feedback","exchangeType":"topic","exchangeRoutingKey":"activelearning.app1.model1","exchangeDurable":true,"queueName":"feedback","queueExclusive":false,"queueDurable":true,"queueAutoDelete":false,"headers":"{}","x":210,"y":1100,"wires":[["aee36c513c25a05d"]]},{"id":"e6119a46b815c12e","type":"amqp-out","z":"5d2d32acc5591747","name":"","broker":"8a0706320fa877e8","exchangeName":"feedback","exchangeType":"topic","exchangeRoutingKey":"","exchangeRoutingKeyType":"str","exchangeDurable":true,"amqpProperties":"{ \"headers\": {} }","rpcTimeoutMilliseconds":3000,"outputs":0,"x":500,"y":940,"wires":[]},{"id":"66943fcd7a86b071","type":"comment","z":"5d2d32acc5591747","name":"Testing part","info":"","x":130,"y":900,"wires":[]},{"id":"fbfee0756d74b05a","type":"comment","z":"5d2d32acc5591747","name":"Main Implementation","info":"","x":150,"y":1200,"wires":[]},{"id":"8a0706320fa877e8","type":"amqp-broker","name":"humaine in","host":"10.100.59.183","port":"5672","vhost":"humaine","tls":false,"credsFromSettings":false}]