code: protected void executeAsyncOperation(final FilterJoinNode node) {
      logger.debug("Executing async actions");
      node.setState(FilterJoinNode.State.RUNNING); // set state before execution to avoid race conditions with listener
  
      NodePipelineManager pipeline = new NodePipelineManager();
      pipeline.addListener(new NodePipelineListener() {
  
        @Override
        public void onSuccess() {
          node.setState(FilterJoinNode.State.COMPLETED); // set state before unblocking the queue to avoid race conditions
          FilterJoinVisitor.this.unblock();
        }
  
        @Override
        public void onFailure(Throwable e) {
          node.setFailure(e);
          node.setState(FilterJoinNode.State.COMPLETED); // set state before unblocking the queue to avoid race conditions
          FilterJoinVisitor.this.unblock();
        }
  
      });
  
      // Adds the list of tasks to be executed
      pipeline.addTask(new IndicesVersionTask());
      pipeline.addTask(new CacheLookupTask());
      pipeline.addTask(new CardinalityEstimationTask());
      pipeline.addTask(new TermsByQueryTask());
  
      // Starts the execution of the pipeline
      pipeline.execute(new NodeTaskContext(client, node, this));
    }
docs: Executes the pipeline of async actions to compute the terms for this node.