Currently 99% of a profiled `script` processor's execution time comes from the invocation of `CollectionUtils.ensureNoSelfReferences()`, not the script itself (this could vary with script intensity, but it stands to reason it would take a lot to change this dramatically).
<img width="2552" alt="image" src="https://user-images.githubusercontent.com/7477841/162812089-a8d9f023-abf5-4249-b676-78b2adc459a1.png">

1. Is there another way we could approach this self-reference guard rail? It's not completely fool-proof but after the first document passes this check we can be reasonably sure the Script doesn't cause self-references, except in the case of some very specific conditional behavior one would almost have to intentionally code in. As this measure is to help users prevent shooting themselves in the foot, an ostensible 100x overhead is too high a cost, surely.
2. As a half-measure, should we not execute the check if the processor has `ignore_errors` set to `true` anyway? This is the case even for some published integrations, and could benefit greatly from the reduced overhead. It's not ideal as this particular problem really should probably not be ignored since it will cause issues in a later step, but this would preserve existing behavior and reduce cost.
server/src/main/java/org/elasticsearch/ingest/IngestService.java
}
            /*
             * We have to track whether or not the pipeline for this request has already been resolved. It can happen that the
             * pipeline for this request has already been derived yet we execute this loop again. That occurs if the bulk request
             * has been forwarded by a non-ingest coordinating node to an ingest node. In this case, the coordinating node will have
             * already resolved the pipeline for this request. It is important that we are able to distinguish this situation as we
             * can not double-resolve the pipeline because we will not be able to distinguish the case of the pipeline having been
             * set from a request pipeline parameter versus having been set by the resolution. We need to be able to distinguish
             * these cases as we need to reject the request if the pipeline was set by a required pipeline and there is a request
             * pipeline parameter too.
             */
            indexRequest.isPipelineResolved(true);
        }
        
        return NOOP_PIPELINE_NAME.equals(indexRequest.getPipeline()) == false
            || NOOP_PIPELINE_NAME.equals(indexRequest.getFinalPipeline()) == false;
    }
    private static String resolveIndexName(final String unresolvedIndexName, final long epochMillis) {
        List<String> resolvedNames = IndexNameExpressionResolver.DateMathExpressionResolver.resolve(
            new IndexNameExpressionResolver.ResolverContext(epochMillis),
            List.of(unresolvedIndexName)
        );
        assert resolvedNames.size() == 1;
        return resolvedNames.get(0);
    }
    public ClusterService getClusterService() {
        return clusterService;
    }
    public ScriptService getScriptService() {
        return scriptService;