Yes.
Regexps can be cheap when they match, but expensive when they fail to match. This is especially true of GREEDYDATA. You can make your regexps cheaper.
Firstly, you are parsing the same prefix in every pattern. You can parse that once so that you avoid the cost of repeatedly parsing it when the rest of the expression fails to match.
grok { match => { "[message]" => "^%{IP:[http][remoteIp]} %{HOSTNAME:[http][sourceHostname]} %{NOTSPACE} \[%{HTTPDATE:[http][timeStamp]}\] %{GREEDYDATA:restOfLine}" } }
The match [restOfLine] against your list of anchored patterns.
Secondly, you can use dissect instead of grok, which is much less flexible and therefore cheaper.
dissect { mapping => { "[message]" => "%{[http][remoteIp]} %{[http][sourceHostname]} %{} [%{http][timeStamp]}] %{restOfLine}" } }
Thirdly, you are using an array of patterns to match the request. You can pull out the request by itself and then use a separate grok to match these patterns against it. Either
dissect { mapping => { "restOfLine" => '"%{httpRequest}" %{everythingElse}' } }
or
grok { match => { "restOfLine" => '"(?<httpRequest>[^"]*)" %{GREEDYDATA:everythingElse}" } }
You could then use another dissect or grok to take off status, size, referer and user agent (again, replacing DATA with QS or the custom pattern used for httpRequest).
If I am reading it correctly you then have a variable section followed by rtm: and a fixed set of stuff. You could pull out the fixed section using dissect
dissect { mapping => { "everythingElse" => "%{beforeRtm} rtm: %{afterRtm}" } }
or grok
grok { match => { "everythingElse => "%{DATA:beforeRtm} rtm: %GREEDYDATA:afterRtm}" } }
then match your list of variable patterns just against the much short [beforeRtm] field.