blob: 3ab2eb0a2391d86ff84d6da7b82df37c2985bac3 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package arq.examples.aggregates;
import org.apache.jena.atlas.logging.LogCtl ;
import org.apache.jena.graph.Graph ;
import org.apache.jena.query.* ;
import org.apache.jena.rdf.model.ModelFactory ;
import org.apache.jena.sparql.engine.binding.Binding ;
import org.apache.jena.sparql.expr.Expr ;
import org.apache.jena.sparql.expr.ExprEvalException ;
import org.apache.jena.sparql.expr.ExprList ;
import org.apache.jena.sparql.expr.NodeValue ;
import org.apache.jena.sparql.expr.aggregate.Accumulator ;
import org.apache.jena.sparql.expr.aggregate.AccumulatorFactory ;
import org.apache.jena.sparql.expr.aggregate.AggCustom ;
import org.apache.jena.sparql.expr.aggregate.AggregateRegistry ;
import org.apache.jena.sparql.function.FunctionEnv ;
import org.apache.jena.sparql.graph.NodeConst ;
import org.apache.jena.sparql.sse.SSE ;
/**
* Custom aggregate example.
* <p>
* Custom aggregates must be registered before parsing the query; custom
* aggregates and custom functions have the same syntax so the to tell the
* differenc, the parser needs to know which IRIs are custom aggregates.
* <p>
* The aggregate is registered as a URI, AccumulatorFactory and default value
* for the "no groups" case.
*/
public class CustomAggregate {
static { LogCtl.setCmdLogging(); }
/**
* Execution of a custom aggregate is with accumulators. One accumulator is
* created for the factory for each group in a query execution.
*/
static AccumulatorFactory myAccumulatorFactory = new AccumulatorFactory() {
@Override
public Accumulator createAccumulator(AggCustom agg, boolean distinct) { return new MyAccumulator(agg) ; }
} ;
/**
* Example accumulators - counts the number of valid literals
* of an expression over a group.
*/
static class MyAccumulator implements Accumulator {
int count = 0 ;
private AggCustom agg ;
MyAccumulator(AggCustom agg) { this.agg = agg ; }
/** Function called on each row in a group */
@Override
public void accumulate(Binding binding, FunctionEnv functionEnv) {
ExprList exprList = agg.getExprList() ;
for(Expr expr: exprList) {
try {
NodeValue nv = expr.eval(binding, functionEnv) ;
// Evaluation succeeded.
if ( nv.isLiteral())
count ++ ;
} catch (ExprEvalException ex) {}
}
}
/** Function called to retrieve the value for a single group */
@Override
public NodeValue getValue() {
return NodeValue.makeInteger(count) ;
}
}
public static void main(String[] args) {
// Example aggregate that counts literals.
// Returns unbound for no rows.
String aggUri = "http://example/countLiterals" ;
/* Registration */
AggregateRegistry.register(aggUri, myAccumulatorFactory, NodeConst.nodeMinusOne);
// Some data.
Graph g = SSE.parseGraph("(graph (:s :p :o) (:s :p 1))") ;
String qs = "SELECT (<http://example/countLiterals>(?o) AS ?x) {?s ?p ?o}" ;
// Execution as normal.
Query q = QueryFactory.create(qs) ;
try ( QueryExecution qexec = QueryExecutionFactory.create(q, ModelFactory.createModelForGraph(g)) ) {
ResultSet rs = qexec.execSelect() ;
ResultSetFormatter.out(rs);
}
}
}