In order to implement multi threaded search we need to adjust the logic that creates the slices.
The new slice logic should take the following into account:

- A minimum doc count per slice. In order to avoid a number of aggregations to produce in-accurate results, a slice should at least contain 10% of the total documents in the Lucene index.
- A maximum number of slices. The number of slices that a shard level search creates should be capped. To avoid creating more slices than available search threads.
server/src/main/java/org/elasticsearch/search/internal/ContextIndexSearcher.java
for (Runnable task : tasks) {
                boolean shouldExecuteOnCallerThread = false;
                
                if (i == tasks.size() - 1) {
                    shouldExecuteOnCallerThread = true;
                }
                if (threadPoolExecutor.getQueue().size() >= (threadPoolExecutor.getMaximumPoolSize() * LIMITING_FACTOR)) {
                    shouldExecuteOnCallerThread = true;
                }
                processTask(task, shouldExecuteOnCallerThread);
                ++i;
            }
        }
        protected void processTask(final Runnable task, final boolean shouldExecuteOnCallerThread) {
            if (task == null) {
                throw new IllegalArgumentException("Input is null");
            }
            if (shouldExecuteOnCallerThread == false) {
                try {
                    threadPoolExecutor.execute(task);
                    return;
                } catch (@SuppressWarnings("unused") RejectedExecutionException e) {
                    
                }
            }
            task.run();
        }
    }
}