private Item transform(Item root) {
        if (root instanceof PhraseItem asPhrase) {
            if (asPhrase.isExplicit() || hasOverlappingTokens(asPhrase)) return root;

            AndItem replacement = new AndItem();
            for (ListIterator<Item> i = asPhrase.getItemIterator(); i.hasNext();) {
                Item item = i.next();
                if (item instanceof WordItem)
                    replacement.addItem(item);
                else if (item instanceof PhraseSegmentItem asSegment)
                    replacement.addItem(new AndSegmentItem(asSegment));
                else
                    replacement.addItem(item); // should never get here
            }
            return replacement;
        }
        else if (root instanceof PhraseSegmentItem asSegment) {
            if (asSegment.isExplicit() || hasOverlappingTokens(asSegment))
                return root;
            else
                return new AndSegmentItem(asSegment);
        }
        else if (root instanceof SegmentItem) {
            return root; // avoid descending into AndSegmentItems and similar
        }
        else if (root instanceof CompositeItem asComposite) {
            for (ListIterator<Item> i = asComposite.getItemIterator(); i.hasNext();) {
                Item item = i.next();
                Item transformedItem = transform(item);
                if (item != transformedItem && asComposite.acceptsItemsOfType(transformedItem.getItemType()))
                    i.set(transformedItem);
            }
            return root;
        }
        return root;
    }
Search to do necessary transforms if the query is in segmented in a CJK language.

@author Steinar Knutsen
container-search/src/main/java/com/yahoo/prelude/querytransform/CJKSearcher.java