4

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

我希望查询可以类似于您用于已实现功能的查询:

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

4 回答 4

2

我不确定您是否可以在不实际更改语法的情况下做您想做的事情。

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

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

顺便说一句,您也不会在 SQL 中获得 STDDEV。是因为需要两次传递数据吗?

于 2012-06-15T17:02:26.183 回答
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 的框架

于 2012-06-26T13:25:22.073 回答
0

是的,ARQ 可以通过多种方式进行扩展。ARQ 扩展页面将是最好的起点。

于 2012-06-15T07:50:56.373 回答
0

ARQ 允许您通过在AggregateRegistry. 示例代码显示了这是如何完成的。这可用于添加问题中请求的自定义标准差聚合函数。在下面的示例中,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);
    }
}

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

于 2018-08-15T16:10:32.017 回答