CategoriesStoredQuery.java

package org.wikidata.query.rdf.blazegraph.categories;

import org.openrdf.model.URI;
import org.openrdf.model.impl.URIImpl;
import org.wikidata.query.rdf.common.uri.Mediawiki;

import com.bigdata.rdf.sparql.ast.eval.ServiceParams;
import com.bigdata.rdf.sparql.ast.service.ServiceCallCreateParams;
import com.bigdata.rdf.sparql.ast.service.ServiceRegistry;
import com.bigdata.rdf.sparql.ast.service.storedquery.SimpleStoredQueryService;

/**
 * Stored query for categories:
 * <pre>
 * {@code
 * SELECT ?out ?depth WHERE {
 *  SERVICE mediawiki:categoryTree {
 *      bd:serviceParam mediawiki:start <https://en.wikipedia.org/wiki/Category:Ducks> .
 *      bd:serviceParam mediawiki:direction "Reverse" .
 *      bd:serviceParam mediawiki:depth 5 .
 *  }
 * } ORDER BY ASC(?depth)
 * }
 * </pre>
 *
 * Directions are:
 * - Forward: get parent category tree
 * - Reverse: get subcategory tree
 * - Undirected: both directions
 */
public class CategoriesStoredQuery extends SimpleStoredQueryService {
    /**
     * The URI service key.
     */
    public static final URI SERVICE_KEY = new URIImpl(Mediawiki.NAMESPACE + "categoryTree");
    /**
     * start parameter.
     */
    public static final URI START_PARAM = new URIImpl(Mediawiki.NAMESPACE + "start");
    /**
     * direction parameter.
     */
    public static final URI DIRECTION_PARAM = new URIImpl(Mediawiki.NAMESPACE + "direction");
    /**
     * max depth parameter.
     */
    public static final URI DEPTH_PARAM = new URIImpl(Mediawiki.NAMESPACE + "depth");
    /**
     * Default max depth.
     */
    public static final int MAX_DEPTH = 8;
    /**
     * Register the service so it is recognized by Blazegraph.
     */
    public static void register() {
        ServiceRegistry reg = ServiceRegistry.getInstance();
        reg.add(SERVICE_KEY, new CategoriesStoredQuery());
        reg.addWhitelistURL(SERVICE_KEY.toString());
    }

    @Override
    protected String getQuery(ServiceCallCreateParams createParams,
            ServiceParams serviceParams) {
        final URI start = serviceParams.getAsURI(START_PARAM);
        final String direction = serviceParams.getAsString(DIRECTION_PARAM, "Reverse");
        final int depth = serviceParams.getAsInt(DEPTH_PARAM, MAX_DEPTH);

        // Fixed parts
        return "SELECT * WHERE {\n" +
                "SERVICE gas:service {\n" +
                "     gas:program gas:gasClass \"com.bigdata.rdf.graph.analytics.BFS\" .\n" +
                "     gas:program gas:linkType mediawiki:isInCategory .\n" +
        // Variable parts
                "   gas:program gas:traversalDirection \"" + direction + "\" .\n" +
                "     gas:program gas:in <" + start.stringValue() + "> .\n" +
                "     gas:program gas:out ?out .\n" +
                "     gas:program gas:out1 ?depth .\n" +
                "     gas:program gas:out2 ?predecessor .\n" +
                "     gas:program gas:maxIterations " + depth + " .\n" +
        // Fixed footer
                "  }\n" +
                "}";
    }

}