private boolean rewriteToNGramMatching(Item item, int indexInParent, IndexFacts.Session indexFacts, Query query) {
        boolean rewritten = false;
        if (item instanceof SegmentItem segments) { // handle CJK segmented terms which should be grams instead
            Index index = indexFacts.getIndex(segments.getIndexName());
            if (index.isNGram()) {
                Item grams = splitToGrams(segments, toLowerCase(segments.getRawWord()), index.getGramSize(), query);
                replaceItemByGrams(item, grams, indexInParent);
                rewritten = true;
            }
        }
        else if (item instanceof CompositeItem composite) {
            for (int i = 0; i < composite.getItemCount(); i++)
                rewritten = rewriteToNGramMatching(composite.getItem(i), i, indexFacts, query) || rewritten;
        }
        else if (item instanceof TermItem term) {
            Index index = indexFacts.getIndex(term.getIndexName());
            if (index.isNGram()) {
                Item grams = splitToGrams(term, term.stringValue(), index.getGramSize(), query);
                replaceItemByGrams(item, grams, indexInParent);
                rewritten = true;
            }
        }
        return rewritten;
    }
Handles NGram indexes by splitting query terms to them into grams and combining summary field values
from such fields into the original text.
<p>
This declares it must be placed after Juniper searchers because it assumes Juniper token separators
(which are returned on bolding) are not replaced by highlight tags when this is run (and "after" means
"before" from the point of view of the result).

@author bratseth
container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java