我试图下载一些电影'使用Apache Jena并查询DBpedia公共端点的信息(生产年份和标题)。 我已经知道公共端点有一些安全限制,因此它不会授予使用在结果集中返回超过2000行的查询。 出于这个原因,我尝试使用LIMIT和OFFSET选项在多个查询中细分我的查询并使用Java程序(http://ideone.com/xF0GCE)我将它们保存在格式化的特定文件中方式:
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);
}
这是我用来检索我需要的信息的查询:
SELECT DISTINCT ?movie (str(?movie_title) as ?title) (str(?movie_year) as ?year) WHERE { ?movie rdf:type dbpedia-owl:Film.
?movie rdfs:label ?movie_title.
?movie dcterms:subject ?cat .
?cat rdfs:label ?movie_year .
FILTER langMatches(lang(?movie_title), "EN") .
FILTER regex(?movie_year, "^[0-9]{4} ", "i")
} limit 2000 offset $specific_offset
正如您在java代码中看到的,我将变量(offset)增加2000以获取正确的结果集分区。
运行初步查询,我发现使用此查询,DBpedia中不同影片的总数为77794:
select distinct count(?film) where {
?film rdf:type dbpedia-owl:Film.
}
问题在于,如果我计算获得的节点数量,则等于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
使用按规范分组,virtuoso端点让我得到没有重复行的正确结果集。 相反,当我尝试使用Apache Jena运行查询时,我无法执行它,因为我收到以下错误:
com.hp.hpl.jena.query.QueryParseException: Non-group key variable in SELECT: ?movie_year in expression str(?movie_year)
答案 0 :(得分:1)
除了满足您原始查询的电影外,还有更多的电影,而您的查询并不一定只计算每部电影一次。 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:释放的值非常奇怪,但我不知道它们对你有多大用处。
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
如果你这样做,当你有多个英文电影片,发行年份等时,你会得到多个结果。如果你想避免这种情况,那么你想要group by ?movie
。耶拿有权拒绝像
select ?movie (str(?movie_title) as ?title) where {
?movie :hasTitle ?movie_title
}
group by ?movie
因为str(?movie_title)
没有意义。对于每个?movie
,您实际上是一组?movie_title
。您需要从该集合中获得代表性的标题。现在,它实际上看起来并不像任何一部电影都有多个英文标题。您可以查看以下查询:
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
鉴于此,这意味着您可以放心group by ?movie ?movie_title
,这样您就可以在投影变量列表中使用?movie_title
。但是如何处理发布日期呢?原则上,你最终可能会得到不止一个。事实上,正如您在此查询中看到的那样,数据确实为您提供了多个数据:
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
)。在这种情况下,我不知道是否有一种简单的方法可以选择最好的&#34;代表,所以你可能只想从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,由sparql.org validator确认(一旦你提供了一些前缀定义),所以Jena应该没问题,而Virtuoso(在这种情况下,DBpedia端点)也接受它。 / p>