All Downloads are FREE. Search and download functionalities are using the official Maven repository.

querqy.rewrite.contrib.ReplaceRewriter Maven / Gradle / Ivy

There is a newer version: 3.18.1
Show newest version
package querqy.rewrite.contrib;

import querqy.model.AbstractNodeVisitor;
import querqy.model.BoostQuery;
import querqy.model.Clause;
import querqy.model.DisjunctionMaxQuery;
import querqy.model.ExpandedQuery;
import querqy.model.Node;
import querqy.model.QuerqyQuery;
import querqy.model.Query;
import querqy.model.Term;
import querqy.rewrite.QueryRewriter;
import querqy.rewrite.contrib.replace.ReplaceInstruction;
import querqy.trie.SequenceLookup;
import querqy.trie.LookupUtils;
import querqy.trie.model.ExactMatch;
import querqy.trie.model.PrefixMatch;
import querqy.trie.model.SuffixMatch;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

public class ReplaceRewriter extends AbstractNodeVisitor implements QueryRewriter {

    private final SequenceLookup sequenceLookup;

    public ReplaceRewriter(final SequenceLookup sequenceLookup) {
        this.sequenceLookup = sequenceLookup;
    }

    private boolean hasReplacement = false;
    private LinkedList collectedTerms;

    @Override
    public ExpandedQuery rewrite(final ExpandedQuery expandedQuery) {

        final QuerqyQuery querqyQuery = expandedQuery.getUserQuery();

        if (!(querqyQuery instanceof Query)) {
            return expandedQuery;
        }

        collectedTerms = new LinkedList<>();

        visit((Query) querqyQuery);

        final List> exactMatches = sequenceLookup.findExactMatches(collectedTerms);
        if (!exactMatches.isEmpty()) {
            this.hasReplacement = true;

            final List> exactMatchesFiltered =
                    LookupUtils.removeSubsetsAndSmallerOverlaps(exactMatches);

            exactMatchesFiltered.sort(LookupUtils.COMPARE_EXACT_MATCH_BY_LOOKUP_OFFSET_DESC);

            exactMatchesFiltered.forEach(exactMatch ->
                    exactMatch.value.apply(
                            collectedTerms,
                            exactMatch.lookupStart,
                            exactMatch.lookupExclusiveEnd - exactMatch.lookupStart
                    )

            );
        }

        final List> suffixMatches = sequenceLookup.findSingleTermSuffixMatches(collectedTerms);
        if (!suffixMatches.isEmpty()) {
            this.hasReplacement = true;

            suffixMatches.sort(LookupUtils.COMPARE_SUFFIX_MATCH_BY_LOOKUP_OFFSET_DESC);

            suffixMatches.forEach(suffixMatch ->
                    suffixMatch.match.apply(
                            collectedTerms,
                            suffixMatch.getLookupOffset(),
                            1,
                            suffixMatch.wildcardMatch

                    ));
        }

        final List> prefixMatches = sequenceLookup.findSingleTermPrefixMatches(collectedTerms);
        if (!prefixMatches.isEmpty()) {
            this.hasReplacement = true;

            prefixMatches.sort(LookupUtils.COMPARE_PREFIX_MATCH_BY_LOOKUP_OFFSET_DESC);

            prefixMatches.forEach(prefixMatch ->
                    prefixMatch.match.apply(
                            collectedTerms,
                            prefixMatch.getLookupOffset(),
                            1,
                            prefixMatch.wildcardMatch
                    ));
        }

        return hasReplacement ? buildQueryFromSeqList(expandedQuery, collectedTerms) : expandedQuery;
    }

    private ExpandedQuery buildQueryFromSeqList(final ExpandedQuery oldQuery, final List tokens) {
        final Query query = new Query();

        for (final CharSequence token : tokens) {
            final DisjunctionMaxQuery dmq = new DisjunctionMaxQuery(query, Clause.Occur.SHOULD, false);
            query.addClause(dmq);
            final Term term = new Term(dmq, token);
            dmq.addClause(term);
        }

        final ExpandedQuery newQuery = new ExpandedQuery(query);

        final Collection boostDownQueries = oldQuery.getBoostDownQueries();
        if (boostDownQueries != null) {
            boostDownQueries.forEach(newQuery::addBoostDownQuery);
        }

        final Collection boostUpQueries = oldQuery.getBoostUpQueries();
        if (boostUpQueries != null) {
            boostUpQueries.forEach(newQuery::addBoostUpQuery);
        }

        final Collection> filterQueries = oldQuery.getFilterQueries();
        if (filterQueries != null) {
            filterQueries.forEach(newQuery::addFilterQuery);
        }

        return newQuery;
    }

    // TODO: Alternatives in DMQs should be considered

    @Override
    public Node visit(final Term term) {
        if (!term.isGenerated()) {
            collectedTerms.addLast(term);
        }
        return null;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy