The filter()-step takes an anonymous traversal as an argument. An anonymous traversal is simply a chain of Gremlin steps. The filter()-step will limit the search to only include elements for which the anonymous traversal returns a result.
For instance, let's consider an example where we want to answer the question "What people are experts in the application called Ardoq?". In other words, we want to find all components of type Person which have an outgoing reference of type "Is Expert In" to a component of type "Application" and name "Ardoq".
One way to do this without using the filter()-step is to find the applications called "Ardoq", follow the incoming reference of type "Is Expert In" and filter away all components whose type is not "Person". This approach is shown in the following query, and visualized step by step to the right:
g.V(). hasLabel('Application'). has('name', 'Ardoq'). in('Is Expert In'). hasLabel('Person')
Notice how the traversal is built up the opposite way from which the question it answers was asked.
The way we typically ask questions is by specify what result we want and then describe the limitations we should impose on the result. The filter()-step enables us to write queries which more closely resembles the way we ask questions. Again, considering the question "What people are experts in the application called Ardoq?", we can write a query which first finds all components of type "Person" and then filters away those which do not have an outgoing reference of type "Is Expert In" to a component of type "Application" and name "Ardoq".
g.V(). hasLabel('Person'). filter( out('Is Expert In'). hasLabel('Application'). has('name', 'Ardoq'))