如何使用 SPARQL "MINUS" as SQL "NOT IN" 等同于获得所有只在一支球队比赛的球员

How to use SPARQL "MINUS" as SQL "NOT IN" equivalent to get all players who exclusively played on one team

我正在对 Lahman 棒球数据库中的数据执行 sparql 查询。 下面是一些示例数据,用于展示我的查询需要执行的操作。

@prefix ma: <http://mydataset.com/ns/master#> .
ma:billybo01 ma:nameFirst "Billy" .
ma:billybo01 ma:nameLast "Bored" .
ma:chrisgow01 ma:nameFirst "Chris" .
ma:chrisgow01 ma:nameLast "Gowan" .
ma:bradlee01 ma:nameFirst "Brad" .
ma:bradlee01 ma:nameLast "Lee" .


@prefix teamQ2: <http://mydataset.com/ns/teamQ2#> .
@prefix yearQ2: <http://mydataset.com/ns/yearQ2#> .
@prefix ma: <http://mydataset.com/ns/master#> .
teamQ2:BS1 yearQ2:1871 ma:billybo01 .
teamQ2:BS1 yearQ2:1872 ma:billybo01 .
teamQ2:BS1 yearQ2:1873 ma:billybo01 .
teamQ2:LAN yearQ2:1874 ma:billybo01 .

teamQ2:LAN yearQ2:1871 ma:chrisgow01 .
teamQ2:LAN yearQ2:1872 ma:chrisgow01 .

teamQ2:BS1 yearQ2:1871 ma:bradlee01 .
teamQ2:BS1 yearQ2:1872 ma:bradlee01 .

我正在尝试获取所有只为 LAN 而没有为其他球队效力的球员的名字和姓氏。我的尝试如下所示。我希望查询任何一年在团队 LAN 中的所有球员,获得他们的 masterID,然后从该集合中减去所有曾出现在 LAN 以外的团队中的球员。然后我将 masterId 与最后的名字和姓氏匹配起来。现在它正在返回数据,就好像 MINUSFILTER !EXISTS 相互抵消一样,它只是 returns 所有在 LAN 上玩过的玩家。除了 MINUSFILTER !EXISTS 之外,我还需要使用其他东西吗?

PREFIX ma: <http://mydataset.com/ns/master#>
PREFIX teamQ2: <http://mydataset.com/ns/teamQ2#> 
SELECT DISTINCT ?nameFirst ?nameLast
WHERE
{
  teamQ2:LAN ?yearID ?masterID .
  MINUS{FILTER (
      !EXISTS {
          teamQ2:LAN ?yearID ?nonLANmasterID .
      }
      )}
  ?masterID ma:nameLast ?nameLast .
  ?masterID ma:nameFirst ?nameFirst .
}
ORDER BY ?nameLast ?nameFirst

建模很不寻常,但这里是根据您的描述得出的查询大纲:

  1. 找到所有 teamQ2:LAN ?p ?o . 个三元组。

  2. 拒绝 (FILTER NOT EXISTS) 任何有不同 (FILTER(?otherteam != teamQ2:LAN ) 主题的 属性-对象对 ?p ?o.

    的匹配

    (这实际上是“没有在同一年为同一支球队效力,因为?pyearQ2:1871等包括年份。)

PREFIX ma: 
PREFIX teamQ2:  
SELECT *
WHERE
{
  teamQ2:LAN ?p ?masterID .
  FILTER NOT EXISTS {
      ?otherteam ?p ?masterID .
      FILTER(?otherteam !=  teamQ2:LAN )
  }
  ?masterID ma:nameLast ?nameLast .
  ?masterID ma:nameFirst ?nameFirst .
}

在这种情况下也可以这样做:

  1. 查找 teamQ2:LAN.
  2. 的玩家
  3. 查找不属于 teamQ2:LAN 的玩家。
  4. MINUS ?masterID 以上两个。
PREFIX ma: 
PREFIX teamQ2:  
SELECT *
WHERE
{
  teamQ2:LAN ?yearID ?masterID .
  MINUS {
      ?otherteam ?yearID ?masterID .
      FILTER(?otherteam !=  teamQ2:LAN )
  }
  ?masterID ma:nameLast ?nameLast .
  ?masterID ma:nameFirst ?nameFirst .
}

我认为你应该考虑及时将数据记录为事件:

玩家 "play for team" "year" 或三人组:

ma:bradlee01 :playedForInYear [ :team teamQ2:BS1 ; :year 1871 ].
ma:bradlee01 :playedForInYear [ :team teamQ2:BS1 ; :year 1872 ].

在你的例子中,我假设你想要的答案是 "Chris Gowan",因为他是那里唯一为 LAN 而不是为任何其他球队效力的球员,对吗?

接近它的方法是逐步建立它。首先,只查询所有参加 LAN 比赛的人:

SELECT DISTINCT ?firstName ?lastName
WHERE { 
         teamQ2:LAN ?yearId ?player .
         ?player ma:nameLast ?lastName;
                 ma:nameFirst ?firstName .
}

结果将是:

Evaluating SPARQL query...
+-------------------------------------+-------------------------------------+
| firstName                           | lastName                            |
+-------------------------------------+-------------------------------------+
| "Billy"                             | "Bored"                             |
| "Chris"                             | "Gowan"                             |
+-------------------------------------+-------------------------------------+
2 result(s) (75 ms)

现在,我们要添加一个过滤器,以删除 在另一年为另一支球队效力的球员。一名球员为另一支球队效力,如果他们是三人组的对象,其中主题是 LAN 以外的球队。

我将使用 MINUS,因为这就是你的要求。还有 FILTER NOT EXISTS 我经常发现使用起来更直观,但它们大致相同。所以我们需要的 MINUS 条件应该是这样的:

 MINUS { ?otherTeam ?otherYearId ?player }

但这还不够,因为我们需要对 ?otherTeam?otherYearId 的允许值进行限制(否则此条件将匹配所有内容)。

坦率地说,要正确地做到这一点有点棘手,因为数据模型太差了。例如,如果所有团队资源都是 rdf:type teamQ2:Team,更不用说使用年份作为团队之间关系的 属性 名称这一事实播放器并不是建模的好方法。但是我跑题了。

我们将使用一个糟糕的识别团队的版本:我们假设每个以 teamQ2 前缀开头的资源都是一个团队标识符。因此,我们想减去该球员效力的所有球队,其中主题以 teamQ2 开头但 而不是 LAN 结尾:

 MINUS { ?otherTeam ?otherYearId ?player . 
         FILTER(STRSTARTS(STR(?otherTeam), STR(teamQ2:)) 
         FILTER(!STRENDS(STR(?otherTeam), "LAN"))
 }

这就是完整的查询:

SELECT DISTINCT ?firstName ?lastName
WHERE { 
         teamQ2:LAN ?yearId ?player .
         ?player ma:nameLast ?lastName;
                 ma:nameFirst ?firstName .
         MINUS { ?otherTeam ?otherYearId ?player . 
                  FILTER(STRSTARTS(STR(?otherTeam), STR(teamQ2:))) 
                  FILTER(!STRENDS(STR(?otherTeam), "LAN"))
         }
}

结果:

Evaluating SPARQL query...
+-------------------------------------+-------------------------------------+
| firstName                           | lastName                            |
+-------------------------------------+-------------------------------------+
| "Chris"                             | "Gowan"                             |
+-------------------------------------+-------------------------------------+
1 result(s) (2 ms)