Java 基于apachejena的电影信息检索DBpedia端点的多查询

Java 基于apachejena的电影信息检索DBpedia端点的多查询,java,jena,semantic-web,dbpedia,Java,Jena,Semantic Web,Dbpedia,我试图使用ApacheJena下载一些电影的信息(制作年份和标题),并查询DBpedia公共端点。 我已经知道公共端点有一些安全限制,因此它不允许使用返回结果集中超过2000行的查询。 出于这个原因,我尝试使用LIMIT和OFFSET选项将我的查询细分为多个查询,并使用Java程序()将它们以格式化的方式保存在特定的文件中: public void movieQuery(String dbpediaFilms) throws IOException { String includeNa

我试图使用ApacheJena下载一些电影的信息(制作年份和标题),并查询DBpedia公共端点。 我已经知道公共端点有一些安全限制,因此它不允许使用返回结果集中超过2000行的查询。 出于这个原因,我尝试使用LIMIT和OFFSET选项将我的查询细分为多个查询,并使用Java程序()将它们以格式化的方式保存在特定的文件中:

public void movieQuery(String dbpediaFilms) throws IOException {
     String includeNamespaces = "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n" +
      "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n" +
      "PREFIX dcterms: <http://purl.org/dc/terms/>\n" +
      "PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>\n";

       String currQuery = includeNamespaces + "SELECT DISTINCT ?movie (str(?movie_title) as ?title) (str(?movie_year) as ?year) WHERE {\n" +
       " ?movie rdf:type dbpedia-owl:Film.\n" +
       " ?movie rdfs:label ?movie_title.\n" +
" ?movie dcterms:subject ?cat .\n" +
" ?cat rdfs:label ?movie_year .\n" +
" FILTER langMatches(lang(?movie_title), \"EN\") .\n" +
" FILTER regex(?movie_year, \"^[0-9]{4} \", \"i\")\n" +
" } limit 2000 offset ";
      int totalNumberOfFilms = 77794;
      int totNumQuery = 39;
      int offset = 0;
      int currNum = 0;

      for(int i = 1; i <= totNumQuery; i++) {
      try {

         Query query = QueryFactory.create(currQuery + offset);
         currNum += Utils.serializeMappingList(getMovieMappingList(query), dbpediaFilms);

       } catch (Exception ex) {
             ex.printStackTrace();
             throw ex;
        }

      offset += 2000;

      myWait(30);

     }

     System.out.println(currNum);


}

正如您在java代码中看到的,为了获得正确的结果集分区,我将一个变量(偏移量)增加2000

运行一个初步查询,我发现使用此查询,DBpedia中不同电影的总数为77794:

select distinct count(?film) where {
?film rdf:type dbpedia-owl:Film.
}
SELECT DISTINCT ?movie (group_concat(?movie_year;separator=';') as ?years)
WHERE {
  ?movie rdf:type dbpedia-owl:Film.
  ?movie rdfs:label ?movie_title.
  FILTER langMatches(lang(?movie_title), 'en')
  optional { ?movie dbpprop:released   ?rel_year }
  optional { ?movie dbpedia-owl:releaseDate ?owl_year}
  optional { ?movie dcterms:subject ?sub.
             ?sub rdfs:label ?movie_year_sub
             filter regex(?movie_year_sub, ".*[0-9]{4}.*", "i")
           }
  BIND(COALESCE(?owl_year, ?rel_year, ?movie_year_sub) AS ?movie_year)
}
group by ?movie ?movie_title 
having count(?movie_year) > 1
limit 2000
问题是,如果我计算得到的节点数,等于76000,所以我认为我错过了很多使用这个程序的电影。 有人会问我如何才能正确地得到整个结果集? 为了正确获得结果,我是否必须查询本地DBpedia转储

事先非常感谢

编辑: 我使用有用的建议@Joshua Taylor创建了一个新的查询:

SELECT DISTINCT ?movie (str(?movie_year) as ?year) (str(?movie_title) as ?title)  WHERE {
?movie rdf:type dbpedia-owl:Film.
movie rdfs:label ?movie_title.
FILTER langMatches(lang(?movie_title), \"EN\") .
optional { ?movie dbpprop:released   ?rel_year }
optional{?movie dbpedia-owl:releaseDate ?owl_year}
 optional {?movie dcterms:subject ?sub.
 ?sub rdfs:label ?movie_year_sub
 filter regex(?movie_year_sub, ".*[0-9]{4}.*", "i") }
 BIND(COALESCE(?owl_year, ?rel_year, ?movie_year_sub) AS ?movie_year)
 } group by ?movie limit 2000 offset $specific_offset 
使用GROUPBY规范,virtuoso端点让我能够获得正确的结果集,其中没有重复的行。 相反,当我尝试使用apache Jena运行查询时,我无法执行它,因为我收到以下错误:

com.hp.hpl.jena.query.QueryParseException: Non-group key variable in SELECT: ?movie_year in expression str(?movie_year)

有比那些满足您原始查询的电影更多的电影,并且您的查询不一定只计算一次每部电影。
select distinct(count(?var)as?nVar).
select(count(distinct?var)as?nVar).
之间有很大的区别。第一个仅显示不同的计数,而第二个显示不同绑定的数量

对于每部电影,可以获得多个结果行。在查询的这一部分中:

?movie rdf:type dbpedia-owl:Film.
?movie dcterms:subject ?cat .
?cat rdfs:label ?movie_year .
FILTER regex(?movie_year, "^[0-9]{4} ", "i")
您将获得电影所属的每个类别的每个匹配标签的结果行。例如,如果某部电影属于1984年最差电影和2010年重拍电影的类别,您将获得两个结果行

还有一些合法的电影你不会计算在内,因为有些电影可能没有英文电影标题或以一年开头的类别

我不确定您是否能够获得完全令人满意的结果,因为DBpedia似乎没有可靠的数据。也就是说,尝试这样的查询开始。它将获得所有的电影,并且(希望)能够获得足够的信息,在很多情况下可以获得日期。不过,dbpprop:released的一些值非常奇怪,我不知道它们对您有多有用

select * where { 
  ?film a dbpedia-owl:Film 
  optional { ?film dbpprop:released        ?released    }
  optional { ?film dbpedia-owl:releaseDate ?releaseDate }
  optional { ?film dcterms:subject [ rdfs:label ?catLabel ]
             filter( regex( ?catLabel, "^[0-9]{4}.*films", "i" ) )
           }
}
order by ?film 
limit 100

新查询后更新 您发布的查询不适用于Jena(因为它不是合法的SPARQL,即使Virtuoso接受它),可以通过几种不同的方式进行修复,具体取决于您想要什么。最简单、最直接的方法就是不要在任何事情上分组

SELECT DISTINCT ?movie (str(?movie_year) as ?year) (str(?movie_title) as ?title)
WHERE {
  ?movie rdf:type dbpedia-owl:Film.
  ?movie rdfs:label ?movie_title.
  FILTER langMatches(lang(?movie_title), 'en')
  optional { ?movie dbpprop:released   ?rel_year }
  optional { ?movie dbpedia-owl:releaseDate ?owl_year}
  optional { ?movie dcterms:subject ?sub.
             ?sub rdfs:label ?movie_year_sub
             filter regex(?movie_year_sub, ".*[0-9]{4}.*", "i")
           }
  BIND(COALESCE(?owl_year, ?rel_year, ?movie_year_sub) AS ?movie_year)
}
limit 2000
但是,如果你这样做,当你有多部英文电影标题、发行年份等时,你会得到多个结果。如果你想避免这种情况,那么你就要按电影分组。Jena有权拒绝这样的事情

select ?movie (str(?movie_title) as ?title) where { 
  ?movie :hasTitle ?movie_title
}
group by ?movie
因为
str(?电影标题)
没有意义。对于每一部
?电影
,实际上都有一组
?电影标题
s。你需要从那个集合中获得一个有代表性的标题。现在,它实际上看起来不像任何电影有一个以上的英文标题。您可以使用以下查询进行检查:

SELECT ?movie (count(?mTitle) as ?nTitles)
WHERE {
  ?movie a dbpedia-owl:Film ;
         rdfs:label ?mTitle .
  filter langMatches(lang(?mTitle),'en')
}
group by ?movie
having count(?mTitle) > 1 
鉴于此,这意味着您可以安全地
按?movie?movie_title
分组,这将允许您在投影变量列表中使用
?movie_title
。但是发布日期怎么办呢?原则上,你可能会得到不止一个这样的结果。事实上,正如您在本查询中所看到的,数据确实为您提供了不止一个:

select distinct count(?film) where {
?film rdf:type dbpedia-owl:Film.
}
SELECT DISTINCT ?movie (group_concat(?movie_year;separator=';') as ?years)
WHERE {
  ?movie rdf:type dbpedia-owl:Film.
  ?movie rdfs:label ?movie_title.
  FILTER langMatches(lang(?movie_title), 'en')
  optional { ?movie dbpprop:released   ?rel_year }
  optional { ?movie dbpedia-owl:releaseDate ?owl_year}
  optional { ?movie dcterms:subject ?sub.
             ?sub rdfs:label ?movie_year_sub
             filter regex(?movie_year_sub, ".*[0-9]{4}.*", "i")
           }
  BIND(COALESCE(?owl_year, ?rel_year, ?movie_year_sub) AS ?movie_year)
}
group by ?movie ?movie_title 
having count(?movie_year) > 1
limit 2000
这意味着您需要基于该集合获取一个值。SPARQL提供了一些函数来实现这一点(例如,
max
min
sum
)。在这种情况下,我不知道是否有一种简单的方法来选择“最佳”代表,因此您可能只想从中
sample
,向您提供如下查询:

SELECT DISTINCT ?movie (str(sample(?movie_year)) as ?year) ?movie_title
WHERE {
  ?movie rdf:type dbpedia-owl:Film.
  ?movie rdfs:label ?movie_title.
  FILTER langMatches(lang(?movie_title), 'en')
  optional { ?movie dbpprop:released   ?rel_year }
  optional { ?movie dbpedia-owl:releaseDate ?owl_year}
  optional { ?movie dcterms:subject ?sub.
             ?sub rdfs:label ?movie_year_sub
             filter regex(?movie_year_sub, ".*[0-9]{4}.*", "i")
           }
  BIND(COALESCE(?owl_year, ?rel_year, ?movie_year_sub) AS ?movie_year)
}
group by ?movie ?movie_title 
limit 2000


这是合法的SPARQL,由(一旦您提供了一些前缀定义)确认,因此Jena应该可以使用它,Virtuoso(在本例中,DBpedia端点)也接受它。

在这种情况下,数字是相同的,但是要计算不同的电影,您应该使用
选择(count(distinct?film)作为?nFilms),其中{…
。注意
的不同位置
;i、 例如,
select(count(distinct…
),而不是
select distinct(count(…
)“正如您在java代码中看到的那样…”我在问题中没有看到任何java代码。请将其添加到问题中。虽然您会得到这样一个整数(76000),但您会“错过”任何没有一个或多个您正在询问的指定属性的电影,或者如果值与筛选器不匹配。当然,有77794部电影,但是有那么多电影有特定的标题,有英文标题,并且与您的正则表达式匹配多年吗?谢谢Joshua。你完全正确。我该如何解决这个问题这个问题?我正在考虑一个简单的查询,使电影的联合与我创建的查询相匹配,或者只有rdf:type等于dbpedia owl:Film作为约束。你能给我建议一个好的方法来完成我的任务吗?你到底想要什么?每部电影的一年和一个标题?Appar发布日期信息以毫秒为单位。我想这代表了电影发布日期和1970年1月1日之间的时间。可能吗?@AlessandroSuglia不希望数据太干净。不是。你看了吗