Off the top of my head, you likely don't need all those label lookups or the union, and that last (c)-->(e) will look for any length path from c to e, which is probably not what you want and will be very slower with thousands of records. I created a very simplistic representation of this locally, and came up with this:
match (a:Person {id: 1})-[r1:knows]->(b)
with a, r1, b
optional match (a)-[r3:knows]->(c)<-[r2:knows]-(b)
return a, b, c, r1, r2, r3
As Michael explained to me, if you only have one type of relationship between labels (ie. Person is only connected to other Persons via [:knows]) then omitting the label actually speeds up the query.
What the above does is gets all the people that (a) knows directly as (b), then optionally matches any people (b) know directly which (a) also knows directly. This comes back with results like this:
+-----------------------------------------------------------------------------------------------------------------------+
| a | b | c | r1 | r2 | r3 |
+-----------------------------------------------------------------------------------------------------------------------+
| Node[260646]{id:1} | Node[260647]{id:2} | Node[260648]{id:3} | :knows[293029]{} | :knows[293030]{} | :knows[293031]{} |
| Node[260646]{id:1} | Node[260648]{id:3} | <null> | :knows[293031]{} | <null> | <null> |
| Node[260646]{id:1} | Node[260649]{id:4} | <null> | :knows[293032]{} | <null> | <null> |
+-----------------------------------------------------------------------------------------------------------------------+
So where there's a friend of a friend that a knows too (c) it gets returned, otherwise you just get the list of friends.
That's what I gathered you were trying to do from your description, and I think it should perform a lot better.