[英]Multiple query on DBpedia endpoint for movie information retrieval using Apache Jena
我正在嘗試使用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代碼中看到的,我將變量(偏移量)增加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
使用按規范分組,藝術鑒賞端點使我能夠獲得沒有重復行的正確結果集。 相反,當我嘗試使用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
但是,如果這樣做,當擁有多個英文電影標題,發行年份等時,您將獲得多個結果。如果要避免這種情況,則希望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
)。 在這種情況下,我不知道是否有一種簡單的方法來選擇“最佳”代表,因此您可能只想從中進行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驗證程序確認(一旦您提供了一些前綴定義),因此Jena應該可以使用它,Virtuoso(在這種情況下為DBpedia端點)也可以接受它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.