Currently if you provide an ANN search using the `knn` search section, the search doesn't respect cancellation. This is because ANN searches use their own Lucene data structures that aren't covered by `ExitableDirectoryReader`.

This class is forked from Lucene, and in Lucene's version we recently added fine-grained cancellation for ANN search (https://github.com/apache/lucene/pull/833). So I think we just need to fold in the changes to the Elasticsearch version.
server/src/test/java/org/elasticsearch/search/SearchCancellationTests.java
w.close();
    }
    private static void indexRandomDocuments(RandomIndexWriter w, int numDocs) throws IOException {
        for (int i = 1; i <= numDocs; ++i) {
            Document doc = new Document();
            doc.add(new StringField(STRING_FIELD_NAME, "a".repeat(i), Field.Store.NO));
            doc.add(new IntPoint(POINT_FIELD_NAME, i, i + 1));
            w.addDocument(doc);
        }
    }
    @AfterClass
    public static void cleanup() throws IOException {
        IOUtils.close(reader, dir);
        dir = null;
        reader = null;
    }
    public void testAddingCancellationActions() throws IOException {
        ContextIndexSearcher searcher = new ContextIndexSearcher(
            reader,
            IndexSearcher.getDefaultSimilarity(),
            IndexSearcher.getDefaultQueryCache(),
            IndexSearcher.getDefaultQueryCachingPolicy(),
            true
        );
        NullPointerException npe = expectThrows(NullPointerException.class, () -> searcher.addQueryCancellation(null));
        assertEquals("cancellation runnable should not be null", npe.getMessage());
        Runnable r = () -> {};
        searcher.addQueryCancellation(r);
        IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> searcher.addQueryCancellation(r));
        assertEquals("Cancellation runnable already added", iae.getMessage());