| /** |
| * 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); |
| } |
| } |
| |
| } |