Update schema and improve manual page MPSPARQL-29
[mp-sparql-moved-to-github.git] / bibframe / triplestore.xml
1 <?xml version="1.0"?>
2
3 <!-- 
4 Mp-sparql example configuration
5
6 This config file snippet is typically included from the main Metaproxy
7 configuration. It sets up a simple chain that consists of the sparql 
8 filter to translate the queries etc, and a http_client filter that is used
9 to do the actual communication to the triple store.
10
11 This config provides quite many databases, one for each major type of
12 records. The most important are "work" and "instance". These have a great
13 number of indexes.  There is a number of "small" databases like "person",
14 "meeting" and "topic". These have one main index, named after the database
15 name, for example "bf.person".  The "node" database can search for any node
16 in the database, and "info" returns simple information about available
17 databases.
18
19 There are other databases defined in this file, but they are only used 
20 internally, to be included in the real database definitions. All real,
21 searchable databases have
22   schema="sparql-results"
23 in the db tag, whereas those for include use only do not.
24
25 All databases support the BF-L ("Link") schema, which returns the triples 
26 of the nodes found in the database, without expanding anything. Most of them 
27 also support BF-V ("Verbose") schema that expands those links to return a set
28 of triples that is more or less self contained. A work, its instances, titles
29 for all of them, authors, and their names, etc.
30
31
32
33
34 -->
35
36 <filters  xmlns="http://indexdata.com/metaproxy">
37     <filter type="sparql">
38
39         <!-- Which sparql server to use, our demo, or your local installation -->
40         <!--defaults uri="http://bibframe.indexdata.com/sparql/"/-->
41         <defaults uri="http://localhost:8890/sparql/"/>
42
43         <!-- "thing" database that will be included all real databases -->
44         <db path="thing">  <!-- no schema, so it is not directly searchable -->
45             <prefix>bf: http://bibframe.org/vocab/</prefix>
46             <form>SELECT DISTINCT ?thing </form>
47
48             <!-- Common indexes -->
49
50             <!-- bf.uri is a simple way to get to a thing -->
51             <index type="bf.uri">
52                 ?thing  %v_rel %v_obj FILTER( ?thing  = %u )
53             </index>
54
55             <!-- bf.type is a simple way to search for types -->
56             <!-- for example, a bf.Work can also be bf:Text or bf:Audio -->
57             <index type="bf.type">
58                 ?thing  a %t
59             </index>
60
61             <!-- Find all nodes that refer to the given uri -->
62             <!-- useful after finding uris in the "small" bases -->
63             <!-- direct references only -->
64             <index type="bf.ref">
65                 ?thing %v_rel %u
66             </index>
67
68
69             <!-- The BF-L present format is the same for everything -->
70             <!-- Each db is supposed to provide a dedicated BF-V present format -->
71             <present type="BF-L">
72                 CONSTRUCT {
73                     %u ?rel ?subj
74                 }
75                 WHERE {
76                     %u ?rel ?subj .
77                 }
78             </present>
79
80         </db>
81
82         <!-- "smallindex" db that will be included in work and instance -->
83         <!-- It provides the small indexes like bf.person, bf.place, etc -->
84         <!-- These match a person, etc, no matter what the relation to that -->
85         <!-- is, as long as there is a direct link -->
86         <!-- The %v gets assigned a new variable name, like ?v0. -->
87         <!-- The %vx gets the same ?v0, with the x suffixed to it, by regular -->
88         <!-- This way, we use a different variable for each index clause, and -->
89         <!-- do not get into trouble if we have an AND between two of the same kind -->
90         <db path="smallindex">
91             <index type="bf.person">
92                 ?thing ?rel %vx .
93                 %vx a bf:Person .
94                 %vx bf:label %v FILTER(contains(%v, %s))
95             </index>
96             <index type="bf.topic">
97                 ?thing ?rel %vx .
98                 %vx a bf:Topic .
99                 %vx bf:label %v FILTER(contains(%v, %s))
100             </index>
101             <index type="bf.place">
102                 ?thing ?rel %vx .
103                 %vx a bf:Place .
104                 %vx bf:label %v FILTER(contains(%v, %s))
105             </index>
106             <index type="bf.agent">
107                 ?thing ?rel %vx .
108                 %vx a bf:Agent .
109                 %vx bf:label %v FILTER(contains(%v, %s))
110             </index>
111             <index type="bf.meeting">
112                 ?thing ?rel %vx .
113                 %vx a bf:Meeting .
114                 %vx bf:label %v FILTER(contains(%v, %s))
115             </index>
116             <index type="bf.organization">
117                 ?thing ?rel %vx .
118                 %vx a bf:Organization .
119                 %vx bf:label %v FILTER(contains(%v, %s))
120             </index>
121             <index type="bf.event">
122                 ?thing ?rel %vx .
123                 %vx a bf:Event .
124                 %vx bf:label %v FILTER(contains(%v, %s))
125             </index>
126         </db>
127
128         <!-- work database -->
129
130         <db path="work" schema="sparql-results" include="thing smallindex">
131
132             <!-- The search clause just finds ?things, present is done below -->
133             <criteria>?thing a bf:Work</criteria>
134
135             <!-- Title indexes -->
136             <!-- These are messy, there are so many ways to get to a title -->
137
138             <!-- Main title. Looks logical, but in practice we have not seen -->
139             <!-- many of these -->
140             <index type="bf.title">
141                     ?thing bf:title %v FILTER(contains(%v, %s))
142             </index>
143
144             <!-- worktitle.titleValue seems to be the most common way to -->
145             <!-- store the title of a work -->
146             <index type="bf.worktitle">
147                 ?thing bf:workTitle %v_wt .
148                 %v_wt bf:titleValue %v FILTER(contains(%v, %s))
149             </index>
150
151             <!-- Combining the two above, since users are not likely -->
152             <!-- to know how a given title has been indexed -->
153             <!-- TODO is "maintitle" a good name for this? I made it up myself -->
154             <index type="bf.maintitle">
155                 {
156                     ?thing bf:workTitle %v_wt .
157                     %v_wt bf:titleValue %v FILTER(contains(%v, %s))
158                 } UNION {
159                     ?thing bf:title %v FILTER(contains(%v, %s))
160                 }
161             </index>
162
163             <!-- the worktitle can also contain a subtitle and a parttitle -->
164             <index type="bf.subtitle">
165                 ?thing bf:workTitle %v_wt .
166                 %v_wt bf:subtitle %v FILTER(contains(%v, %s))
167             </index>
168
169             <index type="bf.parttitle">
170                 ?thing bf:workTitle %v_wt .
171                 %v_wt bf:partTitle %v FILTER(contains(%v, %s))
172             </index>
173
174             <!-- work.titlevariation - this could also have sub- and partTitles -->
175             <index type="bf.titlevariation">
176                 ?thing bf:titleVariation %v_tv .
177                 %v_tv bf:titleValue %v FILTER(contains(%v, %s))
178             </index>
179
180             <!-- Instance titles -->
181             <index type="bf.instancetitle">
182                 %v_inst bf:instanceOf ?thing .
183                 %v_inst bf:instanceTitle %v_tit .
184                 %v_tit bf:titleValue %v FILTER(contains(%v, %s))
185             </index>
186
187             <!-- Combined title index. There are so many ways titles can be expresses
188             in Bibframe, this seems to cover most of what we have seen -->
189             <index type="bf.anytitle">
190                 {
191                     ?thing bf:title %v FILTER(contains(%v, %s))
192                 } UNION { <!-- any kind of link -->
193                     ?thing ?titlerel %v_ti . <!-- mostly workTitle, but others too -->
194                     %v_ti a bf:Title <!-- to something that is a title -->
195                     {
196                         %v_ti bf:titleValue %v FILTER(contains(%v, %s))
197                     } UNION {
198                         %v_ti bf:partTitle %v FILTER(contains(%v, %s))
199                     } UNION {
200                         %v_ti bf:subtitle %v FILTER(contains(%v, %s))
201                     }
202                 } UNION {
203                     %v_inst bf:instanceOf ?thing .
204                     %v_inst bf:instanceTitle %v_ti .
205                     %v_ti bf:titleValue %v FILTER(contains(%v, %s))
206                 }
207             </index>
208
209             <!-- Author indexes. Much simpler than titles. -->
210             <index type="bf.creator">
211                 ?thing bf:creator %v_c .
212                 %v_c bf:label %v FILTER(contains(%v, %s))
213             </index>
214
215             <index type="bf.contributor">
216                 ?thing bf:contributor %v_c .
217                 %v_c bf:label %v FILTER(contains(%v, %s))
218             </index>
219
220             <index type="bf.anyauthor"> <!-- TODO - Is this a good name? -->
221                 {
222                     ?thing bf:creator %v_c .
223                     %v_c bf:label %v FILTER(contains(%v, %s))
224                 } UNION {
225                     ?thing bf:contributor %v_c .
226                     %v_c bf:label %v FILTER(contains(%v, %s))
227                 }
228             </index>
229
230             <!-- Subjects -->
231             <!-- Note that these refer to anything with a bf:subject relation -->
232             <!-- The actual item is likely to be something like topic person etc -->
233             <index type="bf.subject">
234                 ?thing bf:subject %v_su .
235                 %v_su bf:label %v FILTER(contains(%v, %s))
236             </index>
237
238             <!-- contentCategory can be searched with complete URIs like -->
239             <!-- http://id.loc.gov/vocabulary/contentTypes/txt -->
240             <index type="bf.contentcategory">
241                 ?thing bf:contentCategory %u
242             </index>
243
244             <!-- Find the work that has a given Instance -->
245             <index type="bf.instance">
246                 %v_inst bf:instanceOf ?thing FILTER ( %v_inst = %u)
247             </index>
248
249             <!-- Present formats -->
250             <!-- BF-L comes from the "thing" template -->
251             <!-- BF-V expands all links, even to instances but not other works -->
252             <present type="BF-V">
253                 CONSTRUCT {
254                     %u ?wrel1 ?wobj1 .
255                     ?wobj1 ?wrel2 ?wobj2 .
256                     ?wobj2 ?wrel3 ?wobj3 .
257                     ?inst ?irel1 ?iobj1 .
258                     ?iobj1 ?irel2 ?iobj2 .
259                     ?iobj2 ?irel3 ?iobj3
260                 }
261                 WHERE {
262                     %u a bf:Work .
263                     %u ?wrel1 ?wobj1 .
264
265                     OPTIONAL {
266                         ?wobj1 ?wrel2 ?wobj2
267                             MINUS { ?wobj1 a bf:Work }
268                             MINUS { ?wobj1 a bf:Instance }
269                         OPTIONAL {
270                             ?wobj2 ?wrel3 ?wobj3
271                                 MINUS { ?wobj2 a bf:Work }
272                                 MINUS { ?wobj2 a bf:Instance }
273                         }
274                     }
275                     <!-- Link to the instance(s) -->
276                     OPTIONAL {
277                         ?inst bf:instanceOf %u .
278                         ?inst ?irel1 ?iobj1
279                         OPTIONAL {
280                             ?iobj1 ?irel2 ?iobj2
281                                 MINUS { ?iobj1 a bf:Work }
282                                 MINUS { ?iobj1 a bf:Instance }
283                             OPTIONAL {
284                                 ?iobj2 ?irel3 ?iobj3
285                                     MINUS { ?iobj2 a bf:Work }
286                                     MINUS { ?iobj2 a bf:Instance }
287                             }
288                         }
289                     }
290                 }
291             </present>
292         </db>
293
294         <!-- Instance database -->
295
296         <db path="instance" schema="sparql-results" include="thing smallindex">
297             <criteria>?thing a bf:Instance</criteria>
298
299             <!-- Title indexes -->
300             <!-- These are messy, there are so many ways to get to a title -->
301
302             <!-- Main title. Looks logical. Many instances seem to have a title -->
303             <index type="bf.title">
304                 ?thing bf:title %v FILTER(contains(%v, %s))
305             </index>
306
307             <!-- instancetitle is also pretty common -->
308             <index type="bf.instancetitle">
309                 ?thing bf:instanceTitle %v_it .
310                 %v_it bf:titleValue %v FILTER(contains(%v, %s))
311             </index>
312
313             <index type="bf.titlestatement">
314                 ?thing bf:titleStatement %v FILTER(contains(%v, %s))
315             </index>
316
317             <!-- Combining the two above, since users are not likely to know how
318             a given title has been indexed -->
319             <index type="bf.maintitle">
320                 {
321                     ?thing bf:instanceTitle %v_it .
322                     %v_it bf:titleValue %v FILTER(contains(%v, %s))
323                 } UNION {
324                     ?thing bf:title %v FILTER(contains(%v, %s))
325                 }
326             </index>
327
328
329             <!-- the instancetitle can also contain a subtitle and a parttitle -->
330             <index type="bf.subtitle">
331                 ?thing bf:instanceTitle %v_it .
332                 %v_it bf:subtitle %v FILTER(contains(%v, %s))
333             </index>
334
335             <index type="bf.parttitle">
336                 ?thing bf:instanceTitle %v_it .
337                 %v_it bf:partTitle %v FILTER(contains(%v, %s))
338             </index>
339             <!-- We could also go to the works, and get those titles... -->
340
341             <!-- Combining any kind of title into one index -->
342             <index type="bf.anytitle">
343                 {
344                     ?thing bf:title %v FILTER(contains(%v, %s))
345                 } UNION {
346                     ?thing bf:titleStatement %v FILTER(contains(%v, %s))
347                 } UNION {
348                     ?thing ?titlerel %v_it . <!-- any kind of link -->
349                     %v_it a bf:Title <!-- to something that is a title -->
350                     {
351                         %v_it bf:titleValue %v FILTER(contains(%v, %s))
352                     } UNION {
353                         %v_it bf:partTitle %v FILTER(contains(%v, %s))
354                     } UNION {
355                         %v_it bf:subtitle %v FILTER(contains(%v, %s))
356                     }
357                 }
358             </index>
359
360             <!-- Author indexes. Many instances don't have any, works do -->
361             <index type="bf.creator">
362                 ?thing bf:creator %v_cr .
363                 %v_cr bf:label %v FILTER(contains(%v, %s))
364             </index>
365
366             <index type="bf.workcreator">
367                 ?thing bf:instanceOf %v_work .
368                 %v_work bf:creator %v_cr .
369                 %v_cr bf:label %v FILTER(contains(%v, %s))
370             </index>
371
372             <index type="bf.workcontributor">
373                 ?thing bf:instanceOf %v_work .
374                 %v_work bf:contributor %v_co .
375                 %v_co bf:label %v FILTER(contains(%v, %s))
376             </index>
377
378             <index type="bf.contributor">
379                 ?thing bf:contributor %v_co .
380                 %v_co bf:label %v FILTER(contains(%v, %s))
381             </index>
382
383             <index type="bf.anyauthor">
384                 {
385                     ?thing bf:creator %v_cr .
386                     %v_cr bf:label %v FILTER(contains(%v, %s))
387                 } UNION {
388                     ?thing bf:contributor %v_co .
389                     %v_co bf:label %v FILTER(contains(%v, %s))
390                 } UNION {
391                     ?thing bf:instanceOf %v_work .
392                     %v_work bf:creator %v_wcr .
393                     %v_wcr bf:label %v FILTER(contains(%v, %s))
394                 } UNION {
395                     ?thing bf:instanceOf %v_work .
396                     %v_work bf:contributor %v_wco .
397                     %v_wco bf:label %v FILTER(contains(%v, %s))
398                 }
399             </index>
400
401             <!-- isbn index. The Instance may contain a isbn10 or isbn13. -->
402             <!-- These can be literal values like -->
403             <!--   http://isbn.example.org/1906833214 which we need to search -->
404             <!-- by our usual substring match. Or they can be links to Identivfiers -->
405             <!-- which will have a proper identifierValue on which we can do -->
406             <!-- an exact match.  -->
407             <index type="bf.isbn">
408                 {
409                     ?thing bf:isbn10  %v
410                         FILTER(isUri(%v) &amp;&amp; contains(str(%v), %s))
411                 } UNION {
412                     ?thing bf:isbn13  %v
413                         FILTER(isUri(%v) &amp;&amp; contains(str(%v), %s))
414                 } UNION {
415                     {
416                         ?thing bf:isbn10 %v_isbn
417                     } UNION {
418                         ?thing bf:isbn13 %v_isbn
419                     }
420                     %v_isbn a bf:Identifier  .
421                     %v_isbn bf:identifierValue  %v FILTER( %v = %s )
422                 }
423             </index>
424
425             <!-- lccn number, a simpler index for id numbers -->
426             <index type="bf.lccn">
427                 ?thing bf:lccn %v_lccn .
428                 %v_lccn a bf:Identifier  .
429                 %v_lccn bf:identifierValue  %v FILTER( %v = %s )
430             </index>
431
432             <!-- Find the instances of a given work -->
433             <index type="bf.work">
434                 ?thing bf:instanceOf %u
435             </index>
436
437
438             <!-- Present formats. BF-L comes from "thing" -->
439             <!-- Full instance, with the related work too -->
440             <present type="BF-V">
441                 CONSTRUCT {
442                     %u ?irel1 ?iobj1 .
443                     ?iobj1 ?irel2 ?iobj2 .
444                     ?iobj2 ?irel3 ?iobj3 .
445                     ?work ?wrel1 ?wobj1 .
446                     ?wobj1 ?wrel2 ?wobj2 .
447                     ?wobj2 ?wrel3 ?wobj3
448                 }
449                 WHERE {
450                     %u a bf:Instance .
451                     %u ?irel1 ?iobj1 .
452                     OPTIONAL {
453                         ?iobj1 ?irel2 ?iobj2
454                             MINUS { ?iobj2 a bf:Work }
455                             MINUS { ?iobj2 a bf:Instance } .
456                         OPTIONAL {
457                             ?iobj2 ?irel3 ?iobj3
458                                 MINUS { ?iobj3 a bf:Work }
459                                 MINUS { ?iobj3 a bf:Instance }
460                         }
461                     }
462                     OPTIONAL { <!-- Work -->
463                         %u bf:instanceOf ?work .
464                         ?work ?wrel1 ?wobj1 .
465                         OPTIONAL {
466                             ?wobj1 ?wrel2 ?wobj2
467                                 MINUS { ?wobj1 a bf:Work }
468                                 MINUS { ?wobj1 a bf:Instance } .
469                             OPTIONAL {
470                                 ?wobj2 ?wrel3 ?wobj3
471                                     MINUS { ?wobj2 a bf:Work }
472                                     MINUS { ?wobj2 a bf:Instance }
473                             }
474                         }
475                     }
476                 }
477             </present>
478
479         </db>
480
481         <!-- Small databases -->
482
483         <!-- "small" contains all the things common to all small databases -->
484         <!-- It is only to be used as an include, it is not searchable, since -->
485         <!-- it has no schema atribute -->
486         <!-- It is divided into "smallbody", and a "small" that includes -->
487         <!-- the general indexes, so that title searches can include the body, -->
488         <!-- but have different "any" indexes -->
489
490         <db path="smallbody" include="thing">
491             <present type="BF-V">
492                 <!-- I don't think we need more than one level -->
493                 <!--for these simple databases -->
494                 CONSTRUCT {
495                     %u ?rel ?obj .
496                     ?obj ?rel1 ?obj1 .
497                 }
498                 WHERE {
499                     %u ?rel ?obj .
500                     OPTIONAL { ?obj ?rel1 ?obj1 }
501                 }
502             </present>
503         </db>
504
505         <!-- The combined "small" database defaults -->
506         <db path="small" include="smallbody">
507             <index type="any">
508                 ?thing bf:label %v FILTER(contains(%v, %s))
509             </index>
510             <index type="1016">
511                 ?thing bf:label %v FILTER(contains(%v, %s))
512             </index>
513         </db>
514
515         <!-- Various "small" databases, leaning heavily on the defaults above -->
516         <db path="place" schema="sparql-results" include="small" >
517             <criteria>?thing a bf:Place</criteria>
518             <index type="bf.place">
519                 ?thing bf:label %v FILTER(contains(%v, %s))
520             </index>
521         </db>
522
523         <db path="person" schema="sparql-results" include="small" >
524             <criteria>?thing a bf:Person</criteria>
525             <index type="bf.person">
526                 ?thing bf:label %v FILTER(contains(%v, %s))
527             </index>
528         </db>
529
530         <db path="meeting" schema="sparql-results" include="small" >
531             <criteria>?thing a bf:Meeting</criteria>
532             <index type="bf.meeting">
533                 ?thing bf:label %v FILTER(contains(%v, %s))
534             </index>
535         </db>
536
537         <db path="agent" schema="sparql-results" include="small" >
538             <criteria>?thing a bf:Agent</criteria>
539             <index type="bf.agent">
540                 ?thing bf:label %v FILTER(contains(%v, %s))
541             </index>
542         </db>
543
544         <db path="event" schema="sparql-results" include="small" >
545             <criteria>?thing a bf:Event</criteria>
546             <index type="bf.event">
547                 ?thing bf:label %v FILTER(contains(%v, %s))
548             </index>
549         </db>
550
551         <db path="organization" schema="sparql-results" include="small" >
552             <criteria>?thing a bf:Organization</criteria>
553             <index type="bf.organization">
554                 ?thing bf:label %v FILTER(contains(%v, %s))
555             </index>
556         </db>
557
558         <db path="topic" schema="sparql-results" include="small" >
559             <criteria>?thing a bf:Topic</criteria>
560             <index type="bf.topic">
561                 ?thing bf:label %v FILTER(contains(%v, %s))
562             </index>
563         </db>
564
565         <!-- Title search, for seatching Title objects. -->
566         <!-- Not sure if this is needed, but it is a nice example -->
567         <db path="title" schema="sparql-results" include="smallbody" >
568             <criteria>?thing a bf:Title</criteria>
569
570             <index type="any">
571                 {
572                     ?thing bf:titleValue %v FILTER(contains(%v, %s))
573                 } UNION {
574                     ?thing bf:subtitle %v FILTER(contains(%v, %s))
575                 } UNION {
576                     ?thing bf:partTitle %v FILTER(contains(%v, %s))
577                 }
578             </index>
579
580             <index type="1016">
581                 {
582                     ?thing bf:titleValue %v FILTER(contains(%v, %s))
583                 } UNION {
584                     ?thing bf:subtitle %v FILTER(contains(%v, %s))
585                 } UNION {
586                     ?thing bf:partTitle %v FILTER(contains(%v, %s))
587                 }
588             </index>
589
590             <index type="bf.title">
591                 ?thing bf:titleValue %v FILTER(contains(%v, %s))
592             </index>
593
594             <index type="bf.subtitle">
595                 ?thing bf:subtitle %v FILTER(contains(%v, %s))
596             </index>
597
598             <index type="bf.parttitle">
599                 ?thing bf:partTitle %v FILTER(contains(%v, %s))
600             </index>
601         </db>
602
603         <!-- A hack to be able to look at any triplet in the base -->
604         <!-- The indexes bf.uri and bf.ref can also come in handy here -->
605         <db path="node" schema="sparql-results" include="smallbody">
606             <index type="any">
607                 ?thing ?rel ?obj FILTER( str(?thing) = %s )
608             </index>
609         </db>
610
611     </filter>
612
613     <filter type="log">
614         <message>http</message>
615     </filter>
616
617     <filter type="http_client">
618         <x-forwarded-for>true</x-forwarded-for>
619     </filter>
620 </filters>