You can use grok to parse it
grok { match => { "duration" => "^P(%{NUMBER:[@metadata][duration][y]}Y)?(%{NUMBER:[@metadata][duration][m]}M)?(%{NUMBER:[@metadata][duration][d]}D)?(T(%{NUMBER:[@metadata][duration][h]}H)?(%{NUMBER:[@metadata][duration][min]}M)?(%{NUMBER:[@metadata][duration][sec]}S)?)?" } }
If a group is surrounded by ()? then it can occur zero or more times, i.e. it is optional. Each of the six fields field is parsed by an expression like
(%{NUMBER:[@metadata][duration][y]}Y)?
Plus the Time part is optional, so there is an extra ()? around that.
Note that this has no problem with an invalid specification like "P" with no fields defined. Also NUMBER does not allow comma in numbers so it will fail for "P0,3H", but "P0.333H" is OK. If you need to accept commas it gets more complicated.
No duration that includes years, months or days can be unambiguously converted to seconds (think leap second and leap year) unless it is anchored to form a time interval. To do the conversion for the T fields you can use
ruby {
code => '
hours = event.get("[@metadata][duration][h]").to_f
mins = event.get("[@metadata][duration][min]").to_f
secs = event.get("[@metadata][duration][sec]").to_f
event.set("durationInSecs", 3600 * hours + 60 * mins + 1 * secs)
'
}