使用Jena API在SPARQL中自定义函数

时间:2012-06-14 19:44:50

标签: java sparql jena

第一次发布在这里。我希望有人能帮助我在Jena(ARQ)API中使用自定义SPARQL函数。我需要SPARQL做一些聚合,我知道它已经实现了avg,count,min,max和sum,但我需要能够做标准偏差和中位数(我也需要范围,但这可以是仅使用最小值和最大值完成。

我希望查询可以与您已经实现的函数使用的类似:

PREFIX example: <http://www.examples.com/functions#>  
PREFIX core: <http://www.core.com/values#>  
SELECT (stddev(?price) as ?stddev)  
WHERE {  
    ?s core:hasPrice ?price  
}  

我不知道这是否可能,但如果我需要像其他自定义函数一样使用它,只要它仍然得到结果的标准偏差。

我所知道的是,函数将用Java编写,我已经很清楚了。所以,我想知道是否有人知道一个好方法去做这个或从哪里开始寻找一些指导。我试过寻找文件,但似乎没有任何东西。任何帮助将不胜感激。

提前致谢。

4 个答案:

答案 0 :(得分:2)

我不确定你能不能实际改变语法而做你想做的事。

例如,SUM(...)是由SPARQL语法定义的关键字:

过滤器功能或属性功能可能不是您想要的。

顺便说一下,你也没有在SQL中获得STDDEV。是因为需要两次传递数据吗?

答案 1 :(得分:2)

聚合函数是SPARQL(以及ARQ)函数的特例。 我认为在ARQ中扩展聚合函数集并不容易,而扩展过滤函数集和属性函数集很容易(并且有文档记录)。 你可以用这样的方式计算标准偏差:

PREFIX afn: <http://jena.hpl.hp.com/ARQ/function#>
PREFIX core: <http://www.core.com/values#>  
SELECT ( afn:sqrt( sum( (?price - ?avg) * (?price - ?avg) ) / (?count - 1) ) as ?stddev )  
WHERE {
  ?s core:hasPrice ?price .
  {  
    SELECT (avg(?price) as ?avg) (count(*) as ?count) 
    WHERE {  
      ?s core:hasPrice ?price
    }
  }
}  

我无论如何都被迫使用afn:sqrt,这是一个ARQ“专有”函数,不在SPARQL 1.1草案中,所以这个查询不适用于与Jena不同的框架

答案 2 :(得分:0)

是的,ARQ可以通过多种方式进行扩展。 ARQ extensions page将是最佳起点。

答案 3 :(得分:0)

ARQ允许您通过在AggregateRegistry中注册来添加自己的聚合函数。示例code显示了如何完成此操作。这可用于添加问题中要求的自定义标准偏差聚合函数。在下面的示例中,Commons Math用于进行计算。

import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
import org.apache.jena.graph.Graph;
import org.apache.jena.query.*;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.sparql.engine.binding.Binding;
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;

public class StandardDeviationAggregate {
    /**
     * Custom aggregates use accumulators. One accumulator is created for each group in a query execution.
     */
    public static AccumulatorFactory factory = (agg, distinct) -> new StatsAccumulator(agg);

    private static class StatsAccumulator implements Accumulator {
        private AggCustom agg;
        private SummaryStatistics summaryStatistics = new SummaryStatistics();

        StatsAccumulator(AggCustom agg) { this.agg = agg; }

        @Override
        public void accumulate(Binding binding, FunctionEnv functionEnv) {
            // Add values to summaryStatistics
            final ExprList exprList = agg.getExprList();
            final NodeValue value = exprList.get(0).eval(binding, functionEnv) ;
            summaryStatistics.addValue(value.getDouble());
        }

        @Override
        public NodeValue getValue() {
            // Get the standard deviation
            return NodeValue.makeNodeDouble(summaryStatistics.getStandardDeviation());
        }
    }

    public static void main(String[] args) {
        // Register the aggregate function
        AggregateRegistry.register("http://example/stddev", factory, NodeConst.nodeMinusOne);

        // Add data
        Graph g = SSE.parseGraph("(graph " +
                "(:item1 :hasPrice 13) " +
                "(:item2 :hasPrice 15) " +
                "(:item3 :hasPrice 20) " +
                "(:item4 :hasPrice 30) " +
                "(:item5 :hasPrice 32) " +
                "(:item6 :hasPrice 11) " +
                "(:item7 :hasPrice 16))");

        Model m = ModelFactory.createModelForGraph(g);
        String qs = "PREFIX : <http://example/> " +
                    "SELECT (:stddev(?price) AS ?stddev) " +
                    "WHERE { ?item :hasPrice ?price }";

        // Execute query and print results
        Query q = QueryFactory.create(qs) ;
        QueryExecution qexec = QueryExecutionFactory.create(q, m);
        ResultSet rs = qexec.execSelect() ;
        ResultSetFormatter.out(rs);
    }
}

我希望这个例子至少对某人有帮助,即使这个问题是几年前发布的。