WikibaseOptimizers.java

package org.wikidata.query.rdf.blazegraph;

import org.wikidata.query.rdf.blazegraph.label.EmptyLabelServiceOptimizer;
import org.wikidata.query.rdf.blazegraph.label.LabelServiceExtractOptimizer;
import org.wikidata.query.rdf.blazegraph.label.LabelServicePlacementOptimizer;
import org.wikidata.query.rdf.blazegraph.mwapi.MWApiServicePlacementOptimizer;

import com.bigdata.rdf.sparql.ast.optimizers.ASTJoinGroupOrderOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.ASTRunFirstRunLastOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.DefaultOptimizerList;
import com.bigdata.rdf.sparql.ast.optimizers.IASTOptimizer;

/**
 * Optimizer list for Wikibase.
 */
public class WikibaseOptimizers extends DefaultOptimizerList {
    private static final long serialVersionUID = 2364845438265527328L;

    public WikibaseOptimizers() {
        // There are 2 calls to LabelServicePlacementOptimizer, first one should make general rearrangement,
        // so EmptyLabelServiceOptimizer might see all possible resolutions and add corresponding statement patterns,
        // then second sweep of LabelServicePlacementOptimizer will take into account actual projected variables
        // and place service call at the lates possible position to allow assignment and other
        // projection generation nodes see the variables bound be LabelServiceCall
        addAfter(ASTRunFirstRunLastOptimizer.class, new MWApiServicePlacementOptimizer());
        addAfter(MWApiServicePlacementOptimizer.class, new LabelServicePlacementOptimizer());
        addAfter(LabelServicePlacementOptimizer.class, new EmptyLabelServiceOptimizer());
        addAfter(EmptyLabelServiceOptimizer.class, new LabelServicePlacementOptimizer());
        // Needs to be after wildcard projection resolution,
        // see https://phabricator.wikimedia.org/T171194
        // And before ASTJoinGroupOrderOptimizer because of BLZG-2097
        addBefore(ASTJoinGroupOrderOptimizer.class, new LabelServiceExtractOptimizer());
    }

    /**
     * Add optimizer after optimizer of specified class.
     * @param type Optimizer class after which to insert
     * @param opt Optimizer to insert
     */
    private void addAfter(Class<?> type, final IASTOptimizer opt) {
        // Identify the latest occurence of the optimizer with specified type
        int idx = 0;
        for (int i = 0; i < size(); i++) {
            if (type.isInstance(get(i))) {
                idx = i + 1;
            }
        }
        // insert the optimizer if its placement is identified
        if (idx > 0) {
            add(idx, opt);
            return;
        }
        throw new IllegalArgumentException("Cannot find placement for " + opt.getClass());
    }

    /**
     * Add optimizer before optimizer of specified class.
     * @param type Optimizer class before which to insert
     * @param opt Optimizer to insert
     */
    private void addBefore(Class<?> type, final IASTOptimizer opt) {
        for (int i = 0; i < size(); i++) {
            if (type.isInstance(get(i))) {
                add(i, opt);
                return;
            }
        }
        throw new IllegalArgumentException("Cannot find placement for " + opt.getClass());
    }
}