diff --git a/lod/tutorial/css/github.css b/lod/tutorial/css/github.css new file mode 100644 index 0000000..aa5280b --- /dev/null +++ b/lod/tutorial/css/github.css @@ -0,0 +1,61 @@ +.highlight { padding-top: 0; margin: 0;} +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { color: #000000; font-weight: bold } /* Keyword */ +.highlight .o { color: #000000; font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { color: #000000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #000000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d01040 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nl { color: #990000; font-weight: bold } /* Name.Label */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d01040 } /* Literal.String.Backtick */ +.highlight .sc { color: #d01040 } /* Literal.String.Char */ +.highlight .sd { color: #d01040 } /* Literal.String.Doc */ +.highlight .s2 { color: #d01040 } /* Literal.String.Double */ +.highlight .se { color: #d01040 } /* Literal.String.Escape */ +.highlight .sh { color: #d01040 } /* Literal.String.Heredoc */ +.highlight .si { color: #d01040 } /* Literal.String.Interpol */ +.highlight .sx { color: #d01040 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d01040 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/lod/tutorial/css/style.css b/lod/tutorial/css/style.css new file mode 100644 index 0000000..458f98f --- /dev/null +++ b/lod/tutorial/css/style.css @@ -0,0 +1,968 @@ +@media screen { + + body { + font-family: 'Quattrocento', Verdana, sans-serif; + font-size:16px; + background-color:#ffffff; + } + + .container { + max-width: 48rem; + overflow: hidden; + text-overflow: ellipsis; + } + + +/* ============================================================================= +Helper classes +========================================================================== */ + + .noclear { + clear:none; + } + + .expanded { + max-width: 58rem; + } + + .garnish { + width: 23%; + padding:0; + } + + .full-width { + width:80%; + margin: 0 auto; + text-align:center; + } + + .float-right { + float:right; + margin-left: 1rem; + margin-bottom: 1rem; + } + + .float-left { + margin-right: 1rem; + margin-bottom: 1rem; + } + + +/* ============================================================================= +Home Page +========================================================================== */ + + .home-block { + padding:3rem 0; + color:#666; + } + + .home-block h2 { + margin:0; + font-size:2.8rem; + color:#333; + text-align:center; + } + + .home-block p { + margin:0rem; + font-family:'Open Sans'; + font-size:1.2rem; + padding-top:2rem; + text-align:justify; + } + + .home-block a:visited { + color: #38c; + } + + .home-stripe-1 { + color:#eee; + background:#27b; + } + + .home-stripe-1 h2, .home-stripe-2 h2 { + color:#fff; + } + + .home-stripe-1 a:visited, .home-stripe-1 a:link { + color:#6bf; + } + + .home-stripe-2 { + color:#fff; + background:#289; + } + + .home-stripe-2 a:visited, .home-stripe-2 a:link { + color:#6cd; + } + + .home-image { + width: 75%; + } + + .home-logo img { + width: 200px; + } + + .home-logo a h1 { + color: #fff; + } + + .home-logo { + color: #fff; + } + + .home-logo li { + font-size: 1.2rem; + } + + .en-back { + background-color: #444444; + } + + .es-back { + background-color: #535D7F; + } + + .fr-back { + background-color: #3D7C81; + } + + .pt-back { + background-color: #d6b664; + } + + + .sitewide-alert { + position: relative; + margin-bottom: 0; + } + +/* ============================================================================= +Lesson Headers +========================================================================== */ + + header { + margin:-3rem 0 3rem 0; + padding:0; + font-family:'Roboto', sans-serif; + color:#ccc; + background: #efefef; + border-top:1px solid #333; + border-bottom:1px solid #333; + text-align:left; + } + + header .container-fluid { + margin:0; + padding:1rem; + background: #f5f5f5; + } + + header h1 { + margin:0; + padding:0; + font-size:1.8rem; + text-align:left; + } + + header h2 { + font-family:'Roboto', sans-serif; + font-size:1.2rem; + color:#333; + margin: 1.5rem 0 1.5rem 0rem; + text-align:left; + } + + header h3, header h4 { + font: .9rem/1.1rem 'Roboto Condensed', sans-serif; + text-transform:uppercase; + font-variant:small-caps; + letter-spacing:80%; + color:#666; + margin:.3rem 0 0 0; + padding:0; + } + + header h4 { + display:inline; + margin:0; + line-height:1.3rem; + } + + header .header-image { + float:left; + border:.2rem solid gray; + margin:0; + padding:0; + max-width: 200px; + } + + header .header-abstract { + font: 1rem/1.4rem 'Roboto', sans-serif; + color:#666; + margin:1rem 0; + } + + header .header-helpers { + clear:both; + background:#ccc; + color:#fff; + border-top:1px solid #999; + border-bottom:1px solid #999; + } + + header ul { + margin:0; + padding:0; + list-style-type: none; + } + + header li, header .metarow { + font: .9rem/1.1rem 'Roboto Condensed'; + } + + header .metarow { + color:#999; + } + + header .peer-review, header .open-license { + font-size: 0.9rem; + color: #666; + margin: 0; + } + +/* ============================================================================= +Lessons Index +========================================================================== */ + +/***************** + FILTER BUTTONS +******************/ + ul.filter, ul.sort-by { + margin: 0 0 1rem 0; + padding: 0px; + text-align:center; + } + + li.filter, + li.sort, + #filter-none { + font: .9rem/1.1rem 'Open Sans', sans-serif; + padding: .4rem .6rem; + border:none; + border-radius: 3px; + display:inline-block; + text-transform:uppercase; + text-decoration: none; + } + + .filter li:hover, + .sort-by li:hover, + #filter-none:hover { + cursor: pointer; + } + + .activities li.current:hover, + .filter li.current:hover, + .sort-by li.current:hover { + cursor:default; + } + + .topic li a { + text-decoration: none; + } + + .activities li { + background-color:#38c; + color:#fff; + } + + .activities li:hover { + background-color:#16a; + } + + .activities li.current { + background-color:#059; + } + + .topics li { + background-color:#eee; + color: #38a; + } + + .topics li:hover { + background-color:#ccc; + } + + .topics li.current { + background-color:#aaa; + color: #333; + } + + + #filter-none { + width:99.5%; + clear:both; + text-align:center; + margin-bottom:1rem; + background-color:#fefefe; + color:#666; + border:1px solid #999; + } + + #filter-none:hover { + background-color:#ededed; + } + + /***************** + SEARCH + *****************/ + + .search-input { + width:55%; + clear:both; + margin-bottom:1rem; + background-color:#fefefe; + color:#666; + border:1px solid #999; + font: .9rem/1.1rem 'Open Sans', + sans-serif; + padding: .4rem .6rem; + border-radius: 3px; + display:inline-block; + text-transform:uppercase; + text-decoration: none; + } + + #search-button, + #enable-search-button { + background-color: #efefef; + color: rgb(153, 143, 143); + width: 35%; + font: .9rem/1.1rem 'Open Sans', + sans-serif; + padding: .4rem .6rem; + border: none; + border-radius: 3px; + display: inline-block; + text-transform: uppercase; + text-decoration: none; + } + + @media only screen and (max-width: 767px) { + /* phones */ + #search-button, + #enable-search-button { + width: 80%; + } + } + + + #search-info-button { + padding: 0.5rem; + color: rgb(153, 143, 143); + } + + #search-info { + display: none; + height:0px; + background:#efefef; + overflow:hidden; + transition:0.5s; + -webkit-transition:0.5s; + width: 100%; + text-align: left; + box-sizing: border-box; + } + + #search-info.visible { + display: block; + height: fit-content; + height: -moz-max-content; + padding: 10px; + margin-top: 10px; + } + + /***************** + SORT BUTTONS + *****************/ + + li.sort { + background-color: #efefef; + color:#666; + width:49.5%; + } + + li.sort:hover { + text-decoration: none; + background-color:#cecece; + } + + #current-sort { + font-size:75%; + } + + .sort.my-desc:after, .sort-desc:after { + width: 0; + height: 0; + border-left: .4rem solid transparent; + border-right: .4rem solid transparent; + border-top: .4rem solid; + content:""; + position: relative; + top:.75rem; + right:-.3rem; + } + + .sort.my-asc:after, .sort-asc:after { + width: 0; + height: 0; + border-left: .4rem solid transparent; + border-right: .4rem solid transparent; + border-bottom: .4rem solid; + content:""; + position: relative; + bottom:.75rem; + right:-.3rem; + } + + .sort-desc:after { + top:1rem; + } + + .sort-asc:after { + bottom:1rem; + } + + /***************************** + LESSON INDEX RESULTS LIST + *****************************/ + + h2.results-title { + margin:1rem 0; + font: 1.6rem/2rem 'Roboto Condensed'; + color:#666; + text-transform:uppercase; + } + + #results-value { + color:#000; + } + + + #lesson-list .list ul { + margin:0; + padding:0; + } + + #lesson-list .list li { + list-style-type:none; + margin:0; + } + + + .lesson-description { + margin-bottom:2rem; + padding:0rem; + min-height:120px; + text-align:left; + } + + .lesson-description img { + width:100%; + } + + .lesson-image { + width:120px; + float:left; + margin-right:1rem; + } + + .above-title { + margin:0 0 .2rem 0; + font: .8rem/1rem 'Roboto Condensed'; + color:#999; + text-transform:uppercase; + clear:none; + } + + .lesson-description h2.title { + font: 1.2rem/1.3rem 'Crete Round', serif; + margin:0 0 .8rem 0; + clear:none; + } + + .list .date, + .lesson-description .activity, + .lesson-description .topics, + .lesson-description .difficulty { + display: none; + } + + #pre-loader { + visibility: hidden; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + width: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 9999; + transition: opacity 0.3s linear; + background: rgba(211, 211, 211, 0.8); + } +/* ============================================================================= +Top Navigation Bar +========================================================================== */ + + .navbar { + padding: .6rem 1rem; + margin: 0 0 3rem 0; + } + + .navbar-dark .navbar-nav .nav-link { + font-family:'Open Sans'; + text-transform:uppercase; + color:#fff; + font-size:.9rem; + } + + .btn-group > .btn-secondary { + border-color: #333333; + background-color: #888888; + } + + .lang { + text-transform:lowercase !important; + } + + .navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-brand:hover { + color:#39a; + } + + .navbar-toggler-icon { + background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255,255,255, 1)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E"); + } + + .navbar-collapse { + text-align:center; + } + + .navbar-dark .navbar-brand { + font-family:'Crete Round', serif; + color:#fff; + letter-spacing: .02em; + } + + .btn-group > a.btn { + padding-left: 1rem; + padding-right: 1rem; + } + + a.dropdown-item { + border-bottom:1px solid #ccc; + font-family:'Roboto'; + } + + .dropdown-menu { + position: absolute; + background: #fff; + border: 1px solid #ccc; + margin:0; + padding:0; + } + + .dropdown-menu a { + font-size:.8rem; + line-height:2rem; + text-transform:uppercase; + } + + .dropdown-menu a:last-child { + border-bottom:none; + } + + .dropdown-menu:after, .dropdown-menu:before { + bottom: 100%; + left: 20%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + } + + .dropdown-menu:after { + border-color: rgba(255, 255, 255, 0); + border-bottom-color: #fff; + border-width: 12px; + margin-left: -12px; + } + .dropdown-menu:before { + border-color: rgba(51, 153, 170, 0); + border-bottom-color: #ccc; + border-width: 13px; + margin-left: -13px; + } + + .navbar-dark .navbar-nav .nav-link:focus { + color: #ccc; + } + + .header-link { + position: absolute; + right: 0.6em; + opacity: 0; + -webkit-transition: opacity 0.2s ease-in-out 0.1s; + -moz-transition: opacity 0.2s ease-in-out 0.1s; + -ms-transition: opacity 0.2s ease-in-out 0.1s; + } + + h2:hover .header-link, + h3:hover .header-link, + h4:hover .header-link, + h5:hover .header-link, + h6:hover .header-link { + opacity: 1; + } + +/* ============================================================================= +Lesson Typography +========================================================================== */ + + a {text-decoration:none;} + + a:link {color: #38c;} + a:visited {color: #39a;} + a:hover {color: #555;} + a:active {color: #555;} + + b, strong { font-weight: bold; } + + blockquote { margin: 1em 2em; padding: 0 1em 0 1em; font-style: italic; border:1px solid #666; background: #eeeeee;} + + hr { + display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 2em 0; padding: 0; } + + img { + max-width:100%; + } + + ins { background: #ff9; color: #000; text-decoration: none; } + + + h1,h2,h3,h4,h5 { + font-family:'Crete Round', serif; + font-weight:normal; + clear:both; + } + + + h1 { + font-size:2rem; + margin-bottom:1.5rem; + letter-spacing:-.03rem; + text-align:center; + } + + h2 { + font-size:1.6rem; + margin-top:3rem; + letter-spacing:-.02rem; + } + + h3 { + font-size:1.4rem; + margin-top:2.5rem; + } + + h4 { + font-size:1.2rem; + margin-top:1.8rem; + } + + h5 { + font-size:1.0rem; + margin-top:1.4rem; + } + + h1 a, h2 a, h3 a, h4 a, h5 a { + text-decoration:none; + } + + h1 a:link { color: #38c; } + h1 a:visited {color: #39a; } + + + /* select button generated by codeblocks.js */ + .fa-align-left {opacity: 0.2;} + .highlight:hover .fa-align-left {opacity: 1;} + + q { quotes: none; } + q:before, q:after { content: ""; content: none; } + + small { font-size: 85%; } + + /* Position subscript and superscript content without affecting line-height: h5bp.com/k */ + sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; } + sup { top: -0.5em; } + sub { bottom: -0.25em; } + + li { + margin-bottom:.5rem; + line-height:1.4rem; + } + + li.nav-item { + margin-bottom:0; + } + + .alert { + font-family: 'Roboto'; + } + + .alert h2, .alert h3, .alert h4 { + margin-top:0; + } + + +/* ============================================================================= +Code Highlighting +========================================================================== */ + + code { + font-family: monospace, serif; + font-size:.9rem; + } + + .highlight { + margin: 1rem 0 1rem 0; + padding:.5rem .2rem; + font-size:.9rem; + white-space: pre; + word-wrap: normal; + overflow: auto; + border: 1px solid #eee; + background: #fafafa; + } + + +/* ============================================================================= +Figures +========================================================================== */ + + figure { + margin: 0 auto .5rem; + text-align: center; + display:table; + } + + figcaption { + margin-top:.5rem; + font-family:'Open Sans'; + font-size:0.8em; + color: #666; + display:block; + caption-side: bottom; + } + + .author-info, .citation-info { + border-top:1px solid #333; + padding-top:1rem; + margin-top:2rem; + } + + .author-name, .suggested-citation-header { + font-family:'Roboto Condensed'; + font-weight: 600; + font-size:1.2rem; + color: #666; + text-transform:uppercase; + } + + .author-description p, .suggested-citation-text p { + font-size:0.9rem; + font-family:'Open Sans'; + color: #666; + } + + /* ============================================================================= + Tables + ========================================================================== */ + + table { + width: 100%; + margin-bottom: 1em; + } + + th, td { + padding: 10px; + text-align: left; + border-bottom: 1px solid #ddd; + } + + thead { + background-color: #535353; + color: #fff; + font-weight: bold; + } + + tr:nth-child(even) {background-color: #f2f2f2} + +/* ============================================================================= +Blog Index and Layout +========================================================================== */ + + .blog-header { + text-align:center; + } + + .blog-header h2 { + margin:0; + line-height: 2rem; + } + + .blog-header h3 { /*author*/ + margin-top:.4rem; + color: #666; + font-size:1rem; + } + + .blog-header h4{ + color: #999; + font-size:1rem; + margin-bottom:.2rem; + font-family:'Roboto Condensed'; + text-transform:uppercase; + } + + .blog-header figure { + max-width:80%; + } + + .blog-header figcaption { + text-align: center; + } + + .blog-page-header { + margin-bottom:3rem; + } + +/* ============================================================================= +Project Team +========================================================================== */ + + .contact-box { + margin-bottom:3rem; + } + +/* ============================================================================= +Footer +========================================================================== */ + + footer[role="contentinfo"] { + margin-top: 2rem; + padding: 2rem 0; + font-family:'Open Sans'; + font-size:.9rem; + color: #fff; + background-color:#666; + text-align:center; + } + + footer a, footer a:link, footer a:visited { + color: #fff; + border-bottom:1px #eee dotted; + } + + footer a:hover { + text-decoration: none; + border-bottom:1px #fff solid; + } + + footer .fa { + margin: 0 .2rem 0rem 0rem; + } + + .footer-head { + font-size:1.1rem; + line-height:1.4rem; + margin-bottom:1rem; + } + + +} /* end screen */ + +@media only screen and (max-width: 768px) { + .garnish { + display:none; + } + .dropdown-menu:after, .dropdown-menu:before { + display:none; + } +} + +/* Print Styling */ + +@media screen { + /* Class to hide elements only shown when printing */ + .hide-print { + display: none !important; + } +} + +@media print { + * { background: transparent !important; color: black !important; box-shadow:none !important; text-shadow: none !important; filter:none !important; -ms-filter: none !important; } /* Black prints faster: h5bp.com/s */ + a, a:visited { text-decoration: underline; } + a[href]:after { content: " (" attr(href) ")"; } + abbr[title]:after { content: " (" attr(title) ")"; } + a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */ + pre, blockquote { + border: 1px solid #999; + page-break-inside: avoid; + margin: 0.5cm; + padding: 0.5cm + } + thead { display: table-header-group; } /* h5bp.com/t */ + tr, img { page-break-inside: avoid; } + img { max-width: 100% !important; } + @page { + margin: 1.5cm; + } + + body { font-size: 0.85rem;} + p, h2, h3 { orphans: 3; widows: 3; } + h1, h2, h3 { page-break-after: avoid; } + h1 { font-size: 1.4rem; } + h2 { font-size: 1.1rem; } + h3 { font-size: 1rem; } + h4 { font-size: 0.9rem; } + .header-bottom { + margin-bottom: 2rem; + page-break-after: always; + } + .hide-screen { + /* Hide elements that only appear on screen */ + display: none !important; + } + + .print-header { + /* format navbar for print */ + display: block; + z-index:1030; + width: 100%; + height: 3rem; + padding: .6rem 1rem; + margin-bottom: 1rem; + color:#fff; + white-space: nowrap; + font-family: 'Crete Round', serif; + border-bottom: 1px solid lightgrey; + } +} diff --git a/lod/tutorial/en/lessons/retired/graph-databases-and-SPARQL.html b/lod/tutorial/en/lessons/retired/graph-databases-and-SPARQL.html new file mode 100644 index 0000000..8035aff --- /dev/null +++ b/lod/tutorial/en/lessons/retired/graph-databases-and-SPARQL.html @@ -0,0 +1,1527 @@ + + + + + + + + + + + + + + + + + + + + + + + Using SPARQL to access Linked Open Data | Programming Historian + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+
+ Pisces symbol of two linked fish +
+
+ +
+ + +
+

+ + + +Matthew Lincoln ORCID id icon

+
+ +
+

This lesson explains why many cultural institutions are adopting graph databases, and how researchers can access these data though the query language called SPARQL.

+ +
+ +
+
+ + + + + +
+
+
+ +
+
+
+ + +
+
+ + +
+ +
+
+

edited by

+
    + + +
  • Fred Gibbs
  • + +
+
+ +
+

reviewed by

+
    + + +
  • Patrick Murray-John +
  • + + +
  • Jason Heppler +
  • + + +
  • Will Hanley +
  • + +
+
+ + + + + + +
+
+
+
+ +
+
+
+
+

published

2015-11-24 +
+ + +
+

retired

+
+ +
+

difficulty

+ +Medium + +
+ +
+

DOI id icon https://doi.org/10.46430/phen0047

+ +
+
+
+
+ +
+ +
+ + + +
+

Great Open Access tutorials cost money to produce. Join the growing number of people supporting The Programming Historian so we can continue to share knowledge free of charge.

+
+ + + + + +
+ + Available in: + + EN + (original) | + + + + ES + + + +
+ + + + + + + +
+

This lesson has been retired

+

What does this mean?

+

The Programming Historian editors do their best to maintain lessons as minor issues inevitably arise. However, since publication, changes to either the underlying technologies or principles used by this lesson have been substantial, to the point where the editors have decided not to further update it. The lesson may still prove a useful learning tool and a snapshot into the techniques of digital history when it was published, but we cannot guarantee all elements will continue to work as intended.

+

+ +

Why was this lesson retired?

+

The British Museum has failed to maintain their collections database in a consistent and reliably-accessible manner. Although the SPARQL syntax and commands remain correct, the URLs they attempt to connect to have become too unreliable to use in a working lesson.

+

+ +
+ + + + + + + +
+

Lesson Goals

+ +

This lesson explains why many cultural institutions are adopting graph +databases, and how researchers can access these data though the query language +called SPARQL.

+ +

Contents

+ + + +

Graph Databases, RDF, and Linked Open Data

+ +

Many cultural institutions now offer access to their collections information +through web Application Programming Interfaces. While these APIs are a +powerful way to access individual records in a machine-readable manner, they are +not ideal for cultural heritage data because they are structured to work for a +predetermined set of queries. For example, a museum may have information on +donors, artists, artworks, exhibitions, and provenance, but its web API may +offer only object-wise retrieval, making it difficult or impossible to search +for associated data about donors, artists, provenance, etc. This structure is +great if you come looking for information about particular objects. However, it +makes it difficult to aggregate information about every artist or donor that +happens to be described in the dataset as well.

+ +

RDF databases are well-suited to expressing complex relationships between many +entities, like people, places, events, and concepts tied to individual +objects. These databases are often referred to as “graph” databases because they +structure information as a graph or network, where a set of resources, or nodes, +are connected together by edges that describe the relationships between each +resource.

+ +

Because RDF databases support the use of URLs (weblinks), they can be made +available online and linked to other databases, hence the term “Linked Open +Data”. Major art collections including the British Museum, Europeana, +the Smithsonian American Art Museum, and the Yale Center for +British Art have published their collections data as LOD. The Getty +Vocabulary Program, has also released their series of authoritative +databases on geographic place names, terms for describing art and architecture, +and variant spellings of artist names, as LOD.

+ +

SPARQL is the language used to query these databases. This language is +particularly powerful because it does not presuppose the perspectives that users +will bring to the data. A query about objects and a query about donors is +basically equivalent to such a database. Unfortunately, many tutorials on SPARQL +use extremely simplified data models that don’t resemble the more complex +datasets released by cultural heritage institutions. This tutorial gives a crash +course on SPARQL using a dataset that a humanist might actually find in the +wilds of the Internet. In this tutorial, we will learn how to query the British +Museum Linked Open Data collection.

+ +

RDF in brief

+ +

RDF represents information in a series of three-part “statements” that comprise +a subject, predicate, and an object, e.g.:

+ +
<The Nightwatch> <was created by> <Rembrandt van Rijn> .
+
+ +

(Note that just like any good sentence, they each have a period at the end.)

+ +

Here, the subject <The Nightwatch> and the object <Rembrandt van Rijn> can +be thought of as two nodes of the graph, with the predicate <was created by> +defining an edge between them. (Technically, <was created by> can, in other +queries, be treated as an object or subject itself, but that is beyond the scope +of this tutorial.)

+ +

A pseudo-RDF database might contain interrelated statements like these:

+ +
...
+<The Nightwatch> <was created by> <Rembrandt van Rijn> .
+<The Nightwatch> <was created in> <1642> .
+<The Nightwatch> <has medium> <oil on canvas> .
+<Rembrandt van Rijn> <was born in> <1606> .
+<Rembrandt van Rijn> <has nationality> <Dutch> .
+<Johannes Vermeer> <has nationality> <Dutch> .
+<Woman with a Balance> <was created by> <Johannes Vermeer> .
+<Woman with a Balance> <has medium> <oil on canvas> .
+...
+
+ +

If we were to visualize these statements as nodes and edges within network +graph, it would appear like so:

+ +
+ A network visualization of the pseudo-RDF shown above. Arrows indicate the 'direction' of the predicate. For example, that 'Woman with a Balance was created by Vermeer', and not the other way around. +
+

A network visualization of the pseudo-RDF shown above. Arrows indicate the ‘direction’ of the predicate. For example, that ‘Woman with a Balance was created by Vermeer’, and not the other way around.

+ +
+
+ +

A traditional relational database might split attributes about artworks and +attributes about artists into separate tables. In an RDF/graph database, all +these data points belong to the same interconnected graph, which allows users +maximum flexibility in deciding how they wish to query it.

+ +

Searching RDF with SPARQL

+ +

SPARQL lets us translate heavily interlinked, graph data into normalized, +tabular data with rows and columns you can open in programs like Excel, or +import into a visualization suite such as plot.ly or +Palladio.

+ +

It is useful to think of a SPARQL query as a Mad +Lib - a set of sentences with blanks in +them. The database will take this query and find every set of matching +statements that correctly fill in those blanks, returning the matching values to +us as a table. Take this SPARQL query:

+ +
SELECT ?painting
+WHERE {
+  ?painting <has medium> <oil on canvas> .
+}
+
+ +

?painting in this query stands in for the node (or nodes) that the database +will return. On receiving this query, the database will search for all values of +?painting that properly complete the RDF statement <has medium> <oil on +canvas> .:

+ +
+ A visualization of what our query is looking for. +
+

A visualization of what our query is looking for.

+ +
+
+ +

When the query runs against the full database, it looks for the subjects, +predicates, and objects that match this statement, while excluding the rest of +the data:

+ +
+ A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red. +
+

A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red.

+ +
+
+ +

And our results might look like this table:

+ + + + + + + + + + + + + + + +
painting
The Nightwatch
Woman with a Balance
+ +

What makes RDF and SPARQL powerful is the ability to create complex queries that +reference many variables at a time. For example, we could search our pseudo-RDF +database for paintings by any artist who is Dutch:

+ +
SELECT ?artist ?painting
+WHERE {
+  ?artist <has nationality> <Dutch> .
+  ?painting <was created by> ?artist .
+}
+
+ +

Here we’ve introduced a second variable, ?artist. The RDF database will return +all matching combinations of ?artist and ?painting that fulfill both of +these statements.

+ +
+ A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red. +
+

A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red.

+ +
+
+ + + + + + + + + + + + + + + + + + +
artistpainting
Rembrandt van RijnThe Nightwatch
Johannes VermeerWoman with a Balance
+ +

URIs and Literals

+ +

So far, we have been looking at a toy representation of RDF that uses +easy-to-read text. However, RDF is primarily stored as URIs (Uniform Resource +Identifiers) that separate conceptual entities from their plain-English (or +other language!) labels. (Note that a URL, or Uniform Resource Locator, is a URI +for a resource that is accessible on the web) In real RDF, our original +statement:

+ +
<The Nightwatch>   <was created by>   <Rembrandt van Rijn> .
+
+ +

would more likely look something like this:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/creator>  <http://dbpedia.org/resource/Rembrandt>.
+
+ +

N.B. the Rijksmuseum has not (yet) built their own Linked Data site, so the URI in this query is just for demo purposes.

+ +

In order to get the human-readable version of the information represented by +each of these URIs, what we’re really doing is just retrieving more RDF +statements. Even the predicate in that statement has its own literal label:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/title> "The Nightwatch" .
+
+<http://purl.org/dc/terms/creator> <http://www.w3.org/1999/02/22-rdf-syntax-ns#label> "was created by" .
+
+<http://dbpedia.org/resource/Rembrandt> <http://xmlns.com/foaf/0.1/name> "Rembrandt van Rijn" .
+
+ +

You will notice that, unlike the URIs in the query that are surrounded by <>, +the objects of these statements are just strings of text within quotation +marks, known as literals. Literals are unlike URIs in that they represent +values, rather than references. For example, +<http://dbpedia.org/resource/Rembrandt> represents an entity that may +reference (and be referenced by) any number of other statements (say, birth +dates, students, or family members), while the text string "Rembrandt van +Rijn" stands only for itself. Literals do not point to other nodes in the +graph, and they can only ever be objects in an RDF statement. Other literal +values in RDF include dates and numbers.

+ +

See the predicates in these statements, with domain names like purl.org, +w3.org, and xmlns.com? These are some of the many providers of ontologies +that help standardize the way we describe relationships between bits of +information like “title”, “label”, “creator”, or “name”. The more RDF/LOD that +you work with, the more of these providers you’ll find.

+ +

URIs can become unwieldy when composing SPARQL queries, which is why we’ll +use prefixes. These are shortcuts that allow us to skip typing out entire long +URIs. For example, remember that predicate for retrieving the title of the +Nightwatch, <http://purl.org/dc/terms/title>? With these prefixes, we just +need to type dct:title whenever we need to use a purl.org predicate. dct: +stands in for http://purl.org/dc/terms/, and title just gets pasted onto the +end of this link.

+ +

For example, with the prefix PREFIX rkm: <http://data.rijksmuseum.nl/>, +appended to the start of our SPARQL query, +<http://data.rijksmuseum.nl/item/8909812347> becomes rkm:item/8909812347 +instead.

+ +

Be aware that, prefixes +can be arbitrarily assigned with whatever abbreviations you like, different +endpoints may use slightly different prefixes for the same namespace (e.g. dct +vs. dcterms for <http://purl.org/dc/terms/>).

+ +

Terms to review

+ +
    +
  • SPARQL - Protocol and RDF Query Language - The language used to query RDF graph databases
  • +
  • RDF - Resource Description Framework - A method for structuring data as a graph or network of connected statements, rather than a series of tables.
  • +
  • LOD - Linked Open Data - LOD is RDF data published online with dedicated URIs in such a manner than developers can reliably reference it.
  • +
  • statement - Sometimes also called a “triple”, an RDF statement is a quantum of knowledge comprising a subject, predicate, and object.
  • +
  • URI - Uniform Resource Identifier - a string of characters for identifying a resource. RDF statements use URIs to link various resources together. A URL, or uniform resource locator, is a type of URI that points to resources on the web.
  • +
  • literal - Some objects in RDF statements do not refer to other resources with a URI, but instead convey a value, such as text ("Rembrandt van Rijn"), a number (5), or a date (1606-06-15). These are known as literals.
  • +
  • prefix - In order to simplify SPARQL queries, a user may specify prefixes that act as abbreviations for full URIs. These abbreviations, or QNames, are also used in namespaced XML documents.
  • +
+ +

Real-world queries

+ +

All the statements for one object

+ +

Let’s start our first query using the British Museum SPARQL endpoint. A +SPARQL endpoint is a web address that accepts SPARQL queries and returns +results. The BM endpoint is like many others: if you navigate to it in a web +browser, it presents you with a text box for composing queries.

+ +
+ The BM SPARQL endpoint webpage. For all the queries in this tutorial, make sure that you have left the 'Include inferred' and 'Expand results over equivalent URIs' boxes unchecked. +
+

The BM SPARQL endpoint webpage. For all the queries in this tutorial, make sure that you have left the ‘Include inferred’ and ‘Expand results over equivalent URIs’ boxes unchecked.

+ +
+
+ +

When starting to explore a new RDF database, it helps to look at the +relationships that stem from a single example +object.

+ +

(For each of the following queries, click on the “Run query” link below to see +the results. You can then run it as +is, or modify it before requesting the results. Remember when editing the query +before running to uncheck the ‘Include inferred’ box.)

+ +
SELECT ?p ?o
+WHERE {
+  <http://collection.britishmuseum.org/id/object/PPA82633> ?p ?o .
+}
+
+ +

Run query

+ +

By calling SELECT ?p ?o we’re asking the database to return the values of ?p +and ?o as described in the WHERE {} command. This query returns every +statement for which our example artwork, +<http://collection.britishmuseum.org/id/object/PPA82633>, is the subject. ?p +is in the middle position of the RDF statement in the WHERE {} command, so it +returns any predicates matching this statement, while ?o in the final position +returns all objects. Though I have named them ?p and ?o here, as you will +see below we can name these variables anything we like. Indeed, it will be +useful to give them meaningful names for the complex queries that follow!.

+ +
+ An initial list of all the predicates and objects associated with one artwork in the British Museum. +
+

An initial list of all the predicates and objects associated with one artwork in the British Museum.

+ +
+
+ +

Note: depending on how the British Museum has configured their SPARQL endpoint when you read this lesson, instead of seeing “prefixed” versions of the URLs (e.g. thes:8577) you may instead see the full version http://collection.britishmuseum.org/id/thesauri/x8577. As noted in the discussion of prefixes above, this still represents the same URI.

+ +

The BM endpoint formats the results table with hyperlinks for every variable +that is itself an RDF node, so by clicking on any one of these links you can +shift to seeing all the predicates and objects for that newly-selected node. +Note that BM automatically includes a wide range of SPARQL prefixes in its +queries, so you will find many hyperlinks are displayed in their abbreviated +versions; if you mouse over them your browser will display their unabbreviated +URIs.

+ +
+ Visualizing a handful of the nodes returned by the first query to the BM. Elements in this graph that are also in the table of results above are colored red. Additional levels in the hierarchy are included as a preview of how this single print connects to the larger BM graph. +
+

Visualizing a handful of the nodes returned by the first query to the BM. Elements in this graph that are also in the table of results above are colored red. Additional levels in the hierarchy are included as a preview of how this single print connects to the larger BM graph.

+ +
+
+ +

Let’s find out how they store the object type information: look for the +predicate <bmo:PX_object_type> (highlighted in the figure above) and click on +the link for thes:x8577 to navigate to the node describing the particular +object type “print”:

+ +
+ The resource page for `thes:x8577` ('print') in the British Museum LOD. +
+

The resource page for thes:x8577 (‘print’) in the British Museum LOD.

+ +
+
+ +

You’ll note how this node has an plain-text label, as well as ties to related +artwork type nodes within the database.

+ +

Complex queries

+ +

To find other objects of the same type with the preferred label “print”, we can +call this query:

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+
+SELECT ?object
+WHERE {
+
+  # Search for all values of ?object that have a given "object type"
+  ?object bmo:PX_object_type ?object_type .
+
+  # That object type should have the label "print"
+  ?object_type skos:prefLabel "print" .
+}
+LIMIT 10
+
+ +

Run query / See a user-generated query

+ +
+ A one-column table returned by our query for every object with type 'print' +
+

A one-column table returned by our query for every object with type ‘print’

+ +
+
+ +

Remember that, because "print" here is a literal, we enclose it within +quotation marks in our query. When you include literals in a SPARQL query, the +database will only return exact matches for those values.

+ +

Note that, because ?object_type is not present in the SELECT command, it +will not show up in the results table. However, it is essential to structuring +our query, because it connects the dots from ?object to the label "print".

+ +

FILTER

+ +

In the previous query, our SPARQL query searched for an exact match for the +object type with the text label “print”. However, often we want to match literal +values that fall within a certain range, such as dates. For this, we’ll use the +FILTER command.

+ +

To find URIs for all the prints in the BM created between 1580 and 1600, we’ll +need to first figure out where the database stores dates in relationship to the +object node, and then add references to those dates in our query. Similar to the +way that we followed a single link to determine an object type, we must hop +through several nodes to find the production dates associated with a given +object:

+ +
+ Visualizing part of the British Museum's data model where production dates are connected to objects. +
+

Visualizing part of the British Museum’s data model where production dates are connected to objects.

+ +
+
+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+# Return object links and creation date
+SELECT ?object ?date
+WHERE {
+
+  # We'll use our previous command to search only for
+  # objects of type "print"
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel "print" .
+
+  # We need to link though several nodes to find the
+  # creation date associated with an object
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+
+  # As you can see, we need to connect quite a few dots
+  # to get to the date node! Now that we have it, we can
+  # filter our results. Because we are filtering by date,
+  # we must attach the tag ^^xsd:date after our date strings.
+  # This tag tells the database to interpret the string
+  # "1580-01-01" as the date 1 January 1580.
+
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+
+ +

Run query

+ +
+ All BM prints made between 1580 and 1600 +
+

All BM prints made between 1580 and 1600

+ +
+
+ +

Aggregation

+ +

So far we have only used the SELECT command to return a table of objects. +However, SPARQL allows us to do more advanced analysis such as grouping, +counting, and sorting.

+ +

Say we would like to keep looking at objects made between 1580 and 1600, but we +want to understand how many objects of each type the BM has in its collections. +Instead of limiting our results to objects of type “print”, we will instead use +COUNT to tally our search results by type.

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+SELECT ?type (COUNT(?type) as ?n)
+WHERE {
+  # We still need to indicate the ?object_type variable,
+  # however we will not require it to match "print" this time
+
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel ?type .
+
+  # Once again, we will also filter by date
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+# The GROUP BY command designates the variable to tally by,
+# and the ORDER BY DESC() command sorts the results by
+# descending number.
+GROUP BY ?type
+ORDER BY DESC(?n)
+
+ +

Run query

+ +
+ Counts of objects by type produced between 1580 and 1600. +
+

Counts of objects by type produced between 1580 and 1600.

+ +
+
+ +

Linking multiple SPARQL endpoints

+ +
2018-06-13: Unfortunately, Europeana has removed the ability to link to external SPARQL endpoints using `SERVICE` queries, so the query in this section can no longer be run. The text below will be retained as-is for reference purposes, and may be updated if and when Europeana again allows `SERVICE` queries.
+ +

Up until now, we have constructed queries that look for patterns in one dataset +alone. In the ideal world envisioned by Linked Open Data advocates, multiple +databases can be interlinked to allow very complex queries dependent on +knowledge present in different locations. However, this is easier said than +done, and many endpoints (the BM’s included) do not yet reference outside +authorities.

+ +

One endpoint that does, however, is +Europeana’s. They have created links +between the objects in their database and records about individuals in +DBPedia and VIAF, places in +GeoNames, and concepts in the Getty Art & +Architecture thesaurus. SPARQL allows you to insert SERVICE statements that +instruct the database to “phone a friend” and run a portion of the query on +an outside dataset, using the results to complete the query on the local +dataset. While this lesson will go into the data models in Europeana and DBpedia in depth, the following query illustrates how a SELECT statement works. You may run it yourself by copying and pasting the query text into the Europeana endpoint.

+ +
PREFIX edm:    <http://www.europeana.eu/schemas/edm/>
+PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX dbo:    <http://dbpedia.org/ontology/>
+PREFIX dbr:    <http://dbpedia.org/resource/>
+PREFIX rdaGr2: <http://rdvocab.info/ElementsGr2/>
+
+# Find all ?object related by some ?property to an ?agent born in a
+# ?dutch_city
+SELECT ?object ?property ?agent ?dutch_city
+WHERE {
+    ?proxy ?property ?agent .
+    ?proxy ore:proxyFor ?object .
+
+    ?agent rdf:type edm:Agent .
+    ?agent rdaGr2:placeOfBirth ?dutch_city .
+
+    # ?dutch_city is defined by having "Netherlands" as its broader
+    # country in DBpedia. The SERVICE statement asks
+    # http://dbpdeia.org/sparql which cities have the country
+    # "Netherlands". The answers to that sub-query will then be
+    # used to finish off our original query about objects in the
+    # Europeana database
+
+    SERVICE <http://dbpedia.org/sparql> {
+        ?dutch_city dbo:country dbr:Netherlands .
+   }
+}
+# This query can potentially return a lot of objects, so let's
+# just request the first 100 in order to speed up the search
+LIMIT 100
+
+ +
+ Visualizing the query sequence of the above SPARQL request +
+

Visualizing the query sequence of the above SPARQL request

+ +
+
+ +

An interlinked query like this means that we can ask Europeana questions about +its objects that rely on information about geography (what cities are in the +Netherlands?) that Europeana does not need to store and maintain itself. In the +future, more cultural LOD will hopefully link to authority databases like the +Getty’s Union List of Artist Names, allowing, for example, the British Museum to +outsource biographical data to the more complete resources at the Getty.

+ +

Working with SPARQL results

+ +

Having constructed and run a query… what do we do with the results? Many +endpoints offer, like the British Museum, a web-based browser that returns +human-readable results. However, SPARQL endpoints are designed to return +structured data to be used by other programs.

+ +

Export results to CSV

+ +

In the top right corner of the results page for the BM endpoint, you will find +links for both JSON and XML downloads. Other endpoints may also offer the +option for a CSV/TSV download, however this option is not always available. The +JSON and XML output from a SPARQL endpoint contain not only the values returned +from the SELECT statement, but also additional metadata about variable types +and languages.

+ +

Parsing the XML verson of this output may be done with a tool like Beautiful +Soup (see its Programming Historian +lesson) or Open +Refine. To quickly convert JSON results from a SPARQL +endpoint into a tabular format, I recommend the free command line utility +jq. (For a tutorial on using command +line programs, see “Introduction to the Bash Command +Line”.) The following query will convert the +special JSON RDF format into a CSV file, which you may load into your preferred +program for further analysis and visualization:

+ +
jq -r '.head.vars as $fields | ($fields | @csv), (.results.bindings[] | [.[$fields[]].value] | @csv)' sparql.json > sparql.csv
+
+ +

Export results to Palladio

+ +

The popular data exploration platform Palladio can directly load data from a +SPARQL endpoint. On the “Create a new project” screen, a link at the bottom to +“Load data from a SPARQL endpoint (beta)” will provide you a field to enter the +endpoint address, and a box for the query itself. Depending on the endpoint, you +may need to specify the file output type in the endpoint address; for example, +to load data from the BM endpoint you must use the address +http://collection.britishmuseum.org/sparql.json. Try pasting in the +aggregation query we used above to count artworks by type and clicking on “Run +query”. Palladio should display a preview table.

+ +
+ Palladio's SPARQL query interface. +
+

Palladio’s SPARQL query interface.

+ +
+
+ +

After previewing the data returned by the endpoint, click on the “Load data” +button at the bottom of the screen to begin manipulating it. (See this +Programming Historian +lesson +for a more in-depth tutorial on Palladio.) For example, we might make a query +that returns links to the images of prints made between 1580 and +1600, +and render that data as a grid of images sorted by date:

+ +
+ A gallery of images with a timeline of their creation dates generated using Palladio. +
+

A gallery of images with a timeline of their creation dates generated using Palladio.

+ +
+
+ +

Note that Palladio is designed to work with relatively small amounts of data (on +the order of hundreds or thousands of rows, not tens of thousands), so you may +have to use the LIMIT command that we used when querying the Europeana +endpoint to reduce the number of results that you get back, just to keep the +software from freezing.

+ +

Further reading

+ +

In this tutorial we got a look at the structure of LOD as well as a real-life +example of how to write SPARQL queries for the British Museum’s database. You +also learned how to use aggregation commands in SPARQL to group, count, and sort +results rather than simply list them.

+ +

There are even more ways to modify these queries, such as introducing OR and +UNION statements (for describing conditional queries), and CONSTRUCT +statements (for inferring new links based on defined rules), full-text +searching, or doing other mathematical operations more complex than counting. +For a more complete rundown of the commands available in SPARQL, see these +links:

+ + + +

Both the Europeana and Getty Vocabularies LOD sites also offer extensive, and +quite complex example queries which can be good sources for understanding how to +search their data:

+ + + +
+ + + + + + + + + +
+
About the author
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Matthew Lincoln is the digital humanities developer at Carnegie Mellon University, and an art historian of early modern Europe. + ORCID id icon

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + +
+ + + + +
Suggested Citation
+
+

+ + + +Matthew Lincoln, + "Using SPARQL to access Linked Open Data," + The Programming Historian 4 (2015), + https://doi.org/10.46430/phen0047.

+
+
+ + + +
+

Great Open Access tutorials cost money to produce. Join the growing number of people supporting The Programming Historian so we can continue to share knowledge free of charge.

+
+ + + +
+ + + + + + + + + + + + + +
+ + + diff --git a/lod/tutorial/es/lecciones/retirada/sparql-datos-abiertos-enlazados.html b/lod/tutorial/es/lecciones/retirada/sparql-datos-abiertos-enlazados.html new file mode 100644 index 0000000..71e2370 --- /dev/null +++ b/lod/tutorial/es/lecciones/retirada/sparql-datos-abiertos-enlazados.html @@ -0,0 +1,1377 @@ + + + + + + + + + + + + + + + + + + + + + + + Uso de SPARQL para acceder a datos abiertos enlazados + | Programming Historian + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+
+ Grabado con dos peces unidos por una rama en sus bocas. +
+
+ +
+ + +
+

+ + + +Matthew Lincoln ORCID id icon

+
+ +
+

Esta lección explica por qué numerosas instituciones culturales están adoptando bases de datos orientadas a grafos y cómo los investigadores pueden acceder a estos datos a través de consultas realizadas en el lenguaje llamado SPARQL.

+ +
+ +
+ +
+
+ +
+
+
+ + +
+
+ + +
+ +
+
+

editado por

+
    + + +
  • Fred Gibbs
  • + +
+
+ +
+

revisado por

+
    + + +
  • Patrick Murray-John +
  • + + +
  • Jason Heppler +
  • + + +
  • Will Hanley +
  • + + +
  • Fred Gibbs +
  • + +
+
+ + +
+

traducido por

+
    + + +
  • Nuria Rodríguez Ortega
  • + +
+
+ + + +
+

traducción editada por

+
    + + +
  • Antonio Rojas Castro + ORCID id icon
  • + +
+
+ + + +
+

traducción revisada por

+
    + + +
  • Antonio Rojas Castro + ORCID id icon
  • + + +
  • Juan Antonio Pastor Sánchez
  • + +
+
+ +
+
+
+
+ +
+
+
+
+

publicado

2015-11-24 +
+ +
+

traducido

2017-05-20 +
+ + +
+

retirada

+
+ +
+

dificultad

+ +Medio + +
+ +
+

DOI id icon https://doi.org/10.46430/phes0027

+ +
+
+
+
+ +
+ +
+ + + +

¡Haz una donación!

+

Producir buenos tutoriales de acceso abierto cuesta dinero. Únete al creciente número de personas que apoya a The Programming Historian para que podamos continuar compartiendo conocimientos de forma gratuita.

+
+ + + + + +
+ + Disponible en: + + EN + (original) | + + + + ES + + + +
+ + + + + + + +
+

Esta lección ha sido retirada

+

¿Qué significa esto?

+

Los editores de The Programming Historian hacen todo lo posible para mantener las lecciones a medida que surgen inevitablemente problemas menores. Sin embargo, desde la publicación, los cambios en las tecnologías subyacentes o los principios utilizados en esta lección han sido sustanciales, hasta el punto de que los editores han decidido no actualizarla más. Es posible que la lección siga siendo una herramienta de aprendizaje útil y una instantánea de las técnicas de la historia digital cuando se publicó, pero no podemos garantizar que todos los elementos sigan funcionando como estaba previsto.

+

+ +

¿Por qué ha sido retirada?

+

El Museo Británico no ha mantenido el acceso a su base de datos de colecciones de una manera consistente. Aunque la sintaxis y los comandos de SPARQL siguen siendo correctos, las URLs a las que intentan conectarse son ahora demasiado inconsistentes para su uso en una lección funcional.

+

+ +
+ + + + + + + +
+

Objetivos de la lección

+ +

Esta lección explica por qué numerosas instituciones culturales están adoptando bases de datos orientadas a grafos (graph databases) y cómo los investigadores pueden acceder a estos datos a través de consultas realizadas en el lenguaje llamado SPARQL.

+ +

Contenidos

+ + + +

Bases de datos orientadas a grafo, RDF y datos abiertos enlazados (Linked Open Data, LOD)

+ +

Actualmente, numerosas instituciones culturales están ofreciendo información sobre sus colecciones a través de las denominadas API (Application Programming Interfaces). Estas API son instrumentos muy eficaces para acceder de manera automatizada a registros individuales, sin embargo, no constituyen el procedimiento ideal cuando tratamos con datos culturales debido a que las API están estructuradas para trabajar con un conjunto predeterminado de consultas (queries). Por ejemplo, un museo puede tener información sobre donantes, artistas, obras de arte, exposiciones, procedencia de sus obras (provenance), etc., pero su API puede ofrecer solo una recuperación orientada a objetos, haciendo difícil o imposible buscar datos relacionados con donantes, artistas, etc. Así pues, esta estructura es interesante si el objetivo es buscar información sobre objetos particulares; sin embargo, puede complicar la operación de agregar información sobre los artistas o donantes que también se encuentran registrados en la base de datos.

+ +

Las bases de datos RDF son muy apropiadas para expresar relaciones complejas entre múltiples entidades, como personas, lugares, eventos y conceptos ligados a objetos individuales. Estas bases de datos se denominan habitualmente bases de datos orientadas a grafos (graph databases) porque estructuran la información como un grafo o red, donde un conjunto de recursos o nodos están conectados entre sí mediante aristas (o enlaces) que describen las relaciones establecidas entre dichos recursos y/o nodos.

+ +

Dado que las bases de datos RDF admiten el uso de URL, estas pueden estar accesibles online y también pueden enlazarse a otras bases de datos, de ahí el término “datos abiertos enlazados” (Linked Open Data, LOD). Importantes colecciones artísticas, entre las que se incluyen las del British Museum, Europeana, el Smithsonian American Art Museum y el Yale Center for British Art, han publicado sus colecciones de datos como LOD. El Getty Vocabulary Program también ha publicado sus vocabularios controlados (TGN, ULAN y AAT) como LOD.

+ +

SPARQL es el lenguaje utilizado para interrogar este tipo de bases de datos. Este lenguaje es particularmente potente porque obvia las perspectivas que los usuarios transfieren a los datos. Una consulta sobre objetos y una consulta sobre donantes son prácticamente equivalentes en estas bases de datos. Lamentablemente, numerosos tutoriales sobre SPARQL utilizan modelos de datos tan extremadamente simplificados que no son operativos cuando se trata de utilizar las complejas bases de datos desarrolladas por las instituciones culturales. Este tutorial ofrece un curso intensivo sobre SPARQL utilizando un conjunto de datos (dataset) que un humanista podría realmente encontrar en Internet. En concreto, en este tutorial aprenderemos cómo interrogar la colección LOD del British Museum.

+ +

RDF en pocas palabras

+ +

RDF representa la información en una declaración triple -también llamada tripleta- que sigue la estructura sujeto-predicado-objeto. Por ejemplo:

+ +
<La ronda de noche> <fue creada por> <Rembrandt van Rijn> .
+
+
+ +

(Observa que, como toda buena oración, estas declaraciones terminan con un punto y final).

+ +

En este ejemplo, el sujeto <La ronda de noche> y el objeto <Rembrandt van Rijn> pueden ser considerados como dos nodos de un grafo, donde el predicado <fue creada por> define la arista -o relación- entre ellos. (Técnicamente, puede ser tratado en otras consultas como un objeto o un sujeto, pero esta cuestión escapa el alcance de este tutorial).

+ +

Una seudobase de datos RDF podría contener declaraciones interrelacionadas entre sí, como las siguientes:

+ +
...
+<La ronda de noche> <fue creada por> <Rembrandt van Rijn>.
+<La ronda de noche> <fue creada en> <1642>.
+<La ronda de noche> <utiliza la técnica de> <óleo sobre lienzo>.
+<Rembrandt van Rijn> <nació en> <1606>.
+<Rembrandt van Rijn> <es de nacionalidad> <holandesa>.
+<Johannes Vermeer> <es de nacionalidad> <holandesa>.
+<La tasadora de perlas> <fue creada por> <Johannes Vermeer>.
+<La tasadora de peras> <utiliza la técnica de> <óleo sobre lienzo>.
+...
+
+ +

Si visualizásemos estas declaraciones como nodos y aristas de un grafo o red, la representación sería como sigue:

+ +
+ Visualización en red del seudoRDF mostrado más arriba. Las flechas indican la 'dirección' del predicado. Por ejemplo, que '*La tasadora de perlas* fue creada por Vermeer' y no al revés. Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización en red del seudoRDF mostrado más arriba. Las flechas indican la ‘dirección’ del predicado. Por ejemplo, que ‘La tasadora de perlas fue creada por Vermeer’ y no al revés. Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ +

Las tradicionales bases de datos relacionales pueden distribuir atributos sobre obras de arte y artistas en tablas separadas. En las bases de datos RDF u orientadas a grafos, todos estos datos pertenencen a un mismo mismo grafo interconectado, lo que permite a los usuarios una mayor flexibilidad a la hora de decidir cómo quieren interrogar estos recursos.

+ +

Buscando RDF con SPARQL

+ +

SPARQL nos permite traducir datos en grafo, intensamente enlazados, en datos normalizados en formato tabular, esto es, distribuidos en filas y columnas, que se pueden abrir en programas como Excel o importar a programas de visualización, tales como plot.ly o Palladio.

+ +

Resulta útil pensar las consultas SPARQL como un Mad Lib -un conjunto de oraciones con espacios en blanco-. La base de datos tomará esta consulta y encontrará cada conjunto de oraciones que encaje correctamente en estos espacios en blanco, devolviéndonos los valores coincidentes como una tabla. Veamos esta consulta SPARQL:

+ +
SELECT ?pintura
+WHERE {
+	?pintura <utiliza la técnica de> <óleo sobre lienzo> .
+}
+
+ +

En este consulta, ?pintura representa el nodo (o nodos) que la bases de datos nos devolverá. Una vez recibida la consulta, la base de datos buscará todos los valores para ?pintura que adecuadamente complete la declaración RDF <utiliza la técnica de> <óleo sobre lienzo>.

+ +
+ Visualización de lo que nuestra consulta está buscando. Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización de lo que nuestra consulta está buscando. Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ +

Cuando la consulta interroga la base de datos completa, esta busca los sujetos, predicados y objetos que coinciden con esta declaración, exluyendo, al mismo tiempo, el resto de datos.

+ +
+ Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que nos serán devueltos en los resultados) en rojo. Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que nos serán devueltos en los resultados) en rojo. Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ +

Nuestros resultados podrían tener este aspecto:

+ + + + + + + + + + + + + + + +
pinturas
La ronda de noche
La tasadora de perlas
+ +

Ahora bien, lo que hace a RDF y a SPARQL herramientas tan potentes es su habilidad para crear consultas complejas que referencian múltiples variables al mismo tiempo. Por ejemplo, podríamos buscar en nuestra seudobase de datos RDF pinturas creadas por cualquier artista que fuese holandés:

+ +
SELECT ?artista ?pintura
+WHERE {
+	?artista <es de nacionalidad> <holandesa> .
+	?pintura <fue creada por> ?artista .
+	}
+
+ +

En este ejemplo, hemos introducido una segunda variable: ?artista. La base de datos RDF devolverá todas las combinaciones conincidentes de ?artista y ?pintura que encajen en ambas declaraciones.

+ +
+ Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que serán recuperados en los resultados en rojo). Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que serán recuperados en los resultados en rojo). Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ + + + + + + + + + + + + + + + + + +
artistaspinturas
Rembrandt van RijnLa ronda de noche
Johannes VermeerLa tasadora de perlas
+ +

URI y literales

+ +

Hasta ahora, hemos visto una representación facticia de RDF que utiliza un texto fácil de leer. Sin embargo, RDF se almacena principalmente en formato URI (Uniform Resource Identifiers), que separa las entidades conceptuales de sus etiquetas lingüísticas. (Ten en cuenta que una URL, o Uniform Resource Locator, es una URI accesible desde la web). En RDF real, nuestra declaración original:

+ +
<La ronda de noche> <fue creada por> <Rembrandt van  Rijn>.
+
+ +

sería más parecido a lo siguiente:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/creator> <http://dbpedia.org/resource/Rembrandt> .
+
+ +

N.B. el Rijksmuseum todavía no ha desarrollado su propio sitio LOD, por lo que en esta consulta la URI responde únicamente a objetivos de demostración.

+ +

A fin de obtener una versión legible desde el punto de vista humano de la información representada por cada una de estas URI, lo que hacemos realmente es recuperar más declaraciones RDF. Incluso el predicado en esta declaración tiene su propia etiqueta literal:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/title> "La ronda de noche".
+<http://purl.dc.terms/creator> <http://www.w3.org/1999/02/22-rdf-syntax-ns#label> "fue creado por".
+<http://dbpedia.org/resource/Rembrandt> <http://xmlns.com/foaf/0.1/name> "Rembrandt van Rijn".
+
+ +

Como se puede observar, a diferencia de las URI que en esta consulta están enmarcadas por los signos <>, los objetos son cadenas de texto entrecomilladas. Esto es lo que se conoce como literales (literals). Los literales representan valores, mientras que las URI representan referencias. Por ejemplo, <http://dbpedia.org/resources/Rembrandt> representa una entidad que puede referenciar (y puede ser referenciada por) muchas otras declaraciones (fechas de nacimiento, discípulos, miembros de la familia, etc.), mientras que la cadena de texto "Rembrandt van Rijn" solo se representa a sí misma. Otros valores literales en RDF incluyen fechas y números.

+ +

Fijémenos ahora en los predicados de estas declaraciones, con nombres de dominio como purl.org, w3.org y xmlns.com. Estos son algunos de los numerosos proveedores de ontologías que ayudan a estandarizar el modo en que describimos relaciones entre bits de información como, “título”, “etiqueta”, “creador” o “nombre”. Cuanto más trabajemos con RDF/LOD, más proveedores de este tipo encontraremos.

+ +

Las URI pueden llegar a ser difíciles de manejar cuando se componen consultas SPARQL. Para simplificar este proceso se utilizan los prefijos (prefixes). Los prefijos son atajos que nos liberan de tener que escribir toda la larga cadena de caracteres que constituye una URI. Por ejemplo, recordemos el predicado para recuperar el título de La ronda de noche, http://purl.org/dc/terms/title>. Con los siguientes prefijos, solo necesitamos escribir dct:title cuando queramos utilizar un predicado purl.org. dct: representa la cadena completa http://purl.org.dc/terms, y 'title' simplemente se agrega al final de este enlace.

+ +

Por ejemplo, con el prefijo PREFIX rkm: que representa la cadena completa <http//data.rijksmuseum.nl>, agregado al inicio de nuestra consulta SPARQL, http://data.rijksmuseum.nl/item/8909812347 < se convierte en rkm:item/8909812347.

+ +

Debemos ser conscientes de que los prefijos se pueden asignar arbitrariamente a cualquier abreviatura que queramos; así, diferentes puntos de entrada (endpoints) pueden utilizar prefijos ligeramente diferentes para el mismo espacio de nombre (namespace) (por ejemplo: dct vs. dcterms para <http://purl.org/dc/terms>).

+ +

Términos para revisar

+ +
    +
  • SPARQL - Protocol and RDF Query Language - El lenguaje utilizado para interrogar bases de datos RDF u orientadas a grafos.
  • +
  • RDF - Resource Description Framework - Un método para estructurar datos en forma de grafo o como una red de declaraciones conectadas más que como una serie de tablas.
  • +
  • LOD - Linked Open Data (datos abiertos enlazados) - LOD son datos RDF publicados online en formato URI de modo que los desarrolladores pueden referenciarlos de manera fiable y sin ambigüedad.
  • +
  • declaración - a veces denominada “tripleta”, una declaración RDF es una unidad de conocimiento que comprende sujeto, predicado y objeto.
  • +
  • URI - Uniform Resource Identifier - una cadena de caracteres que identifica un recurso. Las declaraciones RDF utilizan URI para enlazar varios recursos. Una URL, o Uniform Resource Locator, es un tipo de URI que apunta a un determinado recurso en la web.
  • +
  • literal - En las declaraciones RDF, algunos objetos no referencian recursos con una URI sino que vehiculan un valor, que puede ser un texto ("Rembrandt van Rijn"), un número (5) o una fecha (1606-06-15). Estos objetos se conocen como literales.
  • +
  • prefijo - A fin de simplificar las consultas SPARQL, un usuario puede especificar prefijos que funcionan como abreviaturas de las URI completas. Estas abreviaturas, o QNAmes, se utilizan también en los espacios de nombre (namespaces) de los documentos XML.
  • +
+ +

Consultas basadas en casos reales

+ +

Todas las declaraciones para un objeto

+ +

Vamos a empezar nuestra primera consulta utilizando el punto de entrada SPARQL del British Museum. Un punto de entrada SPARQL es una dirección web que acepta consultas SPARQL y devuelve resultados. El punto de entrada del British Museum funciona como muchos otros: cuando accedemos a él a través de un navegador web, encontramos una caja de texto para componer las consultas.

+ +
+ Web del punto de entrada SPARQL del British Museum. Para todas las consultas de este tutorial, hay que asegurarse de haber dejado las casillas 'Include inferred' y 'Expand results over equivalent URIs' sin marcar. +
+

Web del punto de entrada SPARQL del British Museum. Para todas las consultas de este tutorial, hay que asegurarse de haber dejado las casillas ‘Include inferred’ y ‘Expand results over equivalent URIs’ sin marcar.

+ +
+
+ +

Cuando empezamos a explorar una nueva base de datos RDF, resulta últil examinar, a modo de ejemplo, las relaciones que emanan de un objeto en concreto.

+ +

(Para cada una de las siguientes consultas, clica en el enlace “Run query” situado más abajo para ver los resultados. La puedes ejecutar tal y como está o modificarla antes. En este último caso, recuerda que es necesario dejar sin marcar la casilla “Include inferred” antes de ejecutar la consulta).

+ +
SELECT ?p ?o
+WHERE {
+	<http://collection.britishmuseum.org/id/object/PPA82633> ?p ?o .
+}
+
+ +

Run query

+ +

Con la orden SELECT ?p ?o, le estamos diciendo a la base de datos que nos devuelva los valores de ?p y ?o descritos en el comando WHERE {}. Esta consulta devuelve cada declaración para la cual nuestra obra de arte seleccionada, <http://collection.britishmuseum.org/id/object/PPA82633>, es el sujeto. ?p ocupa la posición central en la declaración RDF en el comando WHERE {}, por lo que esta devuelve cualquier predicado que coincide con la declaración, mientras que ?o, en la posición final, devuelve todos los objetos. Aunque yo las he nombrado como ?p y ?o, en realidad, tal y como se puede ver en el ejemplo inferior, es posible nombrar estas variables del modo que nosotros queramos. De hecho, será útil darles nombres significativos para las consultas complejas que siguen a continuación.

+ +
+ Listado inicial de todos los predicados y objetos asociados con una obra de arte en el British Museum. +
+

Listado inicial de todos los predicados y objetos asociados con una obra de arte en el British Museum.

+ +
+
+ +

El punto de entrada del Britism Museum formatea la tabla de resultados con enlaces para cada una de las variables, que son, en realidad, nodos RDF, por lo que clicando en cada uno de estos enlaces podemos ver todos los predicados y objetos para cada uno de los nodos seleccionados. Advierte que el British Musuem incluye automáticamente un amplio rango de prefijos SPARQL en sus consultas, por lo que encontraremos numerosos enlaces mostrados en su versión abreviada; si pasamos el ratón sobre ellos, podremos ver las URI sin abreviar.

+ +
+ Visualización del conjunto de nodos recuperados a través de la primera consulta realizada a la base de datos del British Museum. Los elementos de este grafo coloreados en rojo se encuentran también en la tabla de resultados mostrada más arriba. Se han incluido niveles adicionales en la jerarquía para mostrar cómo esta obra en particular se encuentra conectada en el grafo general que constituye la base de datos del BM. +
+

Visualización del conjunto de nodos recuperados a través de la primera consulta realizada a la base de datos del British Museum. Los elementos de este grafo coloreados en rojo se encuentran también en la tabla de resultados mostrada más arriba. Se han incluido niveles adicionales en la jerarquía para mostrar cómo esta obra en particular se encuentra conectada en el grafo general que constituye la base de datos del BM.

+ +
+
+ +

Veamos ahora cómo se almacena la información de tipo objeto: busca el predicado <bmo:PX_object_type> (marcado en la tabla anterior) y clica en el enlace thes:x8577 para acceder al nodo que describe el tipo de objeto “print” (grabado).

+ +
+ Página del recurso `thes:x8577` ('print') en el conjunto de datos enlazados del British Museum. +
+

Página del recurso thes:x8577 (‘print’) en el conjunto de datos enlazados del British Museum.

+ +
+
+ +

Como se puede observar, este nodo tiene una etiqueta (label) en texto plano, así como enlaces a nodos del tipo “objetos artísticos” con los que se relaciona en el conjunto de la base de datos.

+ +

Consultas complejas

+ +

Para encontrar otros objetos del mismo tipo descritos con la etiqueta “print”, podemos invocar esta consulta:

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+
+SELECT ?object
+WHERE {
+
+  # Busca todos los valores de ?object que tengan un "object type" dado
+  ?object bmo:PX_object_type ?object_type .
+
+  # El "object type" debería tener la etiqueta "print"
+  ?object_type skos:prefLabel "print" .
+}
+LIMIT 10
+
+ +

Run query / User-generated query

+ +
+ Tabla resultantes de nuestra consulta para todos los objetos del tipo 'print'. +
+

Tabla resultantes de nuestra consulta para todos los objetos del tipo ‘print’.

+ +
+
+ +

Recuerda que, dado que "print" funciona aquí como un literal, lo escribimos entrecomillado en nuestra consulta. Cuando se incluyen literales en las consultas SPARQL, la base de datos solo devuelve coincidencias exactas para estos valores.

+ +

Advierte también que, dado que ?object_type no se encuentra presente en el comando SELECT, este no se mostrará en la tabla de resultados. Sin embargo, resulta esencial estructurar nuestra consulta, porque es esto lo que permite conectar los puntos desde ?object con la etiqueta "print".

+ +

FILTER

+ +

En los ejemplos anteriores, nuestra consulta SPARQL ha buscado una coincidencia exacta para el tipo de objeto con la etiqueta “print”. Sin embargo, con frecuencia querremos encontrar valores literales que caen dentro de un determinado rango, como son las fechas. Para ello utilizaremos el comando FILTER.

+ +

Para localizar las URI de todos los grabados presentes en la base de datos del British Museum creados entre 1580 y 1600, necesitaremos, en primer lugar, averiguar dónde se almacenan en la base de datos las fechas en relación con los objetos, y entonces añadir referencias a estas fechas en nuestra consulta. De manera similar al procedimiento que hemos seguido de un único enlace para determinar un tipo de objeto, debemos ahora movernos a través de diversos nodos para encontrar las fechas de producción asociadas a un objeto dado:

+ +
+ Visualización de la parte del modelo de datos del British Museum donde las fechas de producción están conectadas a los objetos. +
+

Visualización de la parte del modelo de datos del British Museum donde las fechas de producción están conectadas a los objetos.

+ +
+
+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+# Recupera enlaces de objetos y fechas de creación
+SELECT ?object ?date
+WHERE {
+
+  # Utilizaremos nuestro comando previo para buscar solo
+  # objetos del tipo "print"
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel "print" .
+
+  # Necesitamos enlazar diversos nodos para encontrar la
+  # fecha de creación asociada con un objeto
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+
+  # Como se ve, es necesario conectar unos cuantos pocos de puntos
+  # para llegar al nodo de la fecha. Ahora que lo tehemos, podemos
+  # filtrar nuestros resultados. Dado que estamos filtrando por fecha,
+  # debemos agregar la etiqueta ^^xsd:date después de nuestra cadena de fecha.
+  # Esta etiqueta le dice a la base de datos que interprete la cadena
+  # "1580-01-01" como la fecha 1 de enero de 1580.
+
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+
+ +

Run query

+ +
+ Todos los grabados del British Museum realizados entre 1580-1600. +
+

Todos los grabados del British Museum realizados entre 1580-1600.

+ +
+
+ +

Agregación

+ +

Hasta ahora, solo hemos utilizado el comando SELECT para recuperar una tabla de objetos. Sin embargo, SPARQL nos permite realizar análisis muchos más avanzados, como agrupaciones, cálculos y clasificaciones.

+ +

Pongamos por caso que estuviésemos interesados en examinar los objetos realizados entre 1580 y 1600, pero que asimismo quisiésemos conocer cuántos objetos de cada tipo tiene el British Museum en su colección. En vez de limitar nuestros resultados a los objetos del tipo “print”, en este caso utilizaríamos el operador COUNT para sumar los resultados de nuestra búsqueda en función del tipo al que pertenezcan.

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+SELECT ?type (COUNT(?type) as ?n)
+WHERE {
+  # Es necesario que indiquemos la variable ?object_type,
+  # sin embargo, ahora no es necesario que esta coincida con el valor "print"
+
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel ?type .
+
+  # De nuevo, filtraremos por fecha
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+# El comando GROUP BY designa la variable que se sumará,
+# y el comando ORDER BY DESC() clasifica los resultados
+# en orden descedente.
+
+GROUP BY ?type
+ORDER BY DESC(?n)
+
+ +

Run query

+ +
+ Recuento de los objetos producidos entre 1580 y 1600 según el tipo al que pertenecen. +
+

Recuento de los objetos producidos entre 1580 y 1600 según el tipo al que pertenecen.

+ +
+
+ +

Enlazando múltiples puntos de entrada SPARQL

+ +
2018-06-13: Desafortunadamente, Europeana ha eliminado la opción de enlazar puntos de entrada externos por medio de consultas `SERVICE`, y, en consecuencia, esta sección ha dejado de funcionar. Mantenemos el texto que sigue porque creemos que puede tener valor como referencia y porque esperamos que el servicio de Europeana vuelva a estar operativo en el futuro.
+ +

Hasta ahora, hemos construido consultas que buscan patrones en un único conjunto de datos. Sin embargo, el escenario ideal al que aspiran los partidarios de LOD viene dado por la posibilidad de enlazar múltiples bases de datos, lo que permitirá realizar consultas mucho más complejas al estar estas basadas en el conocimiento distribuido que es posible extraer de diversos espacios web. No obstante, esto resulta más fácil de decir que de hacer, y muchos puntos de entrada (incluido el del British Museum) todavía no referencian recursos de autoridad externos.

+ +

Un punto de entrada que sí lo hace es el de Europeana. Europeana ha creado enlaces entre los objetos de sus bases de datos y los registros de personas en DBPedia y VIAF, los registros de lugares en GeoNames, y los conceptos resgistrados el Tesauro de Arte y Arquitectura (AAT) del Getty Research Institute. SPARQL nos permite insertar declaraciones SERVICE que ordenan a la base de datos “llamar a un amigo” y ejecutar una porción de la consulta en una base de datos externa, utilizando estos resultados para completar la consulta en la base de datos local. Si bien esta lección no se dentendrá en los modelos de datos de Europeana y DBPedia en profundidad, la siguiente consulta nos permite ver cómo funciona la declaración SELECT. Cada uno de los lectores puede ejecutarla por sí mismo copiando y pegando el texto de la consulta en el punto de entrada de Europeana. (A fin de que la consulta funcione, en el punto de entrada de Europeana se debe configurar el menú “Sponging” para “Retrieve remote RDF data for all missing source graphs”).

+ +
PREFIX ore:    <http://www.openarchives.org/ore/terms/>
+PREFIX edm:    <http://www.europeana.eu/schemas/edm/>
+PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX dbo:    <http://dbpedia.org/ontology/>
+PREFIX dbr:    <http://dbpedia.org/resource/>
+PREFIX rdaGr2: <http://rdvocab.info/ElementsGr2/>
+
+# Encuentra todos los ?object relacionados por alguna ?property con un ?agent nacido en una
+# ?dutch_city
+SELECT ?object ?property ?agent ?dutch_city
+WHERE {
+    ?proxy ?property ?agent .
+    ?proxy ore:proxyFor ?object .
+
+    ?agent rdf:type edm:Agent .
+    ?agent rdaGr2:placeOfBirth ?dutch_city .
+
+    # En DBPedia, ?dutch_city está definida por pertenecer al país "Netherlands"
+    # La declaración SERVICE pregunta a
+    # http://dbpdeia.org/sparql qué ciudades pertenecen al país
+    # "Netherlands". La respuesta obtenida de esta subconsulta se utilizará para
+    # completar nuestra consulta originaria sobre los objetos
+    # presentes en la base de datos de Europeana
+
+    SERVICE <http://dbpedia.org/sparql> {
+        ?dutch_city dbo:country dbr:Netherlands .
+   }
+}
+# Potencialmente, esta consulta puede devolvernos un elevado número de objetos, por lo que vamos
+# a solicitar solo los cien primeros a fin de agilizar la búsqueda
+LIMIT 100
+
+ +
+ Visualización de la secuencia de la consulta de la solicitud SPARQL definida más arriba. +
+

Visualización de la secuencia de la consulta de la solicitud SPARQL definida más arriba.

+ +
+
+ +

Una consulta interconectada como esta significa que podemos interrogar a Europeana sobre los objetos que cuentan con información geográfica (¿cuáles son las ciudades de Holanda?) sin necesidad de que Europeana tenga que almacenar y mantener esta información por sí misma. Es de esperar que, en el futuro, cada vez mayor cantidad de información LOD de carácter cultural esté enlazada con bases de datos autorizadas, como el ULAN (Union List of Artist Names) del Getty Research Institute. Esto permitirá, por ejemplo, que el British Museum “externalice” la información biográfica acudiendo a los recursos más completos del GRI.

+ +

Trabajando con resultados SPARQL

+ +

Una vez que hemos construido y ejecutado una consulta, ¿qué hacemos ahora con estos resultados? Muchos puntos de entrada, como el del British Museum, ofrecen un navegador web que devuelve resultados legibles para los humanos. Sin embargo, el objetivo de los puntos de entrada SPARQL (y para eso están diseñados) es devolver datos estructurados para ser utilizados por otros programas.

+ +

Exportar resultados en formato CSV

+ +

En la esquina superior derecha de la página de resultados del punto de entrada del BM, se encuentran enlaces para descargas en formato JSON y XML. Otros puntos de entrada también pueden ofrecer la opción de descargar los resultados en CSV/TSV; sin embargo, esta opción no siempre se encuentra disponible. Las salidas JSON y XML desde un punto de entrada SPARQL contienen no solo los valores devueltos por la declaración SELECT, sino también metadatos adicionales sobre tipos de variables e idiomas.

+ +

El procesamiento de la versión XML de los resultados se puede realizar con herramientas tales como Beautiful Soup (véase la lección correspondiente en The Programming Historian u OpenRefine). Para convertir rápidamente los resultados JSON desde un punto de entrada SPARQL en un formato tabular, yo recomiendo la utilidad de la línea de comando gratuita jg. (Para un tutorial sobre cómo utilizar programas de línea de comando, véase “Introduction to the Bash Command Line”). La siguiente consulta convertirá el formato especial JSON RDF en un fichero CSV, que podremos cargar en nuestro programa preferido para su posterior análisis y visualización:

+ +
jq -r '.head.vars as $fields | ($fields | @csv), (.results.bindings[] | [.[$fields[]].value] | @csv)' sparql.json > sparql.csv
+
+ +

Exportar resultados a Palladio

+ +

La popular plataforma de análisis de datos Palladio puede cargar directamente datos desde un punto de entrada SPARQL. En la parte inferior de la pantalla “Create a new project”, el enlace “Load data from a SPARQL endpoint (beta)” nos proporciona un campo para escribir la dirección del punto de entrada y una caja para la consulta propiamente dicha. Dependiendo del punto de entrada, podemos necesitar especifidar el tipo de fichero de salida en la dirección del punto de entrada; por ejemplo, para cargar datos desde el punto de entrada del British Museum, debemos utilizar la dirección http://collection.britishmuseum.org/sparql.json. Trata de pegar la consulta de agregación que utilizamos más arriba para el recuento de obras de arte según su tipología y clica en “Run query”. Palladio debería mostrar una tabla de previsualización como esta:

+ +
+ Interfaz de Palladio para las consultas SPARQL. +
+

Interfaz de Palladio para las consultas SPARQL.

+ +
+
+ +

Después de previsualizar los datos devueltos por el punto de entrada, clica en en botón “Load data” en la parte inferior de la pantalla para empezar a trabajar con ellos. (Véase esta lección de Programming Historian para un tutorial más detallado sobre Palladio). Por ejemplo, podríamos realizar una consulta que devuelva enlaces a las imágenes de los grabados realizados entre 1580 y 1600, y representar estos datos como una galería de imágenes clasificadas por fecha:

+ +
+ Galería de imágenes con línea de tiempo de sus fechas de creación generada utilizando Palladio. +
+

Galería de imágenes con línea de tiempo de sus fechas de creación generada utilizando Palladio.

+ +
+
+ +

Adviértase que Palladio está diseñado para funcionar con un conjunto relativamente pequeño de datos (del orden de cientos de miles de filas, no decenas de miles), por lo que pudiera ser necesario utilizar el comando LIMIT, que ya empleamos anteriormente en la consulta en el punto de entrada de Europeana, para reducir el número de resultados obtenidos y así evitar que el programa se quede bloqueado.

+ +

Lecturas adicionales

+ +

En este tutorial hemos examinado la estructura de LOD y hemos realizado un ejemplo real de cómo escribir consultas SPARQL para la base de datos del British Museum. También hemos aprendido cómo utilizar comandos de agregación en SPARQL para agrupar, contar y clasificar resultados más allá de la simple operación de listarlos.

+ +

Con todo, existen otras muchas maneras de modificar estas consultas, tales como introducir operadores OR y UNION (para describir consultas condicionales) y declaraciones CONSTRUCT (para inferir nuevos enlaces basados en reglas definidas), búsqueda de texto completo o llevar a cabo otras operaciones matemáticas más complejas que la del recuento. Para un informe más detallado de los comandos disponibles en SPARQL, véanse estos enlaces:

+ + + +

Tanto la web de Europeana como la del Getty Vocabularies ofrecen ejemplos extensos y bastante complejos de consultas que pueden constituir buenos recursos para comprender cómo buscar en sus datos:

+ + + +
+ + + + + + + + + +
+
Acerca del autor
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Matthew Lincoln es desarrollador de humanidades digitales en la Universidad Carnegie Mellon e historiador del arte de la Europa moderna. + ORCID id icon

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + +
+ + + + +
Cita sugerida
+
+

+ + + +Matthew Lincoln, + "Uso de SPARQL para acceder a datos abiertos enlazados", + traducido por + Nuria Rodríguez Ortega, + The Programming Historian en español 1 (2017), + https://doi.org/10.46430/phes0027.

+
+
+ + + +

¡Haz una donación!

+

Producir buenos tutoriales de acceso abierto cuesta dinero. Únete al creciente número de personas que apoya a The Programming Historian para que podamos continuar compartiendo conocimientos de forma gratuita.

+
+ + + +
+ + + + + + + + + + + + + +
+ + + diff --git a/lod/tutorial/gallery/graph-databases-and-SPARQL.png b/lod/tutorial/gallery/graph-databases-and-SPARQL.png new file mode 100644 index 0000000..f42fd1e Binary files /dev/null and b/lod/tutorial/gallery/graph-databases-and-SPARQL.png differ diff --git a/lod/tutorial/graph-databases-and-SPARQL.html b/lod/tutorial/graph-databases-and-SPARQL.html new file mode 100644 index 0000000..f2770ae --- /dev/null +++ b/lod/tutorial/graph-databases-and-SPARQL.html @@ -0,0 +1,1527 @@ + + + + + + + + + + + + + + + + + + + + + + + Using SPARQL to access Linked Open Data | Programming Historian + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+
+ Pisces symbol of two linked fish +
+
+ +
+ + +
+

+ + + +Matthew Lincoln ORCID id icon

+
+ +
+

This lesson explains why many cultural institutions are adopting graph databases, and how researchers can access these data though the query language called SPARQL.

+ +
+ +
+
+ + + + + +
+
+
+ +
+
+
+ + +
+
+ + +
+ +
+
+

edited by

+
    + + +
  • Fred Gibbs
  • + +
+
+ +
+

reviewed by

+
    + + +
  • Patrick Murray-John +
  • + + +
  • Jason Heppler +
  • + + +
  • Will Hanley +
  • + +
+
+ + + + + + +
+
+
+
+ +
+
+
+
+

published

2015-11-24 +
+ + +
+

retired

+
+ +
+

difficulty

+ +Medium + +
+ +
+

DOI id icon https://doi.org/10.46430/phen0047

+ +
+
+
+
+ +
+ +
+ + + +
+

Great Open Access tutorials cost money to produce. Join the growing number of people supporting The Programming Historian so we can continue to share knowledge free of charge.

+
+ + + + + +
+ + Available in: + + EN + (original) | + + + + ES + + + +
+ + + + + + + +
+

This lesson has been retired

+

What does this mean?

+

The Programming Historian editors do their best to maintain lessons as minor issues inevitably arise. However, since publication, changes to either the underlying technologies or principles used by this lesson have been substantial, to the point where the editors have decided not to further update it. The lesson may still prove a useful learning tool and a snapshot into the techniques of digital history when it was published, but we cannot guarantee all elements will continue to work as intended.

+

+ +

Why was this lesson retired?

+

The British Museum has failed to maintain their collections database in a consistent and reliably-accessible manner. Although the SPARQL syntax and commands remain correct, the URLs they attempt to connect to have become too unreliable to use in a working lesson.

+

+ +
+ + + + + + + +
+

Lesson Goals

+ +

This lesson explains why many cultural institutions are adopting graph +databases, and how researchers can access these data though the query language +called SPARQL.

+ +

Contents

+ + + +

Graph Databases, RDF, and Linked Open Data

+ +

Many cultural institutions now offer access to their collections information +through web Application Programming Interfaces. While these APIs are a +powerful way to access individual records in a machine-readable manner, they are +not ideal for cultural heritage data because they are structured to work for a +predetermined set of queries. For example, a museum may have information on +donors, artists, artworks, exhibitions, and provenance, but its web API may +offer only object-wise retrieval, making it difficult or impossible to search +for associated data about donors, artists, provenance, etc. This structure is +great if you come looking for information about particular objects. However, it +makes it difficult to aggregate information about every artist or donor that +happens to be described in the dataset as well.

+ +

RDF databases are well-suited to expressing complex relationships between many +entities, like people, places, events, and concepts tied to individual +objects. These databases are often referred to as “graph” databases because they +structure information as a graph or network, where a set of resources, or nodes, +are connected together by edges that describe the relationships between each +resource.

+ +

Because RDF databases support the use of URLs (weblinks), they can be made +available online and linked to other databases, hence the term “Linked Open +Data”. Major art collections including the British Museum, Europeana, +the Smithsonian American Art Museum, and the Yale Center for +British Art have published their collections data as LOD. The Getty +Vocabulary Program, has also released their series of authoritative +databases on geographic place names, terms for describing art and architecture, +and variant spellings of artist names, as LOD.

+ +

SPARQL is the language used to query these databases. This language is +particularly powerful because it does not presuppose the perspectives that users +will bring to the data. A query about objects and a query about donors is +basically equivalent to such a database. Unfortunately, many tutorials on SPARQL +use extremely simplified data models that don’t resemble the more complex +datasets released by cultural heritage institutions. This tutorial gives a crash +course on SPARQL using a dataset that a humanist might actually find in the +wilds of the Internet. In this tutorial, we will learn how to query the British +Museum Linked Open Data collection.

+ +

RDF in brief

+ +

RDF represents information in a series of three-part “statements” that comprise +a subject, predicate, and an object, e.g.:

+ +
<The Nightwatch> <was created by> <Rembrandt van Rijn> .
+
+ +

(Note that just like any good sentence, they each have a period at the end.)

+ +

Here, the subject <The Nightwatch> and the object <Rembrandt van Rijn> can +be thought of as two nodes of the graph, with the predicate <was created by> +defining an edge between them. (Technically, <was created by> can, in other +queries, be treated as an object or subject itself, but that is beyond the scope +of this tutorial.)

+ +

A pseudo-RDF database might contain interrelated statements like these:

+ +
...
+<The Nightwatch> <was created by> <Rembrandt van Rijn> .
+<The Nightwatch> <was created in> <1642> .
+<The Nightwatch> <has medium> <oil on canvas> .
+<Rembrandt van Rijn> <was born in> <1606> .
+<Rembrandt van Rijn> <has nationality> <Dutch> .
+<Johannes Vermeer> <has nationality> <Dutch> .
+<Woman with a Balance> <was created by> <Johannes Vermeer> .
+<Woman with a Balance> <has medium> <oil on canvas> .
+...
+
+ +

If we were to visualize these statements as nodes and edges within network +graph, it would appear like so:

+ +
+ A network visualization of the pseudo-RDF shown above. Arrows indicate the 'direction' of the predicate. For example, that 'Woman with a Balance was created by Vermeer', and not the other way around. +
+

A network visualization of the pseudo-RDF shown above. Arrows indicate the ‘direction’ of the predicate. For example, that ‘Woman with a Balance was created by Vermeer’, and not the other way around.

+ +
+
+ +

A traditional relational database might split attributes about artworks and +attributes about artists into separate tables. In an RDF/graph database, all +these data points belong to the same interconnected graph, which allows users +maximum flexibility in deciding how they wish to query it.

+ +

Searching RDF with SPARQL

+ +

SPARQL lets us translate heavily interlinked, graph data into normalized, +tabular data with rows and columns you can open in programs like Excel, or +import into a visualization suite such as plot.ly or +Palladio.

+ +

It is useful to think of a SPARQL query as a Mad +Lib - a set of sentences with blanks in +them. The database will take this query and find every set of matching +statements that correctly fill in those blanks, returning the matching values to +us as a table. Take this SPARQL query:

+ +
SELECT ?painting
+WHERE {
+  ?painting <has medium> <oil on canvas> .
+}
+
+ +

?painting in this query stands in for the node (or nodes) that the database +will return. On receiving this query, the database will search for all values of +?painting that properly complete the RDF statement <has medium> <oil on +canvas> .:

+ +
+ A visualization of what our query is looking for. +
+

A visualization of what our query is looking for.

+ +
+
+ +

When the query runs against the full database, it looks for the subjects, +predicates, and objects that match this statement, while excluding the rest of +the data:

+ +
+ A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red. +
+

A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red.

+ +
+
+ +

And our results might look like this table:

+ + + + + + + + + + + + + + + +
painting
The Nightwatch
Woman with a Balance
+ +

What makes RDF and SPARQL powerful is the ability to create complex queries that +reference many variables at a time. For example, we could search our pseudo-RDF +database for paintings by any artist who is Dutch:

+ +
SELECT ?artist ?painting
+WHERE {
+  ?artist <has nationality> <Dutch> .
+  ?painting <was created by> ?artist .
+}
+
+ +

Here we’ve introduced a second variable, ?artist. The RDF database will return +all matching combinations of ?artist and ?painting that fulfill both of +these statements.

+ +
+ A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red. +
+

A visualization of the SPARQL query, with mentioned elements in orange, and selected elements (those that will be returned in the results) in red.

+ +
+
+ + + + + + + + + + + + + + + + + + +
artistpainting
Rembrandt van RijnThe Nightwatch
Johannes VermeerWoman with a Balance
+ +

URIs and Literals

+ +

So far, we have been looking at a toy representation of RDF that uses +easy-to-read text. However, RDF is primarily stored as URIs (Uniform Resource +Identifiers) that separate conceptual entities from their plain-English (or +other language!) labels. (Note that a URL, or Uniform Resource Locator, is a URI +for a resource that is accessible on the web) In real RDF, our original +statement:

+ +
<The Nightwatch>   <was created by>   <Rembrandt van Rijn> .
+
+ +

would more likely look something like this:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/creator>  <http://dbpedia.org/resource/Rembrandt>.
+
+ +

N.B. the Rijksmuseum has not (yet) built their own Linked Data site, so the URI in this query is just for demo purposes.

+ +

In order to get the human-readable version of the information represented by +each of these URIs, what we’re really doing is just retrieving more RDF +statements. Even the predicate in that statement has its own literal label:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/title> "The Nightwatch" .
+
+<http://purl.org/dc/terms/creator> <http://www.w3.org/1999/02/22-rdf-syntax-ns#label> "was created by" .
+
+<http://dbpedia.org/resource/Rembrandt> <http://xmlns.com/foaf/0.1/name> "Rembrandt van Rijn" .
+
+ +

You will notice that, unlike the URIs in the query that are surrounded by <>, +the objects of these statements are just strings of text within quotation +marks, known as literals. Literals are unlike URIs in that they represent +values, rather than references. For example, +<http://dbpedia.org/resource/Rembrandt> represents an entity that may +reference (and be referenced by) any number of other statements (say, birth +dates, students, or family members), while the text string "Rembrandt van +Rijn" stands only for itself. Literals do not point to other nodes in the +graph, and they can only ever be objects in an RDF statement. Other literal +values in RDF include dates and numbers.

+ +

See the predicates in these statements, with domain names like purl.org, +w3.org, and xmlns.com? These are some of the many providers of ontologies +that help standardize the way we describe relationships between bits of +information like “title”, “label”, “creator”, or “name”. The more RDF/LOD that +you work with, the more of these providers you’ll find.

+ +

URIs can become unwieldy when composing SPARQL queries, which is why we’ll +use prefixes. These are shortcuts that allow us to skip typing out entire long +URIs. For example, remember that predicate for retrieving the title of the +Nightwatch, <http://purl.org/dc/terms/title>? With these prefixes, we just +need to type dct:title whenever we need to use a purl.org predicate. dct: +stands in for http://purl.org/dc/terms/, and title just gets pasted onto the +end of this link.

+ +

For example, with the prefix PREFIX rkm: <http://data.rijksmuseum.nl/>, +appended to the start of our SPARQL query, +<http://data.rijksmuseum.nl/item/8909812347> becomes rkm:item/8909812347 +instead.

+ +

Be aware that, prefixes +can be arbitrarily assigned with whatever abbreviations you like, different +endpoints may use slightly different prefixes for the same namespace (e.g. dct +vs. dcterms for <http://purl.org/dc/terms/>).

+ +

Terms to review

+ +
    +
  • SPARQL - Protocol and RDF Query Language - The language used to query RDF graph databases
  • +
  • RDF - Resource Description Framework - A method for structuring data as a graph or network of connected statements, rather than a series of tables.
  • +
  • LOD - Linked Open Data - LOD is RDF data published online with dedicated URIs in such a manner than developers can reliably reference it.
  • +
  • statement - Sometimes also called a “triple”, an RDF statement is a quantum of knowledge comprising a subject, predicate, and object.
  • +
  • URI - Uniform Resource Identifier - a string of characters for identifying a resource. RDF statements use URIs to link various resources together. A URL, or uniform resource locator, is a type of URI that points to resources on the web.
  • +
  • literal - Some objects in RDF statements do not refer to other resources with a URI, but instead convey a value, such as text ("Rembrandt van Rijn"), a number (5), or a date (1606-06-15). These are known as literals.
  • +
  • prefix - In order to simplify SPARQL queries, a user may specify prefixes that act as abbreviations for full URIs. These abbreviations, or QNames, are also used in namespaced XML documents.
  • +
+ +

Real-world queries

+ +

All the statements for one object

+ +

Let’s start our first query using the British Museum SPARQL endpoint. A +SPARQL endpoint is a web address that accepts SPARQL queries and returns +results. The BM endpoint is like many others: if you navigate to it in a web +browser, it presents you with a text box for composing queries.

+ +
+ The BM SPARQL endpoint webpage. For all the queries in this tutorial, make sure that you have left the 'Include inferred' and 'Expand results over equivalent URIs' boxes unchecked. +
+

The BM SPARQL endpoint webpage. For all the queries in this tutorial, make sure that you have left the ‘Include inferred’ and ‘Expand results over equivalent URIs’ boxes unchecked.

+ +
+
+ +

When starting to explore a new RDF database, it helps to look at the +relationships that stem from a single example +object.

+ +

(For each of the following queries, click on the “Run query” link below to see +the results. You can then run it as +is, or modify it before requesting the results. Remember when editing the query +before running to uncheck the ‘Include inferred’ box.)

+ +
SELECT ?p ?o
+WHERE {
+  <http://collection.britishmuseum.org/id/object/PPA82633> ?p ?o .
+}
+
+ +

Run query

+ +

By calling SELECT ?p ?o we’re asking the database to return the values of ?p +and ?o as described in the WHERE {} command. This query returns every +statement for which our example artwork, +<http://collection.britishmuseum.org/id/object/PPA82633>, is the subject. ?p +is in the middle position of the RDF statement in the WHERE {} command, so it +returns any predicates matching this statement, while ?o in the final position +returns all objects. Though I have named them ?p and ?o here, as you will +see below we can name these variables anything we like. Indeed, it will be +useful to give them meaningful names for the complex queries that follow!.

+ +
+ An initial list of all the predicates and objects associated with one artwork in the British Museum. +
+

An initial list of all the predicates and objects associated with one artwork in the British Museum.

+ +
+
+ +

Note: depending on how the British Museum has configured their SPARQL endpoint when you read this lesson, instead of seeing “prefixed” versions of the URLs (e.g. thes:8577) you may instead see the full version http://collection.britishmuseum.org/id/thesauri/x8577. As noted in the discussion of prefixes above, this still represents the same URI.

+ +

The BM endpoint formats the results table with hyperlinks for every variable +that is itself an RDF node, so by clicking on any one of these links you can +shift to seeing all the predicates and objects for that newly-selected node. +Note that BM automatically includes a wide range of SPARQL prefixes in its +queries, so you will find many hyperlinks are displayed in their abbreviated +versions; if you mouse over them your browser will display their unabbreviated +URIs.

+ +
+ Visualizing a handful of the nodes returned by the first query to the BM. Elements in this graph that are also in the table of results above are colored red. Additional levels in the hierarchy are included as a preview of how this single print connects to the larger BM graph. +
+

Visualizing a handful of the nodes returned by the first query to the BM. Elements in this graph that are also in the table of results above are colored red. Additional levels in the hierarchy are included as a preview of how this single print connects to the larger BM graph.

+ +
+
+ +

Let’s find out how they store the object type information: look for the +predicate <bmo:PX_object_type> (highlighted in the figure above) and click on +the link for thes:x8577 to navigate to the node describing the particular +object type “print”:

+ +
+ The resource page for `thes:x8577` ('print') in the British Museum LOD. +
+

The resource page for thes:x8577 (‘print’) in the British Museum LOD.

+ +
+
+ +

You’ll note how this node has an plain-text label, as well as ties to related +artwork type nodes within the database.

+ +

Complex queries

+ +

To find other objects of the same type with the preferred label “print”, we can +call this query:

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+
+SELECT ?object
+WHERE {
+
+  # Search for all values of ?object that have a given "object type"
+  ?object bmo:PX_object_type ?object_type .
+
+  # That object type should have the label "print"
+  ?object_type skos:prefLabel "print" .
+}
+LIMIT 10
+
+ +

Run query / See a user-generated query

+ +
+ A one-column table returned by our query for every object with type 'print' +
+

A one-column table returned by our query for every object with type ‘print’

+ +
+
+ +

Remember that, because "print" here is a literal, we enclose it within +quotation marks in our query. When you include literals in a SPARQL query, the +database will only return exact matches for those values.

+ +

Note that, because ?object_type is not present in the SELECT command, it +will not show up in the results table. However, it is essential to structuring +our query, because it connects the dots from ?object to the label "print".

+ +

FILTER

+ +

In the previous query, our SPARQL query searched for an exact match for the +object type with the text label “print”. However, often we want to match literal +values that fall within a certain range, such as dates. For this, we’ll use the +FILTER command.

+ +

To find URIs for all the prints in the BM created between 1580 and 1600, we’ll +need to first figure out where the database stores dates in relationship to the +object node, and then add references to those dates in our query. Similar to the +way that we followed a single link to determine an object type, we must hop +through several nodes to find the production dates associated with a given +object:

+ +
+ Visualizing part of the British Museum's data model where production dates are connected to objects. +
+

Visualizing part of the British Museum’s data model where production dates are connected to objects.

+ +
+
+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+# Return object links and creation date
+SELECT ?object ?date
+WHERE {
+
+  # We'll use our previous command to search only for
+  # objects of type "print"
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel "print" .
+
+  # We need to link though several nodes to find the
+  # creation date associated with an object
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+
+  # As you can see, we need to connect quite a few dots
+  # to get to the date node! Now that we have it, we can
+  # filter our results. Because we are filtering by date,
+  # we must attach the tag ^^xsd:date after our date strings.
+  # This tag tells the database to interpret the string
+  # "1580-01-01" as the date 1 January 1580.
+
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+
+ +

Run query

+ +
+ All BM prints made between 1580 and 1600 +
+

All BM prints made between 1580 and 1600

+ +
+
+ +

Aggregation

+ +

So far we have only used the SELECT command to return a table of objects. +However, SPARQL allows us to do more advanced analysis such as grouping, +counting, and sorting.

+ +

Say we would like to keep looking at objects made between 1580 and 1600, but we +want to understand how many objects of each type the BM has in its collections. +Instead of limiting our results to objects of type “print”, we will instead use +COUNT to tally our search results by type.

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+SELECT ?type (COUNT(?type) as ?n)
+WHERE {
+  # We still need to indicate the ?object_type variable,
+  # however we will not require it to match "print" this time
+
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel ?type .
+
+  # Once again, we will also filter by date
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+# The GROUP BY command designates the variable to tally by,
+# and the ORDER BY DESC() command sorts the results by
+# descending number.
+GROUP BY ?type
+ORDER BY DESC(?n)
+
+ +

Run query

+ +
+ Counts of objects by type produced between 1580 and 1600. +
+

Counts of objects by type produced between 1580 and 1600.

+ +
+
+ +

Linking multiple SPARQL endpoints

+ +
2018-06-13: Unfortunately, Europeana has removed the ability to link to external SPARQL endpoints using `SERVICE` queries, so the query in this section can no longer be run. The text below will be retained as-is for reference purposes, and may be updated if and when Europeana again allows `SERVICE` queries.
+ +

Up until now, we have constructed queries that look for patterns in one dataset +alone. In the ideal world envisioned by Linked Open Data advocates, multiple +databases can be interlinked to allow very complex queries dependent on +knowledge present in different locations. However, this is easier said than +done, and many endpoints (the BM’s included) do not yet reference outside +authorities.

+ +

One endpoint that does, however, is +Europeana’s. They have created links +between the objects in their database and records about individuals in +DBPedia and VIAF, places in +GeoNames, and concepts in the Getty Art & +Architecture thesaurus. SPARQL allows you to insert SERVICE statements that +instruct the database to “phone a friend” and run a portion of the query on +an outside dataset, using the results to complete the query on the local +dataset. While this lesson will go into the data models in Europeana and DBpedia in depth, the following query illustrates how a SELECT statement works. You may run it yourself by copying and pasting the query text into the Europeana endpoint.

+ +
PREFIX edm:    <http://www.europeana.eu/schemas/edm/>
+PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX dbo:    <http://dbpedia.org/ontology/>
+PREFIX dbr:    <http://dbpedia.org/resource/>
+PREFIX rdaGr2: <http://rdvocab.info/ElementsGr2/>
+
+# Find all ?object related by some ?property to an ?agent born in a
+# ?dutch_city
+SELECT ?object ?property ?agent ?dutch_city
+WHERE {
+    ?proxy ?property ?agent .
+    ?proxy ore:proxyFor ?object .
+
+    ?agent rdf:type edm:Agent .
+    ?agent rdaGr2:placeOfBirth ?dutch_city .
+
+    # ?dutch_city is defined by having "Netherlands" as its broader
+    # country in DBpedia. The SERVICE statement asks
+    # http://dbpdeia.org/sparql which cities have the country
+    # "Netherlands". The answers to that sub-query will then be
+    # used to finish off our original query about objects in the
+    # Europeana database
+
+    SERVICE <http://dbpedia.org/sparql> {
+        ?dutch_city dbo:country dbr:Netherlands .
+   }
+}
+# This query can potentially return a lot of objects, so let's
+# just request the first 100 in order to speed up the search
+LIMIT 100
+
+ +
+ Visualizing the query sequence of the above SPARQL request +
+

Visualizing the query sequence of the above SPARQL request

+ +
+
+ +

An interlinked query like this means that we can ask Europeana questions about +its objects that rely on information about geography (what cities are in the +Netherlands?) that Europeana does not need to store and maintain itself. In the +future, more cultural LOD will hopefully link to authority databases like the +Getty’s Union List of Artist Names, allowing, for example, the British Museum to +outsource biographical data to the more complete resources at the Getty.

+ +

Working with SPARQL results

+ +

Having constructed and run a query… what do we do with the results? Many +endpoints offer, like the British Museum, a web-based browser that returns +human-readable results. However, SPARQL endpoints are designed to return +structured data to be used by other programs.

+ +

Export results to CSV

+ +

In the top right corner of the results page for the BM endpoint, you will find +links for both JSON and XML downloads. Other endpoints may also offer the +option for a CSV/TSV download, however this option is not always available. The +JSON and XML output from a SPARQL endpoint contain not only the values returned +from the SELECT statement, but also additional metadata about variable types +and languages.

+ +

Parsing the XML verson of this output may be done with a tool like Beautiful +Soup (see its Programming Historian +lesson) or Open +Refine. To quickly convert JSON results from a SPARQL +endpoint into a tabular format, I recommend the free command line utility +jq. (For a tutorial on using command +line programs, see “Introduction to the Bash Command +Line”.) The following query will convert the +special JSON RDF format into a CSV file, which you may load into your preferred +program for further analysis and visualization:

+ +
jq -r '.head.vars as $fields | ($fields | @csv), (.results.bindings[] | [.[$fields[]].value] | @csv)' sparql.json > sparql.csv
+
+ +

Export results to Palladio

+ +

The popular data exploration platform Palladio can directly load data from a +SPARQL endpoint. On the “Create a new project” screen, a link at the bottom to +“Load data from a SPARQL endpoint (beta)” will provide you a field to enter the +endpoint address, and a box for the query itself. Depending on the endpoint, you +may need to specify the file output type in the endpoint address; for example, +to load data from the BM endpoint you must use the address +http://collection.britishmuseum.org/sparql.json. Try pasting in the +aggregation query we used above to count artworks by type and clicking on “Run +query”. Palladio should display a preview table.

+ +
+ Palladio's SPARQL query interface. +
+

Palladio’s SPARQL query interface.

+ +
+
+ +

After previewing the data returned by the endpoint, click on the “Load data” +button at the bottom of the screen to begin manipulating it. (See this +Programming Historian +lesson +for a more in-depth tutorial on Palladio.) For example, we might make a query +that returns links to the images of prints made between 1580 and +1600, +and render that data as a grid of images sorted by date:

+ +
+ A gallery of images with a timeline of their creation dates generated using Palladio. +
+

A gallery of images with a timeline of their creation dates generated using Palladio.

+ +
+
+ +

Note that Palladio is designed to work with relatively small amounts of data (on +the order of hundreds or thousands of rows, not tens of thousands), so you may +have to use the LIMIT command that we used when querying the Europeana +endpoint to reduce the number of results that you get back, just to keep the +software from freezing.

+ +

Further reading

+ +

In this tutorial we got a look at the structure of LOD as well as a real-life +example of how to write SPARQL queries for the British Museum’s database. You +also learned how to use aggregation commands in SPARQL to group, count, and sort +results rather than simply list them.

+ +

There are even more ways to modify these queries, such as introducing OR and +UNION statements (for describing conditional queries), and CONSTRUCT +statements (for inferring new links based on defined rules), full-text +searching, or doing other mathematical operations more complex than counting. +For a more complete rundown of the commands available in SPARQL, see these +links:

+ + + +

Both the Europeana and Getty Vocabularies LOD sites also offer extensive, and +quite complex example queries which can be good sources for understanding how to +search their data:

+ + + +
+ + + + + + + + + +
+
About the author
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Matthew Lincoln is the digital humanities developer at Carnegie Mellon University, and an art historian of early modern Europe. + ORCID id icon

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + +
+ + + + +
Suggested Citation
+
+

+ + + +Matthew Lincoln, + "Using SPARQL to access Linked Open Data," + The Programming Historian 4 (2015), + https://doi.org/10.46430/phen0047.

+
+
+ + + +
+

Great Open Access tutorials cost money to produce. Join the growing number of people supporting The Programming Historian so we can continue to share knowledge free of charge.

+
+ + + +
+ + + + + + + + + + + + + +
+ + + diff --git a/lod/tutorial/images/ORCIDiD_iconvector.svg b/lod/tutorial/images/ORCIDiD_iconvector.svg new file mode 100644 index 0000000..2bddf44 --- /dev/null +++ b/lod/tutorial/images/ORCIDiD_iconvector.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/lod/tutorial/images/doi_icon.jpg b/lod/tutorial/images/doi_icon.jpg new file mode 100644 index 0000000..77d44cf Binary files /dev/null and b/lod/tutorial/images/doi_icon.jpg differ diff --git a/lod/tutorial/images/favicons/en_favicon.ico b/lod/tutorial/images/favicons/en_favicon.ico new file mode 100644 index 0000000..a696cb5 Binary files /dev/null and b/lod/tutorial/images/favicons/en_favicon.ico differ diff --git a/lod/tutorial/images/favicons/es_favicon.ico b/lod/tutorial/images/favicons/es_favicon.ico new file mode 100644 index 0000000..0b47a95 Binary files /dev/null and b/lod/tutorial/images/favicons/es_favicon.ico differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL.png b/lod/tutorial/images/graph-databases-and-SPARQL.png new file mode 100644 index 0000000..f42fd1e Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-01.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-01.png new file mode 100644 index 0000000..e663483 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-01.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-02.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-02.png new file mode 100644 index 0000000..ae6c6b6 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-02.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-03.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-03.png new file mode 100644 index 0000000..497f0e9 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-03.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-04.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-04.png new file mode 100644 index 0000000..89c8442 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-04.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-05.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-05.png new file mode 100644 index 0000000..28b182b Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-05.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-06.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-06.png new file mode 100644 index 0000000..b2bb1a4 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-06.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-07.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-07.png new file mode 100644 index 0000000..c115095 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-07.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-08.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-08.png new file mode 100644 index 0000000..89062d4 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-08.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-09.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-09.png new file mode 100644 index 0000000..93a5003 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-09.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-10.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-10.png new file mode 100644 index 0000000..3991dd3 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-10.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-11.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-11.png new file mode 100644 index 0000000..548273a Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-11.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-12.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-12.png new file mode 100644 index 0000000..b082498 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-12.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-13.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-13.png new file mode 100644 index 0000000..48af655 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-13.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-14.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-14.png new file mode 100644 index 0000000..f6826d1 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-14.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-15.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-15.png new file mode 100644 index 0000000..c58e046 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql-lod-15.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql01-1.svg b/lod/tutorial/images/graph-databases-and-SPARQL/sparql01-1.svg new file mode 100644 index 0000000..606b8a0 --- /dev/null +++ b/lod/tutorial/images/graph-databases-and-SPARQL/sparql01-1.svg @@ -0,0 +1,40 @@ + + + + + + +%3 + + +nw + +The Nightwatch + + +oil + +oil on canvas + + +nw->oil + + +has medium + + +wb + +Woman with a Balance + + +wb->oil + + +has medium + + + diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql01.svg b/lod/tutorial/images/graph-databases-and-SPARQL/sparql01.svg new file mode 100644 index 0000000..9ead24a --- /dev/null +++ b/lod/tutorial/images/graph-databases-and-SPARQL/sparql01.svg @@ -0,0 +1,104 @@ + + + + + + +%3 + + +nw + +The Nightwatch + + +rr + +Rembrandt van Rijn + + +nw->rr + + +was +created by + + +oil + +oil on canvas + + +nw->oil + + +has medium + + +nwd + +1642 + + +nw->nwd + + +was +created in + + +d + +Dutch + + +rr->d + + +has nationality + + +rrb + +1606 + + +rr->rrb + + +was born in + + +jv + +Johannes Vermeer + + +jv->d + + +has nationality + + +wb + +Woman with a Balance + + +wb->jv + + +was +created by + + +wb->oil + + +has medium + + + diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql02-1.svg b/lod/tutorial/images/graph-databases-and-SPARQL/sparql02-1.svg new file mode 100644 index 0000000..bf71865 --- /dev/null +++ b/lod/tutorial/images/graph-databases-and-SPARQL/sparql02-1.svg @@ -0,0 +1,104 @@ + + + + + + +%3 + + +nw + +The Nightwatch + + +rr + +Rembrandt van Rijn + + +nw->rr + + +was +created by + + +oil + +oil on canvas + + +nw->oil + + +has medium + + +nwd + +1642 + + +nw->nwd + + +was +created in + + +d + +Dutch + + +rr->d + + +has nationality + + +rrb + +1606 + + +rr->rrb + + +was born in + + +jv + +Johannes Vermeer + + +jv->d + + +has nationality + + +wb + +Woman with a Balance + + +wb->jv + + +was +created by + + +wb->oil + + +has medium + + + diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql02.svg b/lod/tutorial/images/graph-databases-and-SPARQL/sparql02.svg new file mode 100644 index 0000000..4a9efeb --- /dev/null +++ b/lod/tutorial/images/graph-databases-and-SPARQL/sparql02.svg @@ -0,0 +1,104 @@ + + + + + + +%3 + + +nw + +The Nightwatch + + +rr + +Rembrandt van Rijn + + +nw->rr + + +was +created by + + +oil + +oil on canvas + + +nw->oil + + +has medium + + +nwd + +1642 + + +nw->nwd + + +was +createdin + + +d + +Dutch + + +rr->d + + +has nationality + + +rrb + +1606 + + +rr->rrb + + +was born in + + +jv + +Johannes Vermeer + + +jv->d + + +has nationality + + +wb + +Woman with a Balance + + +wb->jv + + +was +created by + + +wb->oil + + +has medium + + + diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql03.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql03.png new file mode 100644 index 0000000..28b182b Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql03.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql04-1.svg b/lod/tutorial/images/graph-databases-and-SPARQL/sparql04-1.svg new file mode 100644 index 0000000..619d29d --- /dev/null +++ b/lod/tutorial/images/graph-databases-and-SPARQL/sparql04-1.svg @@ -0,0 +1,127 @@ + + + + + + +%3 + + +o + +object/PPA82633 + + +th1 + +thes:x11409 + + +o->th1 + + +ecrm:p45_consists_of + + +dep + +person-institution/147800 + + +o->dep + + +ecrm:P62_depicts + + +etc + +etc... + + +o->etc + + + + +own + +thesIdentifier:the-british-museum + + +o->own + + +ecrm:P54_has_current_owner + + +con + +object/PPA82633/concept/1 + + +o->con + + +ecrm:P128_carries + + +th1lab + +paper + + +th1->th1lab + + +skos:prefLabel + + +deplab + +Julius Caesar Scaliger + + +dep->deplab + + +skos:prefLabel + + +contype + +ecrm:E73_Information_Object + + +con->contype + + +rdf:type + + +concon + +thes:x12440 + + +con->concon + + +ecrm:P129_is_about + + +conlab + +academic + + +concon->conlab + + +skos:prefLabel + + + diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql04.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql04.png new file mode 100644 index 0000000..b2bb1a4 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql04.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql05.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql05.png new file mode 100644 index 0000000..89062d4 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql05.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql06.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql06.png new file mode 100644 index 0000000..93a5003 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql06.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql07.svg b/lod/tutorial/images/graph-databases-and-SPARQL/sparql07.svg new file mode 100644 index 0000000..6ced72b --- /dev/null +++ b/lod/tutorial/images/graph-databases-and-SPARQL/sparql07.svg @@ -0,0 +1,114 @@ + + + + + + +%3 + + +obj + +http://collection.britishmuseum.org/id/object/PPA82633 + + +object_type + +object_type + + +obj->object_type + + +bmo:PX_object_type + + +production + +production + + +obj->production + + +ecrm:P108i_was_produced_by + + +other +Other top-level object attributes + + +obj->other + + +... + + +print + +print + + +object_type->print + + +skos:prefLabel + + +date + +date + + +production->date + + +ecrm:P9_consists_of + + +other_prod +Other production info + + +production->other_prod + + +... + + +timespan + +timespan + + +date->timespan + + +ecrm:P4_has_time-span + + +start_date + +start_date + + +timespan->start_date + + +ecrm:P82a_begin_of_the_begin + + +other_date +End of begin, Start of end... + + +timespan->other_date + + +... + + + diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql08.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql08.png new file mode 100644 index 0000000..548273a Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql08.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql09-1.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql09-1.png new file mode 100644 index 0000000..48af655 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql09-1.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql09.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql09.png new file mode 100644 index 0000000..b082498 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql09.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql10.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql10.png new file mode 100644 index 0000000..f6826d1 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql10.png differ diff --git a/lod/tutorial/images/graph-databases-and-SPARQL/sparql11.png b/lod/tutorial/images/graph-databases-and-SPARQL/sparql11.png new file mode 100644 index 0000000..c58e046 Binary files /dev/null and b/lod/tutorial/images/graph-databases-and-SPARQL/sparql11.png differ diff --git a/lod/tutorial/js/bootstrap-4-navbar.js b/lod/tutorial/js/bootstrap-4-navbar.js new file mode 100644 index 0000000..c206c70 --- /dev/null +++ b/lod/tutorial/js/bootstrap-4-navbar.js @@ -0,0 +1,34 @@ + +/*! + * Bootstrap 4 multi dropdown navbar ( https://bootstrapthemes.co/demo/resource/bootstrap-4-multi-dropdown-navbar/ ) + * Copyright 2017. + * Licensed under the GPL license + */ + + +$( document ).ready( function () { + $( '.mobile-drop a.dropdown-toggle' ).on( 'click', function ( e ) { + var $el = $( this ); + var $parent = $( this ).offsetParent( ".mobile-drop" ); + if ($('.show.mobile-drop').length > 0){ + $('.show.mobile-drop').each(function(item){ + $(this).toggleClass('show'); + }); + } + + var $subMenu = $( this ).next( ".mobile-drop" ); + $subMenu.toggleClass( 'show' ); + + $( this ).parent( "li" ).toggleClass( 'show' ); + + $( this ).parents( 'li.nav-item.dropdown.mobile-drop.show' ).on( 'click', function ( e ) { + $( '.mobile-drop .show' ).removeClass( "show" ); + } ); + + if ( !$parent.parent().hasClass( 'navbar-nav' ) ) { + $el.next().css( { "top": $el[0].offsetTop, "left": $parent.outerWidth() - 4 } ); + } + + return false; + } ); +} ); diff --git a/lod/tutorial/js/ext_links.js b/lod/tutorial/js/ext_links.js new file mode 100644 index 0000000..409df72 --- /dev/null +++ b/lod/tutorial/js/ext_links.js @@ -0,0 +1,8 @@ +$(document).ready(function() { + $('a').each(function() { + var a = new RegExp('/' + window.location.host + '/'); + if (!a.test(this.href)) { + $(this).attr("target","_blank"); + } + }); +}); diff --git a/lod/tutorial/js/header_links.js b/lod/tutorial/js/header_links.js new file mode 100644 index 0000000..64cb679 --- /dev/null +++ b/lod/tutorial/js/header_links.js @@ -0,0 +1,13 @@ +// http://ben.balter.com/2014/03/13/pages-anchor-links/ + +$(function() { + return $("h2, h3, h4, h5, h6").each(function(i, el) { + var $el, icon, id; + $el = $(el); + id = $el.attr('id'); + icon = ''; + if (id) { + return $el.append($("").addClass("header-link").attr("href", "#" + id).html(icon)); + } + }); +}); diff --git a/lod/tutorial/sparql-datos-abiertos-enlazados.html b/lod/tutorial/sparql-datos-abiertos-enlazados.html new file mode 100644 index 0000000..446933d --- /dev/null +++ b/lod/tutorial/sparql-datos-abiertos-enlazados.html @@ -0,0 +1,1377 @@ + + + + + + + + + + + + + + + + + + + + + + + Uso de SPARQL para acceder a datos abiertos enlazados + | Programming Historian + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+ +
+ +
+ +
+
+
+ Grabado con dos peces unidos por una rama en sus bocas. +
+
+ +
+ + +
+

+ + + +Matthew Lincoln ORCID id icon

+
+ +
+

Esta lección explica por qué numerosas instituciones culturales están adoptando bases de datos orientadas a grafos y cómo los investigadores pueden acceder a estos datos a través de consultas realizadas en el lenguaje llamado SPARQL.

+ +
+ +
+ +
+
+ +
+
+
+ + +
+
+ + +
+ +
+
+

editado por

+
    + + +
  • Fred Gibbs
  • + +
+
+ +
+

revisado por

+
    + + +
  • Patrick Murray-John +
  • + + +
  • Jason Heppler +
  • + + +
  • Will Hanley +
  • + + +
  • Fred Gibbs +
  • + +
+
+ + +
+

traducido por

+
    + + +
  • Nuria Rodríguez Ortega
  • + +
+
+ + + +
+

traducción editada por

+
    + + +
  • Antonio Rojas Castro + ORCID id icon
  • + +
+
+ + + +
+

traducción revisada por

+
    + + +
  • Antonio Rojas Castro + ORCID id icon
  • + + +
  • Juan Antonio Pastor Sánchez
  • + +
+
+ +
+
+
+
+ +
+
+
+
+

publicado

2015-11-24 +
+ +
+

traducido

2017-05-20 +
+ + +
+

retirada

+
+ +
+

dificultad

+ +Medio + +
+ +
+

DOI id icon https://doi.org/10.46430/phes0027

+ +
+
+
+
+ +
+ +
+ + + +

¡Haz una donación!

+

Producir buenos tutoriales de acceso abierto cuesta dinero. Únete al creciente número de personas que apoya a The Programming Historian para que podamos continuar compartiendo conocimientos de forma gratuita.

+
+ + + + + +
+ + Disponible en: + + EN + (original) | + + + + ES + + + +
+ + + + + + + +
+

Esta lección ha sido retirada

+

¿Qué significa esto?

+

Los editores de The Programming Historian hacen todo lo posible para mantener las lecciones a medida que surgen inevitablemente problemas menores. Sin embargo, desde la publicación, los cambios en las tecnologías subyacentes o los principios utilizados en esta lección han sido sustanciales, hasta el punto de que los editores han decidido no actualizarla más. Es posible que la lección siga siendo una herramienta de aprendizaje útil y una instantánea de las técnicas de la historia digital cuando se publicó, pero no podemos garantizar que todos los elementos sigan funcionando como estaba previsto.

+

+ +

¿Por qué ha sido retirada?

+

El Museo Británico no ha mantenido el acceso a su base de datos de colecciones de una manera consistente. Aunque la sintaxis y los comandos de SPARQL siguen siendo correctos, las URLs a las que intentan conectarse son ahora demasiado inconsistentes para su uso en una lección funcional.

+

+ +
+ + + + + + + +
+

Objetivos de la lección

+ +

Esta lección explica por qué numerosas instituciones culturales están adoptando bases de datos orientadas a grafos (graph databases) y cómo los investigadores pueden acceder a estos datos a través de consultas realizadas en el lenguaje llamado SPARQL.

+ +

Contenidos

+ + + +

Bases de datos orientadas a grafo, RDF y datos abiertos enlazados (Linked Open Data, LOD)

+ +

Actualmente, numerosas instituciones culturales están ofreciendo información sobre sus colecciones a través de las denominadas API (Application Programming Interfaces). Estas API son instrumentos muy eficaces para acceder de manera automatizada a registros individuales, sin embargo, no constituyen el procedimiento ideal cuando tratamos con datos culturales debido a que las API están estructuradas para trabajar con un conjunto predeterminado de consultas (queries). Por ejemplo, un museo puede tener información sobre donantes, artistas, obras de arte, exposiciones, procedencia de sus obras (provenance), etc., pero su API puede ofrecer solo una recuperación orientada a objetos, haciendo difícil o imposible buscar datos relacionados con donantes, artistas, etc. Así pues, esta estructura es interesante si el objetivo es buscar información sobre objetos particulares; sin embargo, puede complicar la operación de agregar información sobre los artistas o donantes que también se encuentran registrados en la base de datos.

+ +

Las bases de datos RDF son muy apropiadas para expresar relaciones complejas entre múltiples entidades, como personas, lugares, eventos y conceptos ligados a objetos individuales. Estas bases de datos se denominan habitualmente bases de datos orientadas a grafos (graph databases) porque estructuran la información como un grafo o red, donde un conjunto de recursos o nodos están conectados entre sí mediante aristas (o enlaces) que describen las relaciones establecidas entre dichos recursos y/o nodos.

+ +

Dado que las bases de datos RDF admiten el uso de URL, estas pueden estar accesibles online y también pueden enlazarse a otras bases de datos, de ahí el término “datos abiertos enlazados” (Linked Open Data, LOD). Importantes colecciones artísticas, entre las que se incluyen las del British Museum, Europeana, el Smithsonian American Art Museum y el Yale Center for British Art, han publicado sus colecciones de datos como LOD. El Getty Vocabulary Program también ha publicado sus vocabularios controlados (TGN, ULAN y AAT) como LOD.

+ +

SPARQL es el lenguaje utilizado para interrogar este tipo de bases de datos. Este lenguaje es particularmente potente porque obvia las perspectivas que los usuarios transfieren a los datos. Una consulta sobre objetos y una consulta sobre donantes son prácticamente equivalentes en estas bases de datos. Lamentablemente, numerosos tutoriales sobre SPARQL utilizan modelos de datos tan extremadamente simplificados que no son operativos cuando se trata de utilizar las complejas bases de datos desarrolladas por las instituciones culturales. Este tutorial ofrece un curso intensivo sobre SPARQL utilizando un conjunto de datos (dataset) que un humanista podría realmente encontrar en Internet. En concreto, en este tutorial aprenderemos cómo interrogar la colección LOD del British Museum.

+ +

RDF en pocas palabras

+ +

RDF representa la información en una declaración triple -también llamada tripleta- que sigue la estructura sujeto-predicado-objeto. Por ejemplo:

+ +
<La ronda de noche> <fue creada por> <Rembrandt van Rijn> .
+
+
+ +

(Observa que, como toda buena oración, estas declaraciones terminan con un punto y final).

+ +

En este ejemplo, el sujeto <La ronda de noche> y el objeto <Rembrandt van Rijn> pueden ser considerados como dos nodos de un grafo, donde el predicado <fue creada por> define la arista -o relación- entre ellos. (Técnicamente, puede ser tratado en otras consultas como un objeto o un sujeto, pero esta cuestión escapa el alcance de este tutorial).

+ +

Una seudobase de datos RDF podría contener declaraciones interrelacionadas entre sí, como las siguientes:

+ +
...
+<La ronda de noche> <fue creada por> <Rembrandt van Rijn>.
+<La ronda de noche> <fue creada en> <1642>.
+<La ronda de noche> <utiliza la técnica de> <óleo sobre lienzo>.
+<Rembrandt van Rijn> <nació en> <1606>.
+<Rembrandt van Rijn> <es de nacionalidad> <holandesa>.
+<Johannes Vermeer> <es de nacionalidad> <holandesa>.
+<La tasadora de perlas> <fue creada por> <Johannes Vermeer>.
+<La tasadora de peras> <utiliza la técnica de> <óleo sobre lienzo>.
+...
+
+ +

Si visualizásemos estas declaraciones como nodos y aristas de un grafo o red, la representación sería como sigue:

+ +
+ Visualización en red del seudoRDF mostrado más arriba. Las flechas indican la 'dirección' del predicado. Por ejemplo, que '*La tasadora de perlas* fue creada por Vermeer' y no al revés. Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización en red del seudoRDF mostrado más arriba. Las flechas indican la ‘dirección’ del predicado. Por ejemplo, que ‘La tasadora de perlas fue creada por Vermeer’ y no al revés. Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ +

Las tradicionales bases de datos relacionales pueden distribuir atributos sobre obras de arte y artistas en tablas separadas. En las bases de datos RDF u orientadas a grafos, todos estos datos pertenencen a un mismo mismo grafo interconectado, lo que permite a los usuarios una mayor flexibilidad a la hora de decidir cómo quieren interrogar estos recursos.

+ +

Buscando RDF con SPARQL

+ +

SPARQL nos permite traducir datos en grafo, intensamente enlazados, en datos normalizados en formato tabular, esto es, distribuidos en filas y columnas, que se pueden abrir en programas como Excel o importar a programas de visualización, tales como plot.ly o Palladio.

+ +

Resulta útil pensar las consultas SPARQL como un Mad Lib -un conjunto de oraciones con espacios en blanco-. La base de datos tomará esta consulta y encontrará cada conjunto de oraciones que encaje correctamente en estos espacios en blanco, devolviéndonos los valores coincidentes como una tabla. Veamos esta consulta SPARQL:

+ +
SELECT ?pintura
+WHERE {
+	?pintura <utiliza la técnica de> <óleo sobre lienzo> .
+}
+
+ +

En este consulta, ?pintura representa el nodo (o nodos) que la bases de datos nos devolverá. Una vez recibida la consulta, la base de datos buscará todos los valores para ?pintura que adecuadamente complete la declaración RDF <utiliza la técnica de> <óleo sobre lienzo>.

+ +
+ Visualización de lo que nuestra consulta está buscando. Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización de lo que nuestra consulta está buscando. Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ +

Cuando la consulta interroga la base de datos completa, esta busca los sujetos, predicados y objetos que coinciden con esta declaración, exluyendo, al mismo tiempo, el resto de datos.

+ +
+ Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que nos serán devueltos en los resultados) en rojo. Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que nos serán devueltos en los resultados) en rojo. Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ +

Nuestros resultados podrían tener este aspecto:

+ + + + + + + + + + + + + + + +
pinturas
La ronda de noche
La tasadora de perlas
+ +

Ahora bien, lo que hace a RDF y a SPARQL herramientas tan potentes es su habilidad para crear consultas complejas que referencian múltiples variables al mismo tiempo. Por ejemplo, podríamos buscar en nuestra seudobase de datos RDF pinturas creadas por cualquier artista que fuese holandés:

+ +
SELECT ?artista ?pintura
+WHERE {
+	?artista <es de nacionalidad> <holandesa> .
+	?pintura <fue creada por> ?artista .
+	}
+
+ +

En este ejemplo, hemos introducido una segunda variable: ?artista. La base de datos RDF devolverá todas las combinaciones conincidentes de ?artista y ?pintura que encajen en ambas declaraciones.

+ +
+ Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que serán recuperados en los resultados en rojo). Diagrama reconstruido por Nuria Rodríguez Ortega. +
+

Visualización de la consulta SPARQL con los elementos mencionados en naranja y los elementos seleccionados (aquellos que serán recuperados en los resultados en rojo). Diagrama reconstruido por Nuria Rodríguez Ortega.

+ +
+
+ + + + + + + + + + + + + + + + + + +
artistaspinturas
Rembrandt van RijnLa ronda de noche
Johannes VermeerLa tasadora de perlas
+ +

URI y literales

+ +

Hasta ahora, hemos visto una representación facticia de RDF que utiliza un texto fácil de leer. Sin embargo, RDF se almacena principalmente en formato URI (Uniform Resource Identifiers), que separa las entidades conceptuales de sus etiquetas lingüísticas. (Ten en cuenta que una URL, o Uniform Resource Locator, es una URI accesible desde la web). En RDF real, nuestra declaración original:

+ +
<La ronda de noche> <fue creada por> <Rembrandt van  Rijn>.
+
+ +

sería más parecido a lo siguiente:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/creator> <http://dbpedia.org/resource/Rembrandt> .
+
+ +

N.B. el Rijksmuseum todavía no ha desarrollado su propio sitio LOD, por lo que en esta consulta la URI responde únicamente a objetivos de demostración.

+ +

A fin de obtener una versión legible desde el punto de vista humano de la información representada por cada una de estas URI, lo que hacemos realmente es recuperar más declaraciones RDF. Incluso el predicado en esta declaración tiene su propia etiqueta literal:

+ +
<http://data.rijksmuseum.nl/item/8909812347> <http://purl.org/dc/terms/title> "La ronda de noche".
+<http://purl.dc.terms/creator> <http://www.w3.org/1999/02/22-rdf-syntax-ns#label> "fue creado por".
+<http://dbpedia.org/resource/Rembrandt> <http://xmlns.com/foaf/0.1/name> "Rembrandt van Rijn".
+
+ +

Como se puede observar, a diferencia de las URI que en esta consulta están enmarcadas por los signos <>, los objetos son cadenas de texto entrecomilladas. Esto es lo que se conoce como literales (literals). Los literales representan valores, mientras que las URI representan referencias. Por ejemplo, <http://dbpedia.org/resources/Rembrandt> representa una entidad que puede referenciar (y puede ser referenciada por) muchas otras declaraciones (fechas de nacimiento, discípulos, miembros de la familia, etc.), mientras que la cadena de texto "Rembrandt van Rijn" solo se representa a sí misma. Otros valores literales en RDF incluyen fechas y números.

+ +

Fijémenos ahora en los predicados de estas declaraciones, con nombres de dominio como purl.org, w3.org y xmlns.com. Estos son algunos de los numerosos proveedores de ontologías que ayudan a estandarizar el modo en que describimos relaciones entre bits de información como, “título”, “etiqueta”, “creador” o “nombre”. Cuanto más trabajemos con RDF/LOD, más proveedores de este tipo encontraremos.

+ +

Las URI pueden llegar a ser difíciles de manejar cuando se componen consultas SPARQL. Para simplificar este proceso se utilizan los prefijos (prefixes). Los prefijos son atajos que nos liberan de tener que escribir toda la larga cadena de caracteres que constituye una URI. Por ejemplo, recordemos el predicado para recuperar el título de La ronda de noche, http://purl.org/dc/terms/title>. Con los siguientes prefijos, solo necesitamos escribir dct:title cuando queramos utilizar un predicado purl.org. dct: representa la cadena completa http://purl.org.dc/terms, y 'title' simplemente se agrega al final de este enlace.

+ +

Por ejemplo, con el prefijo PREFIX rkm: que representa la cadena completa <http//data.rijksmuseum.nl>, agregado al inicio de nuestra consulta SPARQL, http://data.rijksmuseum.nl/item/8909812347 < se convierte en rkm:item/8909812347.

+ +

Debemos ser conscientes de que los prefijos se pueden asignar arbitrariamente a cualquier abreviatura que queramos; así, diferentes puntos de entrada (endpoints) pueden utilizar prefijos ligeramente diferentes para el mismo espacio de nombre (namespace) (por ejemplo: dct vs. dcterms para <http://purl.org/dc/terms>).

+ +

Términos para revisar

+ +
    +
  • SPARQL - Protocol and RDF Query Language - El lenguaje utilizado para interrogar bases de datos RDF u orientadas a grafos.
  • +
  • RDF - Resource Description Framework - Un método para estructurar datos en forma de grafo o como una red de declaraciones conectadas más que como una serie de tablas.
  • +
  • LOD - Linked Open Data (datos abiertos enlazados) - LOD son datos RDF publicados online en formato URI de modo que los desarrolladores pueden referenciarlos de manera fiable y sin ambigüedad.
  • +
  • declaración - a veces denominada “tripleta”, una declaración RDF es una unidad de conocimiento que comprende sujeto, predicado y objeto.
  • +
  • URI - Uniform Resource Identifier - una cadena de caracteres que identifica un recurso. Las declaraciones RDF utilizan URI para enlazar varios recursos. Una URL, o Uniform Resource Locator, es un tipo de URI que apunta a un determinado recurso en la web.
  • +
  • literal - En las declaraciones RDF, algunos objetos no referencian recursos con una URI sino que vehiculan un valor, que puede ser un texto ("Rembrandt van Rijn"), un número (5) o una fecha (1606-06-15). Estos objetos se conocen como literales.
  • +
  • prefijo - A fin de simplificar las consultas SPARQL, un usuario puede especificar prefijos que funcionan como abreviaturas de las URI completas. Estas abreviaturas, o QNAmes, se utilizan también en los espacios de nombre (namespaces) de los documentos XML.
  • +
+ +

Consultas basadas en casos reales

+ +

Todas las declaraciones para un objeto

+ +

Vamos a empezar nuestra primera consulta utilizando el punto de entrada SPARQL del British Museum. Un punto de entrada SPARQL es una dirección web que acepta consultas SPARQL y devuelve resultados. El punto de entrada del British Museum funciona como muchos otros: cuando accedemos a él a través de un navegador web, encontramos una caja de texto para componer las consultas.

+ +
+ Web del punto de entrada SPARQL del British Museum. Para todas las consultas de este tutorial, hay que asegurarse de haber dejado las casillas 'Include inferred' y 'Expand results over equivalent URIs' sin marcar. +
+

Web del punto de entrada SPARQL del British Museum. Para todas las consultas de este tutorial, hay que asegurarse de haber dejado las casillas ‘Include inferred’ y ‘Expand results over equivalent URIs’ sin marcar.

+ +
+
+ +

Cuando empezamos a explorar una nueva base de datos RDF, resulta últil examinar, a modo de ejemplo, las relaciones que emanan de un objeto en concreto.

+ +

(Para cada una de las siguientes consultas, clica en el enlace “Run query” situado más abajo para ver los resultados. La puedes ejecutar tal y como está o modificarla antes. En este último caso, recuerda que es necesario dejar sin marcar la casilla “Include inferred” antes de ejecutar la consulta).

+ +
SELECT ?p ?o
+WHERE {
+	<http://collection.britishmuseum.org/id/object/PPA82633> ?p ?o .
+}
+
+ +

Run query

+ +

Con la orden SELECT ?p ?o, le estamos diciendo a la base de datos que nos devuelva los valores de ?p y ?o descritos en el comando WHERE {}. Esta consulta devuelve cada declaración para la cual nuestra obra de arte seleccionada, <http://collection.britishmuseum.org/id/object/PPA82633>, es el sujeto. ?p ocupa la posición central en la declaración RDF en el comando WHERE {}, por lo que esta devuelve cualquier predicado que coincide con la declaración, mientras que ?o, en la posición final, devuelve todos los objetos. Aunque yo las he nombrado como ?p y ?o, en realidad, tal y como se puede ver en el ejemplo inferior, es posible nombrar estas variables del modo que nosotros queramos. De hecho, será útil darles nombres significativos para las consultas complejas que siguen a continuación.

+ +
+ Listado inicial de todos los predicados y objetos asociados con una obra de arte en el British Museum. +
+

Listado inicial de todos los predicados y objetos asociados con una obra de arte en el British Museum.

+ +
+
+ +

El punto de entrada del Britism Museum formatea la tabla de resultados con enlaces para cada una de las variables, que son, en realidad, nodos RDF, por lo que clicando en cada uno de estos enlaces podemos ver todos los predicados y objetos para cada uno de los nodos seleccionados. Advierte que el British Musuem incluye automáticamente un amplio rango de prefijos SPARQL en sus consultas, por lo que encontraremos numerosos enlaces mostrados en su versión abreviada; si pasamos el ratón sobre ellos, podremos ver las URI sin abreviar.

+ +
+ Visualización del conjunto de nodos recuperados a través de la primera consulta realizada a la base de datos del British Museum. Los elementos de este grafo coloreados en rojo se encuentran también en la tabla de resultados mostrada más arriba. Se han incluido niveles adicionales en la jerarquía para mostrar cómo esta obra en particular se encuentra conectada en el grafo general que constituye la base de datos del BM. +
+

Visualización del conjunto de nodos recuperados a través de la primera consulta realizada a la base de datos del British Museum. Los elementos de este grafo coloreados en rojo se encuentran también en la tabla de resultados mostrada más arriba. Se han incluido niveles adicionales en la jerarquía para mostrar cómo esta obra en particular se encuentra conectada en el grafo general que constituye la base de datos del BM.

+ +
+
+ +

Veamos ahora cómo se almacena la información de tipo objeto: busca el predicado <bmo:PX_object_type> (marcado en la tabla anterior) y clica en el enlace thes:x8577 para acceder al nodo que describe el tipo de objeto “print” (grabado).

+ +
+ Página del recurso `thes:x8577` ('print') en el conjunto de datos enlazados del British Museum. +
+

Página del recurso thes:x8577 (‘print’) en el conjunto de datos enlazados del British Museum.

+ +
+
+ +

Como se puede observar, este nodo tiene una etiqueta (label) en texto plano, así como enlaces a nodos del tipo “objetos artísticos” con los que se relaciona en el conjunto de la base de datos.

+ +

Consultas complejas

+ +

Para encontrar otros objetos del mismo tipo descritos con la etiqueta “print”, podemos invocar esta consulta:

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+
+SELECT ?object
+WHERE {
+
+  # Busca todos los valores de ?object que tengan un "object type" dado
+  ?object bmo:PX_object_type ?object_type .
+
+  # El "object type" debería tener la etiqueta "print"
+  ?object_type skos:prefLabel "print" .
+}
+LIMIT 10
+
+ +

Run query / User-generated query

+ +
+ Tabla resultantes de nuestra consulta para todos los objetos del tipo 'print'. +
+

Tabla resultantes de nuestra consulta para todos los objetos del tipo ‘print’.

+ +
+
+ +

Recuerda que, dado que "print" funciona aquí como un literal, lo escribimos entrecomillado en nuestra consulta. Cuando se incluyen literales en las consultas SPARQL, la base de datos solo devuelve coincidencias exactas para estos valores.

+ +

Advierte también que, dado que ?object_type no se encuentra presente en el comando SELECT, este no se mostrará en la tabla de resultados. Sin embargo, resulta esencial estructurar nuestra consulta, porque es esto lo que permite conectar los puntos desde ?object con la etiqueta "print".

+ +

FILTER

+ +

En los ejemplos anteriores, nuestra consulta SPARQL ha buscado una coincidencia exacta para el tipo de objeto con la etiqueta “print”. Sin embargo, con frecuencia querremos encontrar valores literales que caen dentro de un determinado rango, como son las fechas. Para ello utilizaremos el comando FILTER.

+ +

Para localizar las URI de todos los grabados presentes en la base de datos del British Museum creados entre 1580 y 1600, necesitaremos, en primer lugar, averiguar dónde se almacenan en la base de datos las fechas en relación con los objetos, y entonces añadir referencias a estas fechas en nuestra consulta. De manera similar al procedimiento que hemos seguido de un único enlace para determinar un tipo de objeto, debemos ahora movernos a través de diversos nodos para encontrar las fechas de producción asociadas a un objeto dado:

+ +
+ Visualización de la parte del modelo de datos del British Museum donde las fechas de producción están conectadas a los objetos. +
+

Visualización de la parte del modelo de datos del British Museum donde las fechas de producción están conectadas a los objetos.

+ +
+
+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+# Recupera enlaces de objetos y fechas de creación
+SELECT ?object ?date
+WHERE {
+
+  # Utilizaremos nuestro comando previo para buscar solo
+  # objetos del tipo "print"
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel "print" .
+
+  # Necesitamos enlazar diversos nodos para encontrar la
+  # fecha de creación asociada con un objeto
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+
+  # Como se ve, es necesario conectar unos cuantos pocos de puntos
+  # para llegar al nodo de la fecha. Ahora que lo tehemos, podemos
+  # filtrar nuestros resultados. Dado que estamos filtrando por fecha,
+  # debemos agregar la etiqueta ^^xsd:date después de nuestra cadena de fecha.
+  # Esta etiqueta le dice a la base de datos que interprete la cadena
+  # "1580-01-01" como la fecha 1 de enero de 1580.
+
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+
+ +

Run query

+ +
+ Todos los grabados del British Museum realizados entre 1580-1600. +
+

Todos los grabados del British Museum realizados entre 1580-1600.

+ +
+
+ +

Agregación

+ +

Hasta ahora, solo hemos utilizado el comando SELECT para recuperar una tabla de objetos. Sin embargo, SPARQL nos permite realizar análisis muchos más avanzados, como agrupaciones, cálculos y clasificaciones.

+ +

Pongamos por caso que estuviésemos interesados en examinar los objetos realizados entre 1580 y 1600, pero que asimismo quisiésemos conocer cuántos objetos de cada tipo tiene el British Museum en su colección. En vez de limitar nuestros resultados a los objetos del tipo “print”, en este caso utilizaríamos el operador COUNT para sumar los resultados de nuestra búsqueda en función del tipo al que pertenezcan.

+ +
PREFIX bmo: <http://www.researchspace.org/ontology/>
+PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
+PREFIX ecrm: <http://www.cidoc-crm.org/cidoc-crm/>
+PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+
+SELECT ?type (COUNT(?type) as ?n)
+WHERE {
+  # Es necesario que indiquemos la variable ?object_type,
+  # sin embargo, ahora no es necesario que esta coincida con el valor "print"
+
+  ?object bmo:PX_object_type ?object_type .
+  ?object_type skos:prefLabel ?type .
+
+  # De nuevo, filtraremos por fecha
+  ?object ecrm:P108i_was_produced_by ?production .
+  ?production ecrm:P9_consists_of ?date_node .
+  ?date_node ecrm:P4_has_time-span ?timespan .
+  ?timespan ecrm:P82a_begin_of_the_begin ?date .
+  FILTER(?date >= "1580-01-01"^^xsd:date &&
+         ?date <= "1600-01-01"^^xsd:date)
+}
+# El comando GROUP BY designa la variable que se sumará,
+# y el comando ORDER BY DESC() clasifica los resultados
+# en orden descedente.
+
+GROUP BY ?type
+ORDER BY DESC(?n)
+
+ +

Run query

+ +
+ Recuento de los objetos producidos entre 1580 y 1600 según el tipo al que pertenecen. +
+

Recuento de los objetos producidos entre 1580 y 1600 según el tipo al que pertenecen.

+ +
+
+ +

Enlazando múltiples puntos de entrada SPARQL

+ +
2018-06-13: Desafortunadamente, Europeana ha eliminado la opción de enlazar puntos de entrada externos por medio de consultas `SERVICE`, y, en consecuencia, esta sección ha dejado de funcionar. Mantenemos el texto que sigue porque creemos que puede tener valor como referencia y porque esperamos que el servicio de Europeana vuelva a estar operativo en el futuro.
+ +

Hasta ahora, hemos construido consultas que buscan patrones en un único conjunto de datos. Sin embargo, el escenario ideal al que aspiran los partidarios de LOD viene dado por la posibilidad de enlazar múltiples bases de datos, lo que permitirá realizar consultas mucho más complejas al estar estas basadas en el conocimiento distribuido que es posible extraer de diversos espacios web. No obstante, esto resulta más fácil de decir que de hacer, y muchos puntos de entrada (incluido el del British Museum) todavía no referencian recursos de autoridad externos.

+ +

Un punto de entrada que sí lo hace es el de Europeana. Europeana ha creado enlaces entre los objetos de sus bases de datos y los registros de personas en DBPedia y VIAF, los registros de lugares en GeoNames, y los conceptos resgistrados el Tesauro de Arte y Arquitectura (AAT) del Getty Research Institute. SPARQL nos permite insertar declaraciones SERVICE que ordenan a la base de datos “llamar a un amigo” y ejecutar una porción de la consulta en una base de datos externa, utilizando estos resultados para completar la consulta en la base de datos local. Si bien esta lección no se dentendrá en los modelos de datos de Europeana y DBPedia en profundidad, la siguiente consulta nos permite ver cómo funciona la declaración SELECT. Cada uno de los lectores puede ejecutarla por sí mismo copiando y pegando el texto de la consulta en el punto de entrada de Europeana. (A fin de que la consulta funcione, en el punto de entrada de Europeana se debe configurar el menú “Sponging” para “Retrieve remote RDF data for all missing source graphs”).

+ +
PREFIX ore:    <http://www.openarchives.org/ore/terms/>
+PREFIX edm:    <http://www.europeana.eu/schemas/edm/>
+PREFIX rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX dbo:    <http://dbpedia.org/ontology/>
+PREFIX dbr:    <http://dbpedia.org/resource/>
+PREFIX rdaGr2: <http://rdvocab.info/ElementsGr2/>
+
+# Encuentra todos los ?object relacionados por alguna ?property con un ?agent nacido en una
+# ?dutch_city
+SELECT ?object ?property ?agent ?dutch_city
+WHERE {
+    ?proxy ?property ?agent .
+    ?proxy ore:proxyFor ?object .
+
+    ?agent rdf:type edm:Agent .
+    ?agent rdaGr2:placeOfBirth ?dutch_city .
+
+    # En DBPedia, ?dutch_city está definida por pertenecer al país "Netherlands"
+    # La declaración SERVICE pregunta a
+    # http://dbpdeia.org/sparql qué ciudades pertenecen al país
+    # "Netherlands". La respuesta obtenida de esta subconsulta se utilizará para
+    # completar nuestra consulta originaria sobre los objetos
+    # presentes en la base de datos de Europeana
+
+    SERVICE <http://dbpedia.org/sparql> {
+        ?dutch_city dbo:country dbr:Netherlands .
+   }
+}
+# Potencialmente, esta consulta puede devolvernos un elevado número de objetos, por lo que vamos
+# a solicitar solo los cien primeros a fin de agilizar la búsqueda
+LIMIT 100
+
+ +
+ Visualización de la secuencia de la consulta de la solicitud SPARQL definida más arriba. +
+

Visualización de la secuencia de la consulta de la solicitud SPARQL definida más arriba.

+ +
+
+ +

Una consulta interconectada como esta significa que podemos interrogar a Europeana sobre los objetos que cuentan con información geográfica (¿cuáles son las ciudades de Holanda?) sin necesidad de que Europeana tenga que almacenar y mantener esta información por sí misma. Es de esperar que, en el futuro, cada vez mayor cantidad de información LOD de carácter cultural esté enlazada con bases de datos autorizadas, como el ULAN (Union List of Artist Names) del Getty Research Institute. Esto permitirá, por ejemplo, que el British Museum “externalice” la información biográfica acudiendo a los recursos más completos del GRI.

+ +

Trabajando con resultados SPARQL

+ +

Una vez que hemos construido y ejecutado una consulta, ¿qué hacemos ahora con estos resultados? Muchos puntos de entrada, como el del British Museum, ofrecen un navegador web que devuelve resultados legibles para los humanos. Sin embargo, el objetivo de los puntos de entrada SPARQL (y para eso están diseñados) es devolver datos estructurados para ser utilizados por otros programas.

+ +

Exportar resultados en formato CSV

+ +

En la esquina superior derecha de la página de resultados del punto de entrada del BM, se encuentran enlaces para descargas en formato JSON y XML. Otros puntos de entrada también pueden ofrecer la opción de descargar los resultados en CSV/TSV; sin embargo, esta opción no siempre se encuentra disponible. Las salidas JSON y XML desde un punto de entrada SPARQL contienen no solo los valores devueltos por la declaración SELECT, sino también metadatos adicionales sobre tipos de variables e idiomas.

+ +

El procesamiento de la versión XML de los resultados se puede realizar con herramientas tales como Beautiful Soup (véase la lección correspondiente en The Programming Historian u OpenRefine). Para convertir rápidamente los resultados JSON desde un punto de entrada SPARQL en un formato tabular, yo recomiendo la utilidad de la línea de comando gratuita jg. (Para un tutorial sobre cómo utilizar programas de línea de comando, véase “Introduction to the Bash Command Line”). La siguiente consulta convertirá el formato especial JSON RDF en un fichero CSV, que podremos cargar en nuestro programa preferido para su posterior análisis y visualización:

+ +
jq -r '.head.vars as $fields | ($fields | @csv), (.results.bindings[] | [.[$fields[]].value] | @csv)' sparql.json > sparql.csv
+
+ +

Exportar resultados a Palladio

+ +

La popular plataforma de análisis de datos Palladio puede cargar directamente datos desde un punto de entrada SPARQL. En la parte inferior de la pantalla “Create a new project”, el enlace “Load data from a SPARQL endpoint (beta)” nos proporciona un campo para escribir la dirección del punto de entrada y una caja para la consulta propiamente dicha. Dependiendo del punto de entrada, podemos necesitar especifidar el tipo de fichero de salida en la dirección del punto de entrada; por ejemplo, para cargar datos desde el punto de entrada del British Museum, debemos utilizar la dirección http://collection.britishmuseum.org/sparql.json. Trata de pegar la consulta de agregación que utilizamos más arriba para el recuento de obras de arte según su tipología y clica en “Run query”. Palladio debería mostrar una tabla de previsualización como esta:

+ +
+ Interfaz de Palladio para las consultas SPARQL. +
+

Interfaz de Palladio para las consultas SPARQL.

+ +
+
+ +

Después de previsualizar los datos devueltos por el punto de entrada, clica en en botón “Load data” en la parte inferior de la pantalla para empezar a trabajar con ellos. (Véase esta lección de Programming Historian para un tutorial más detallado sobre Palladio). Por ejemplo, podríamos realizar una consulta que devuelva enlaces a las imágenes de los grabados realizados entre 1580 y 1600, y representar estos datos como una galería de imágenes clasificadas por fecha:

+ +
+ Galería de imágenes con línea de tiempo de sus fechas de creación generada utilizando Palladio. +
+

Galería de imágenes con línea de tiempo de sus fechas de creación generada utilizando Palladio.

+ +
+
+ +

Adviértase que Palladio está diseñado para funcionar con un conjunto relativamente pequeño de datos (del orden de cientos de miles de filas, no decenas de miles), por lo que pudiera ser necesario utilizar el comando LIMIT, que ya empleamos anteriormente en la consulta en el punto de entrada de Europeana, para reducir el número de resultados obtenidos y así evitar que el programa se quede bloqueado.

+ +

Lecturas adicionales

+ +

En este tutorial hemos examinado la estructura de LOD y hemos realizado un ejemplo real de cómo escribir consultas SPARQL para la base de datos del British Museum. También hemos aprendido cómo utilizar comandos de agregación en SPARQL para agrupar, contar y clasificar resultados más allá de la simple operación de listarlos.

+ +

Con todo, existen otras muchas maneras de modificar estas consultas, tales como introducir operadores OR y UNION (para describir consultas condicionales) y declaraciones CONSTRUCT (para inferir nuevos enlaces basados en reglas definidas), búsqueda de texto completo o llevar a cabo otras operaciones matemáticas más complejas que la del recuento. Para un informe más detallado de los comandos disponibles en SPARQL, véanse estos enlaces:

+ + + +

Tanto la web de Europeana como la del Getty Vocabularies ofrecen ejemplos extensos y bastante complejos de consultas que pueden constituir buenos recursos para comprender cómo buscar en sus datos:

+ + + +
+ + + + + + + + + +
+
Acerca del autor
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Matthew Lincoln es desarrollador de humanidades digitales en la Universidad Carnegie Mellon e historiador del arte de la Europa moderna. + ORCID id icon

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + +
+ + + + +
Cita sugerida
+
+

+ + + +Matthew Lincoln, + "Uso de SPARQL para acceder a datos abiertos enlazados", + traducido por + Nuria Rodríguez Ortega, + The Programming Historian en español 1 (2017), + https://doi.org/10.46430/phes0027.

+
+
+ + + +

¡Haz una donación!

+

Producir buenos tutoriales de acceso abierto cuesta dinero. Únete al creciente número de personas que apoya a The Programming Historian para que podamos continuar compartiendo conocimientos de forma gratuita.

+
+ + + +
+ + + + + + + + + + + + + +
+ + +