You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2014/12/29 17:46:44 UTC
[3/3] jena git commit: JENA-803 : Example custom aggregate
JENA-803 : Example custom aggregate
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/6537629d
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/6537629d
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/6537629d
Branch: refs/heads/master
Commit: 6537629d8a1c6f03810612321327e4dbc96f0dfa
Parents: a01534e
Author: Andy Seaborne <an...@apache.org>
Authored: Mon Dec 29 16:42:43 2014 +0000
Committer: Andy Seaborne <an...@apache.org>
Committed: Mon Dec 29 16:42:43 2014 +0000
----------------------------------------------------------------------
.../examples/aggregates/CustomAggregate.java | 113 +++++++++++++++++++
1 file changed, 113 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/6537629d/jena-arq/src-examples/arq/examples/aggregates/CustomAggregate.java
----------------------------------------------------------------------
diff --git a/jena-arq/src-examples/arq/examples/aggregates/CustomAggregate.java b/jena-arq/src-examples/arq/examples/aggregates/CustomAggregate.java
new file mode 100644
index 0000000..2650508
--- /dev/null
+++ b/jena-arq/src-examples/arq/examples/aggregates/CustomAggregate.java
@@ -0,0 +1,113 @@
+/**
+ * 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 com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.query.* ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+import com.hp.hpl.jena.sparql.engine.binding.Binding ;
+import com.hp.hpl.jena.sparql.expr.Expr ;
+import com.hp.hpl.jena.sparql.expr.ExprEvalException ;
+import com.hp.hpl.jena.sparql.expr.ExprList ;
+import com.hp.hpl.jena.sparql.expr.NodeValue ;
+import com.hp.hpl.jena.sparql.expr.aggregate.Accumulator ;
+import com.hp.hpl.jena.sparql.expr.aggregate.AccumulatorFactory ;
+import com.hp.hpl.jena.sparql.expr.aggregate.AggCustom ;
+import com.hp.hpl.jena.sparql.expr.aggregate.AggregateRegistry ;
+import com.hp.hpl.jena.sparql.function.FunctionEnv ;
+import com.hp.hpl.jena.sparql.graph.NodeConst ;
+import com.hp.hpl.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) { 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);
+ }
+ }
+
+}