簡體   English   中英

使用Jena API在SPARQL中自定義函數

[英]Custom functions in SPARQL with the Jena API

第一次發布在這里。 我希望有人能幫助我在Jena(ARQ)API中使用自定義SPARQL函數。 我需要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編寫,我已經很清楚了。 所以,我想知道是否有人知道一個好方法去做這個或從哪里開始尋找一些指導。 我試過尋找文件,但似乎沒有任何東西。 任何幫助將不勝感激。

提前致謝。

我不確定你能做什么你想做而不改變語法。

例如,SUM(...)是由SPARQL語法定義的關鍵字:

過濾器功能或屬性功能可能不是您要找的。

順便說一下,你也沒有在SQL中獲得STDDEV。 是因為需要兩次傳遞數據嗎?

聚合函數是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不同的框架

是的,ARQ可以通過多種方式進行擴展。 ARQ擴展頁面將是最佳起點。

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

我希望這個例子至少可以幫助某人,即使這個問題是幾年前發布的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM