Java 基于apachejena的电影信息检索DBpedia端点的多查询
我试图使用ApacheJena下载一些电影的信息(制作年份和标题),并查询DBpedia公共端点。 我已经知道公共端点有一些安全限制,因此它不允许使用返回结果集中超过2000行的查询。 出于这个原因,我尝试使用LIMIT和OFFSET选项将我的查询细分为多个查询,并使用Java程序()将它们以格式化的方式保存在特定的文件中: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
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不希望数据太干净。不是。你看了吗