如何使用SPARQL计算有向图的最大度数?

时间:2014-06-17 18:05:51

标签: sparql jena fuseki

我在两个单独的查询中计算了有向图中每个节点的indegree和outdegree:

SELECT ?s (COUNT(*) AS ?outdegree) 
{ ?s ?p ?o }
GROUP BY ?s
ORDER BY DESC(?outdegree) 

SELECT ?o (COUNT(*) AS ?indegree) 
{ ?s ?p ?o }
GROUP BY ?o
ORDER BY DESC(?indegree)  

我需要计算图表的最大程度。由于有向图的最大度是图的最大值(indegree + outdegree),我想知道如何组合上述两个查询的结果来计算它。

此外,如果有更有效的方法,请同时提出建议。

2 个答案:

答案 0 :(得分:3)

使用以下测试数据:

<urn:ex:cent0>  <urn:ex:p>  <urn:ex:cent1> , <urn:ex:o1> , <urn:ex:o0> .
<urn:ex:s1>  <urn:ex:p>  <urn:ex:cent0> .
<urn:ex:cent1>  <urn:ex:p>  <urn:ex:o3> , <urn:ex:o2> .
<urn:ex:s2>  <urn:ex:p>  <urn:ex:cent0> .
<urn:ex:s0>  <urn:ex:p>  <urn:ex:cent0> .

我执行了您的查询和以下查询:

SELECT  ?cent (( ?indegree + ?outdegree ) AS ?degree)
WHERE
  { { SELECT  (?s AS ?cent) (count(*) AS ?outdegree)
      WHERE
        { ?s ?p ?o }
      GROUP BY ?s
      ORDER BY DESC(?outdegree)
    }
    { SELECT  (?o AS ?cent) (count(*) AS ?indegree)
      WHERE
        { ?s ?p ?o }
      GROUP BY ?o
      ORDER BY DESC(?indegree)
    }
  }

导致以下输出:

-----------------------------
| o              | indegree |
=============================
| <urn:ex:cent0> | 3        |
| <urn:ex:cent1> | 1        |
| <urn:ex:o0>    | 1        |
| <urn:ex:o1>    | 1        |
| <urn:ex:o2>    | 1        |
| <urn:ex:o3>    | 1        |
-----------------------------
------------------------------
| s              | outdegree |
==============================
| <urn:ex:cent0> | 3         |
| <urn:ex:cent1> | 2         |
| <urn:ex:s0>    | 1         |
| <urn:ex:s1>    | 1         |
| <urn:ex:s2>    | 1         |
------------------------------
---------------------------
| cent           | degree |
===========================
| <urn:ex:cent0> | 6      |
| <urn:ex:cent1> | 3      |
---------------------------

这满足了识别具有最大总度的节点的目标。以下是我用来构建此模型并执行此测试的代码(如果您希望重现它):

final Resource c0 = ResourceFactory.createResource("urn:ex:cent0");
final Resource c1 = ResourceFactory.createResource("urn:ex:cent1");
final Property p = ResourceFactory.createProperty("urn:ex:p");

final Model model = new ModelCom(Factory.createDefaultGraph()){{
    this.add(this.createResource("urn:ex:s0"), p, c0);
    this.add(this.createResource("urn:ex:s1"), p, c0);
    this.add(this.createResource("urn:ex:s2"), p, c0);

    this.add(c0, p, this.createResource("urn:ex:o0"));
    this.add(c0, p, this.createResource("urn:ex:o1"));
    this.add(c0, p, c1);

    this.add(c1, p, this.createResource("urn:ex:o2"));
    this.add(c1, p, this.createResource("urn:ex:o3"));
}};

final Query outdeg = QueryFactory.create(
    "SELECT ?s (COUNT(*) AS ?outdegree)\n"+ 
    "{ ?s ?p ?o }\n"+
    "GROUP BY ?s\n"+
    "ORDER BY DESC(?outdegree)"
);

final Query indeg = QueryFactory.create(
    "SELECT ?o (COUNT(*) AS ?indegree)\n"+ 
    "{ ?s ?p ?o }\n"+
    "GROUP BY ?o\n"+
    "ORDER BY DESC(?indegree)"
);

final Query alldeg = QueryFactory.create(
    "SELECT ?cent ((?indegree+?outdegree) AS ?degree) WHERE {\n"+
    "  {SELECT (?s AS ?cent) (COUNT(*) AS ?outdegree)\n"+ 
    "    { ?s ?p ?o }\n"+
    "    GROUP BY ?s\n"+
    "    ORDER BY DESC(?outdegree)\n"+
    "  }\n"+
    "  {SELECT (?o AS ?cent) (COUNT(*) AS ?indegree)\n"+ 
    "    { ?s ?p ?o }\n"+
    "    GROUP BY ?o\n"+
    "    ORDER BY DESC(?indegree)\n"+
    "  }\n"+
    "}"
);

@Test
public void test()
{
    model.write(System.out, "TTL");
    System.out.println();

    System.out.println(alldeg);

    final QueryExecution exec0 = QueryExecutionFactory.create(indeg, model);
    ResultSetFormatter.out(exec0.execSelect(), indeg);
    exec0.close();

    final QueryExecution exec1 = QueryExecutionFactory.create(outdeg, model);
    ResultSetFormatter.out(exec1.execSelect(), outdeg);
    exec1.close();

    final QueryExecution exec2 = QueryExecutionFactory.create(alldeg, model);
    ResultSetFormatter.out(exec2.execSelect(), alldeg);
    exec2.close();
}

答案 1 :(得分:3)

您可以使用非常简单的查询来获取每个顶点?x的度:

select ?x (count(*) as ?degree) { 
  { ?x ?p ?o } union
  { ?s ?p ?x }
}
group by ?x

例如,关于这些数据:

@prefix : <https://stackoverflow.com/q/24270532/1281433/> .

#     a
#     |
#     V
# b<--c-->d
#     |
#     V  
#     e

:a :p :c .
:c :p :b, :d, :e .

你会得到结果:

---------------
| x  | degree |
===============
| :a | 1      |
| :b | 1      |
| :c | 4      |
| :d | 1      |
| :e | 1      |
---------------

现在,如果您想要最大值,您可以简单地订购并使用限制为1,例如

select ?x (count(*) as ?degree) { 
  { ?x ?p ?o } union
  { ?s ?p ?x }
}
group by ?x
order by desc(?degree)
limit 1
---------------
| x  | degree |
===============
| :c | 4      |
---------------

如果只有一个具有最高学位的顶点,这将有效。如果有多个具有相同的最高学位,您将获得其中一个。

如果您真的希望合并您已经获得的两个查询,那么Rob Hall's answer之类的内容将起作用,除了,因为子查询不是t返回具有0 indegree或0 outdegree的节点,它们不在最终结果中,因为它们不可用于连接。因此,如果您保证每个节点都具有非零的indegrees和outdegree,则只使用该方法。他的答案也很有用,作为如何构建图形并以编程方式使用Jena运行这些查询的示例。