Sparql如何对这类数据进行分组

时间:2016-04-05 13:12:36

标签: sparql rdf aggregation semantic-web ontology

因为我担心你不了解我的情况,所以我为你制作了这个视觉插图(点击图片以获得高质量的版本)。

enter image description here

我知道用户(无论是谁,我们都不在乎)喜欢项目(i1)

我们想建议其他项目:

i1i2类似,具体取决于具体条件(因此存在相似度值,我们称之为s1

i1也类似于相同的i2,但取决于其他条件(因此存在相似度值,我们称之为s2

i1也类似于相同的i2,但取决于第三个标准(因此存在相似度值,我们称之为s3

现在i2属于两个类,每个类都会通过特定权重影响相似性

我的问题

我想计算i1i2之间的最终最终相似度,除了特定类别的权重外,我几乎完成了所有这些相似度。

我的问题是,这个权重不应该用于导致选择i2的标准。换句话说,如果使用1000个条件选择i2 1000次,并且i2属于特定类,那么该类的权重将仅应用一次,而不是1000次,如果{i2 1}}属于两个类,这两个类的两个权重只应用于选择i2

的标准数量

现在

为了方便您帮助我,我做了这个查询(好了很久但是必须很长时间向您展示这个案例),但我也通过让我的查询只选择所需的信息来让您轻松所以你只需在它上面添加另一层选择。

    prefix : <http://example.org/rs#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>


select  ?item ?similarityValue ?finalWeight where {
  values ?i1 {:i1}
  ?i1 ?similaryTo ?item .
  ?similaryTo :hasValue ?similarityValue .
  optional{
    ?item :hasContextValue ?weight .
  }
  bind (if(bound(?weight), ?weight, 1) as ?finalWeight)
}

所以该查询的结果是(查看项i2)它重复了6次(如预期的那样),具有三种不同的相似性(正如预期的那样,由于三种不同的标准),finalWeight ,重量,重复每个标准:

enter image description here

最后

这是数据

@prefix : <http://example.org/rs#>
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

:i1 :similaryTo1 :i2 .
:similaryTo1 :hasValue 0.5 .
:i1 :similaryTo2 :i2 .
:similaryTo2 :hasValue 0.6 .
:i1 :similaryTo3 :i2 .
:similaryTo3 :hasValue 0.7 .
:i2 :hasContextValue 0.1 .
:i2 :hasContextValue 0.4 .
:i1 :similaryTo4 :i3 .
:similaryTo4 :hasValue 0.5 .

我希望你帮助我,我真的很感激

所以我想做什么

想象一下,根本没有重量,所以我的查询将是:

prefix : <http://example.org/rs#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select  ?item ?similarityValue  where {
  values ?i1 {:i1}
  ?i1 ?similaryTo ?item .
  ?similaryTo :hasValue ?similarityValue .

}

结果将是: enter image description here

然后我对具有相似之处的项目进行聚合:

prefix : <http://example.org/rs#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select  ?item (SUM(?similarityValue) as ?sumSimilarities)  where {
  values ?i1 {:i1}
  ?i1 ?similaryTo ?item .
  ?similaryTo :hasValue ?similarityValue .
}
group by ?item

结果是: enter image description here

我想要的是将此结果的每一行乘以与?item相关联的两个权重的总和,对于i2和(1)是(0.1 * 0.4)对于i3

请注意,有些项目没有两个权重,有些项目有一个,有些项目没有,并且注意即使对于那些有两个权重的项目,这两个值也可能相同,所以如果你在这里使用distinct,请小心。

最后,我只是说两个作为一个例子,但在现实生活中,这个数字来自动态系统。

&LT 3的密度;更新 在@Joshua Taylor回答之后,我将他的样本数据理解为:

enter image description here

1 个答案:

答案 0 :(得分:1)

一些数据

首先,我们可以使用一些数据。项目:a 有一堆相似性连接,每个连接都指定一个项目和一个原因。 可能与某个项目类似,原因有几个,甚至可能与相同的项目和原因有重复的相似之处。我认为这与您的用例相匹配到目前为止。 (问题中的示例数据可以使这更清楚,但我认为这与您所拥有的一致)。然后,每个项目都有上下文值,每个原因都有一个可选的权重。

@prefix : <urn:ex:>

:a :similarTo [ :item :b ; :reason :p ] ,
              [ :item :b ; :reason :p ] , # a duplicate
              [ :item :b ; :reason :q ] ,
              [ :item :b ; :reason :r ] ,
              [ :item :c ; :reason :p ] ,
              [ :item :c ; :reason :q ] ,
              [ :item :d ; :reason :r ] ,
              [ :item :d ; :reason :s ] .

:b :context 0.01 .
:b :context 0.02 .
:c :context 0.04 .
:d :context 0.05 .
:e :context 0.06 . # not used

:p :weight 0.1 .
:q :weight 0.3 .
:r :weight 0.5 .
# no weight for :s
:t :weight 0.9 . # not used

听起来你想要做的是计算相似项的上下文值的总和,包括每次出现的上下文值,但是要对原因权重求和,但仅针对不同的出现次数。如果这是正确的理解,那么我认为你想要的东西如下。

因为原因而获得权重

第一步是能够获得每个相似项目的不同原因的权重总和。

prefix : <urn:ex:>

select * where {
  values ?i { :a }

  #-- get the sum of weights of distinct reasons
  #-- for each item that is similar to ?i.
  { select ?item (sum(?weight) as ?propertyWeight) {
      #-- get the distinct properties for each ?item
      #-- along with their weights.
      { select distinct ?item ?property ?weight {
          ?i :similarTo [ :item ?item ; :reason ?property ] .
          optional { ?property :weight ?weight_ }
          bind(if(bound(?weight_), ?weight_, 0.0) as ?weight)
        } }
    }
    group by ?item
  }
}
------------------------------
| i  | item | propertyWeight |
==============================
| :a | :b   | 0.9            |
| :a | :c   | 0.4            |
| :a | :d   | 0.5            |
------------------------------

获取物品的重量

现在,您仍然需要每个项目的值的总和,计算每次出现的重量。所以我们扩展了查询:

select * where {
  values ?i { :a }

  #-- get the sum of weights of distinct reasons
  #-- for each item that is similar to ?i.
  { select ?item (sum(?weight) as ?propertyWeight) {
      #-- get the distinct properties for each ?item
      #-- along with their weights.
      { select distinct ?item ?property ?weight {
          ?i :similarTo [ :item ?item ; :reason ?property ] .
          optional { ?property :weight ?weight_ }
          bind(if(bound(?weight_), ?weight_, 0.0) as ?weight)
        } }
    }
    group by ?item
  }

  #-- get the sum of the context values
  #-- for each item.
  { select ?item (sum(?context_) as ?context) {
      ?item :context ?context_ .
    }
    group by ?item
  }
}
----------------------------------------
| i  | item | propertyWeight | context |
========================================
| :a | :b   | 0.9            | 0.03    |
| :a | :c   | 0.4            | 0.04    |
| :a | :d   | 0.5            | 0.05    |
----------------------------------------

请注意,在第二个子查询中搜索?item:context?context _。是可以的,甚至不能确保?item 是其中一个类似的项目。由于两个子查询的结果已连接,我们只会获得第一个子查询也返回的?item 值的结果。

将它们放在一起

现在,您可以添加,或乘以或执行您想要做的任何其他操作,以将原因权重的总和与上下文值的总和相结合。例如,如果你要总结它们:

select ?i ?item ((?propertyWeight + ?context) as ?similarity) where {
  values ?i { :a }

  #-- get the sum of weights of distinct reasons
  #-- for each item that is similar to ?i.
  { select ?item (sum(?weight) as ?propertyWeight) {
      #-- get the distinct properties for each ?item
      #-- along with their weights.
      { select distinct ?item ?property ?weight {
          ?i :similarTo [ :item ?item ; :reason ?property ] .
          optional { ?property :weight ?weight_ }
          bind(if(bound(?weight_), ?weight_, 0.0) as ?weight)
        } }
    }
    group by ?item
  }

  #-- get the sum of the context values
  #-- for each item.
  { select ?item (sum(?context_) as ?context) {
      ?item :context ?context_ .
    }
    group by ?item
  }
}
--------------------------
| i  | item | similarity |
==========================
| :a | :b   | 0.93       |
| :a | :c   | 0.44       |
| :a | :d   | 0.55       |
--------------------------

最终清理

看看最后的查询,有两件事让我感到困惑。第一个是我们检索内部子查询中每个解决方案的原因权重,而我们只需要为每个项目检索一次。也就是说,我们可以将可选部分移动到外部内部子查询中。然后,我们有一个 bind ,它设置一个我们只在聚合中使用的变量。我们可以通过将 coalesce(?weight,0.0)相加以使用?weight (如果它已绑定)来替换它,否则 0.0 。进行这些更改后,我们最终得到:

select ?i ?item ((?propertyWeight + ?context) as ?similarity) where {
  values ?i { :a }

  #-- get the sum of weights of distinct properties
  #-- using 0.0 as the weight for a property that doesn't
  #-- actually specify a weight.
  { select ?item (sum(coalesce(?weight,0.0)) as ?propertyWeight) {

      #-- get the distinct properties for each ?item.
      { select distinct ?item ?property {
          ?i :similarTo [ :item ?item ; :reason ?property ] .
        } }

       #-- then get each property's optional weight.
       optional { ?property :weight ?weight }
    }
    group by ?item
  }

  #-- get the sum of the context values
  #-- for each item.
  { select ?item (sum(?context_) as ?context) {
      ?item :context ?context_ .
    }
    group by ?item
  }
}

这不是一个巨大的变化,但它让事情变得更清洁,我想,并且更容易理解。

评论

此时几乎成了我的口头禅,但如果提供样本数据,这些问题就更容易回答了。在这种情况下,你首先获得这些值的如何的大多数实际机制并不重要。这就是你之后聚合它们的方式。这就是为什么我们可以使用非常简单的数据,就像我在本回答开始时从头开始创建的那样。

我认为,最重要的是,使用SPARQL(以及其他查询语言,我也期望)的一个重要技术是使用单独的子查询并加入其结果。在这种情况下,我们最终得到了几个子查询,因为我们确实需要以几种不同的方式进行分组。如果SPARQL提供不同的运算符,这可能会更简单,所以我们可以说类似

sum(distinct by(?property) ?weight)

但是这有一个问题,即如果一个不同的属性可以有多个权重,你会选择哪个权重?因此解决方案似乎确实是几个子查询,因此我们可以进行一些不同类型的分组。这就是为什么我问你想要计算的实际公式。