簡體   English   中英

使用Apache Jena對DBpedia端點進行多次查詢以獲取電影信息

[英]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

SPARQL結果

新查詢后更新

您發布的查詢不適用於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為您提供了一些功能(例如maxminsum )。 在這種情況下,我不知道是否有一種簡單的方法來選擇“最佳”代表,因此您可能只想從中進行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,由sparql.org驗證程序確認(一旦您提供了一些前綴定義),因此Jena應該可以使用它,Virtuoso(在這種情況下為DBpedia端點)也可以接受它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM