public static Set<PhraseMatcher.Phrase> getNonOverlappingPartialPhraseMatches(PhraseMatcher phraseMatcher,
                                                                                  Query query)
                                                                                  throws RuntimeException {
        RewriterUtils.log(logger, query, "Retrieving longest non-overlapping partial phrase matches");
        if (phraseMatcher == null)
            return null;

        Item root = query.getModel().getQueryTree().getRoot();
        List<PhraseMatcher.Phrase> matches = phraseMatcher.matchPhrases(root);
        if (matches == null || matches.isEmpty())
            return null;

        Set<PhraseMatcher.Phrase> resultMatches = new HashSet<>();
        ArrayList<PhraseMatcher.Phrase> phrasesInSubTree = new ArrayList<>();
        CompositeItem prevOwner = null;
        ListIterator<PhraseMatcher.Phrase> matchesIter = matches.listIterator();

        // Iterate through all matches
        while (matchesIter.hasNext()) {
            PhraseMatcher.Phrase phrase = matchesIter.next();
            RewriterUtils.log(logger, query, "Working on phrase: " + phrase);
            CompositeItem currOwner = phrase.getOwner();

            // Check if previous is AND item and this phrase is in a different item
            // If so, work on the previous set to eliminate overlapping matches
            if (!phrasesInSubTree.isEmpty() && currOwner!=null &&
               prevOwner!=null && !currOwner.equals(prevOwner)) {
                RewriterUtils.log(logger, query, "Previous phrase is in different AND item");
                List<PhraseMatcher.Phrase> subTreeMatches
                    = getNonOverlappingMatchesInAndItem(phrasesInSubTree, query);
                if(subTreeMatches==null) {
                    RewriterUtils.error(logger, query, "Error retrieving matches from subtree");
                    throw new RuntimeException("Error retrieving matches from subtree");
                }
                resultMatches.addAll(subTreeMatches);
                phrasesInSubTree.clear();
            }

            // Check if this is an AND item
            if (currOwner instanceof AndItem) {
                phrasesInSubTree.add(phrase);
                // If phrase is not an AND item, only keep those that are single word
                // in order to eliminate cases such as (new RANK york) from being treated
                // as match if only new york but not new or york is in the dictionary
            }
            else if (phrase.getLength() == 1 && !(currOwner instanceof RankItem && phrase.getStartIndex() != 0)) {
                resultMatches.add(phrase);
            }

            prevOwner = currOwner;
        }

        // Check if last item is AND item
        // If so, work on the previous set to elimate overlapping matches
        if(!phrasesInSubTree.isEmpty()) {
            RewriterUtils.log(logger, query, "Last phrase is in AND item");
            List<PhraseMatcher.Phrase> subTreeMatches
                = getNonOverlappingMatchesInAndItem(phrasesInSubTree, query);
            if(subTreeMatches==null) {
                RewriterUtils.error(logger, query, "Error retrieving matches from subtree");
                throw new RuntimeException("Error retrieving matches from subtree");
            }
            resultMatches.addAll(subTreeMatches);
        }
        RewriterUtils.log(logger, query, "Successfully Retrieved longest non-overlapping partial phrase matches");
        return resultMatches;
    }
<p>Retrieve the longest, from left to right non overlapping partial
phrase substrings in query based on FSA dictionary</p>

e.g. query: ((modern AND new AND york AND city AND travel) OR travel) AND
            ((sunny AND travel AND agency) OR nyc)<br>
     dictionary: <br>
                 mny\tmodern new york<br>
                 mo\tmodern<br>
                 modern\tn/a<br>
                 modern new york\tn/a<br>
                 new york\tn/a<br>
                 new york city\tn/a<br>
                 new york city travel\tn/a<br>
                 new york company\tn/a<br>
                 ny\tnew york<br>
                 nyc\tnew york city\tnew york company<br>
                 nyct\tnew york city travel<br>
                 ta\ttravel agency<br>
                 travel agency\tn/a<br>
     return: <br>
             modern<br>
             new york city travel<br>
             travel agency<br>
             nyc<br>
@param phraseMatcher PhraseMatcher object loaded with FSA dict
@param query Query object from the searcher
@return Matching phrases
container-search/src/main/java/com/yahoo/search/query/rewrite/RewriterFeatures.java