### Description

As we have more rules doing analysis across plans, a number of methods are useful to add to the `QueryPlan` class itself, mainly around expressions:

```
- expressions() - return the expressions declared by this plan
- references() - return the references from the expressions above
```
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java
new BooleanSimplification(),
            new LiteralsOnTheRight(),
            new BinaryComparisonSimplification(),
            
            new PropagateEquals(),
            new PropagateNullable(),
            new BooleanFunctionEqualsElimination(),
            new CombineDisjunctionsToIn(),
            new SimplifyComparisonsArithmetics(EsqlDataTypes::areCompatible),
            
            new PruneFilters(),
            new PruneColumns(),
            new PruneLiteralsInOrderBy(),
            new PushDownAndCombineLimits(),
            new PushDownAndCombineFilters(),
            new PushDownEval(),
            new PushDownRegexExtract(),
            new PushDownEnrich(),
            new PushDownAndCombineOrderBy(),
            new PruneOrderByBeforeStats(),
            new PruneRedundantSortClauses()
        );
        var skip = new Batch<>("Skip Compute", new SkipQueryOnLimitZero());
        var cleanup = new Batch<>("Clean Up", new ReplaceLimitAndSortAsTopN());
        var label = new Batch<>("Set as Optimized", Limiter.ONCE, new SetAsOptimized());
        return asList(substitutions, operators, skip, cleanup, label);
    }
    
    static class SubstituteSurrogates extends OptimizerRules.OptimizerRule<Aggregate> {