1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742 10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758 10759 10760 10761 10762 10763 10764 10765 10766 10767 10768 10769 10770 10771 10772 10773 10774 10775 10776 10777 10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802 10803 10804 10805 10806 10807 10808 10809 10810 10811 10812 10813 10814 10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896 10897 10898 10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937 10938 10939 10940 10941 10942 10943 10944 10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979 10980 10981 10982 10983 10984 10985 10986 10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004 11005 11006 11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023 11024 11025 11026 11027 11028 11029 11030 11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134 11135 11136 11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184 11185 11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203 11204 11205 11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248 11249 11250 11251 11252 11253 11254 11255 11256 11257 11258 11259 11260 11261 11262 11263 11264 11265 11266 11267 11268 11269 11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289 11290 11291 11292 11293 11294 11295 11296 11297 11298 11299 11300 11301 11302 11303 11304 11305 11306 11307 11308 11309 11310 11311 11312 11313 11314 11315 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333 11334 11335 11336 11337 11338 11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351 11352 11353 11354 11355 11356 11357 11358 11359 11360 11361 11362 11363 11364 11365 11366 11367 11368 11369 11370 11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409 11410 11411 11412 11413 11414 11415 11416 11417 11418 11419 11420 11421 11422 11423 11424 11425 11426 11427 11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438 11439 11440 11441 11442 11443 11444 11445 11446 11447 11448 11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464 11465 11466 11467 11468 11469 11470 11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494 11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668 11669 11670 11671 11672 11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685 11686 11687 11688 11689 11690 11691 11692 11693 11694 11695 11696 11697 11698 11699 11700 11701 11702 11703 11704 11705 11706 11707 11708 11709 11710 11711 11712 11713 11714 11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729 11730 11731 11732 11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 11827 11828 11829 11830 11831 11832 11833 11834 11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869 11870 11871 11872 11873 11874 11875 11876 11877 11878 11879 11880 11881 11882 11883 11884 11885 11886 11887 11888 11889 11890 11891 11892 11893 11894 11895 11896 11897 11898 11899 11900 11901 11902 11903 11904 11905 11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921 11922 11923 11924 11925 11926 11927 11928 11929 11930 11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945 11946 11947 11948 11949 11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979 11980 11981 11982 11983 11984 11985 11986 11987 11988 11989 11990 11991 11992 11993 11994 11995 11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010 12011 12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023 12024 12025 12026 12027 12028 12029 12030 12031 12032 12033 12034 12035 12036 12037 12038 12039 12040 12041 12042 12043 12044 12045 12046 12047 12048 12049 12050 12051 12052 12053 12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081 12082 12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114 12115 12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133 12134 12135 12136 12137 12138 12139 12140 12141 12142 12143 12144 12145 12146 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 12171 12172 12173 12174 12175 12176 12177 12178 12179 12180 12181 12182 12183 12184 12185 12186 12187 12188 12189 12190 12191 12192 12193 12194 12195 12196 12197 12198 12199 12200 12201 12202 12203 12204 12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217 12218 12219 12220 12221 12222 12223 12224 12225 12226 12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274 12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357 12358 12359 12360 12361 12362 12363 12364 12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 12429 12430 12431 12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466 12467 12468 12469 12470 12471 12472 12473 12474 12475 12476 12477 12478 12479 12480 12481 12482 12483 12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499 12500 12501 12502 12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574 12575 12576 12577 12578 12579 12580 12581 12582 12583 12584 12585 12586 12587 12588 12589 12590 12591 12592 12593 12594 12595 12596 12597 12598 12599 12600 12601 12602 12603 12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 12617 12618 12619 12620 12621 12622 12623 12624 12625 12626 12627 12628 12629 12630 12631 12632 12633 12634 12635 12636 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651 12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670 12671 12672 12673 12674 12675 12676 12677 12678 12679 12680 12681 12682 12683 12684 12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701 12702 12703 12704 12705 12706 12707 12708 12709 12710 12711 12712 12713 12714 12715 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 12760 12761 12762 12763 12764 12765 12766 12767 12768 12769 12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780 12781 12782 12783 12784 12785 12786 12787 12788 12789 12790 12791 12792 12793 12794 12795 12796 12797 12798 12799 12800 12801 12802 12803 12804 12805 12806 12807 12808 12809 12810 12811 12812 12813 12814 12815 12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828 12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 12921 12922 12923 12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957 12958 12959 12960 12961 12962 12963 12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 12980 12981 12982 12983 12984 12985 12986 12987 12988 12989 12990 12991 12992 12993 12994 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 13020 13021 13022 13023 13024 13025 13026 13027 13028 13029 13030 13031 13032 13033 13034 13035 13036 13037 13038 13039 13040 13041 13042 13043 13044 13045 13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141 13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169 13170 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182 13183 13184 13185 13186 13187 13188 13189 13190 13191 13192 13193 13194 13195 13196 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240 13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 13281 13282 13283 13284 13285 13286 13287 13288 13289 13290 13291 13292 13293 13294 13295 13296 13297 13298 13299 13300 13301 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 13312 13313 13314 13315 13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 13337 13338 13339 13340 13341 13342 13343 13344 13345 13346 13347 13348 13349 13350 13351 13352 13353 13354 13355 13356 13357 13358 13359 13360 13361 13362 13363 13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375 13376 13377 13378 13379 13380 13381 13382 13383 13384 13385 13386 13387 13388 13389 13390 13391 13392 13393 13394 13395 13396 13397 13398 13399 13400 13401 13402 13403 13404 13405 13406 13407 13408 13409 13410 13411 13412 13413 13414 13415 13416 13417 13418 13419 13420 13421 13422 13423 13424 13425 13426 13427 13428 13429 13430 13431 13432 13433 13434 13435 13436 13437 13438 13439 13440 13441 13442 13443 13444 13445 13446 13447 13448 13449 13450 13451 13452 13453 13454 13455 13456 13457 13458 13459 13460 13461 13462 13463 13464 13465 13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478 13479 13480 13481 13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494 13495 13496 13497 13498 13499 13500 13501 13502 13503 13504 13505 13506 13507 13508 13509 13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 13523 13524 13525 13526 13527 13528 13529 13530 13531 13532 13533 13534 13535 13536 13537 13538 13539 13540 13541 13542 13543 13544 13545 13546 13547 13548 13549 13550 13551 13552 13553 13554 13555 13556 13557 13558 13559 13560 13561 13562 13563 13564 13565 13566 13567 13568 13569 13570 13571 13572 13573 13574 13575 13576 13577 13578 13579 13580 13581 13582 13583 13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 13594 13595 13596 13597 13598 13599 13600 13601 13602 13603 13604 13605 13606 13607 13608 13609 13610 13611 13612 13613 13614 13615 13616 13617 13618 13619 13620 13621 13622 13623 13624 13625 13626 13627 13628 13629 13630 13631 13632 13633 13634 13635 13636 13637 13638 13639 13640 13641 13642 13643 13644 13645 13646 13647 13648 13649 13650 13651 13652 13653 13654 13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670 13671 13672 13673 13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689 13690 13691 13692 13693 13694 13695 13696 13697 13698 13699 13700 13701 13702 13703 13704 13705 13706 13707 13708 13709 13710 13711 13712 13713 13714 13715 13716 13717 13718 13719 13720 13721 13722 13723 13724 13725 13726 13727 13728 13729 13730 13731 13732 13733 13734 13735 13736 13737 13738 13739 13740 13741 13742 13743 13744 13745 13746 13747 13748 13749 13750 13751 13752 13753 13754 13755 13756 13757 13758 13759 13760 13761 13762 13763 13764 13765 13766 13767 13768 13769 13770 13771 13772 13773 13774 13775 13776 13777 13778 13779 13780 13781 13782 13783 13784 13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816 13817 13818 13819 13820 13821 13822 13823 13824 13825 13826 13827 13828 13829 13830 13831 13832 13833 13834 13835 13836 13837 13838 13839 13840 13841 13842 13843 13844 13845 13846 13847 13848 13849 13850 13851 13852 13853 13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 13864 13865 13866 13867 13868 13869 13870 13871 13872 13873 13874 13875 13876 13877 13878 13879 13880 13881 13882 13883 13884 13885 13886 13887 13888 13889 13890 13891 13892 13893 13894 13895 13896 13897 13898 13899 13900 13901 13902 13903 13904 13905 13906 13907 13908 13909 13910 13911 13912 13913 13914 13915 13916 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934 13935 13936 13937 13938 13939 13940 13941 13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952 13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966 13967 13968 13969 13970 13971 13972 13973 13974 13975 13976 13977 13978 13979 13980 13981 13982 13983 13984 13985 13986 13987 13988 13989 13990 13991 13992 13993 13994 13995 13996 13997 13998 13999 14000 14001 14002 14003 14004 14005 14006 14007 14008 14009 14010 14011 14012 14013 14014 14015 14016 14017 14018 14019 14020 14021 14022 14023 14024 14025 14026 14027 14028 14029 14030 14031 14032 14033 14034 14035 14036 14037 14038 14039 14040 14041 14042 14043 14044 14045 14046 14047 14048 14049 14050 14051 14052 14053 14054 14055 14056 14057 14058 14059 14060 14061 14062 14063 14064 14065 14066 14067 14068 14069 14070 14071 14072 14073 14074 14075 14076 14077 14078 14079 14080 14081 14082 14083 14084 14085 14086 14087 14088 14089 14090 14091 14092 14093 14094 14095 14096 14097 14098 14099 14100 14101 14102 14103 14104 14105 14106 14107 14108 14109 14110 14111 14112 14113 14114 14115 14116 14117 14118 14119 14120 14121 14122 14123 14124 14125 14126 14127 14128 14129 14130 14131 14132 14133 14134 14135 14136 14137 14138 14139 14140 14141 14142 14143 14144 14145 14146 14147 14148 14149 14150 14151 14152 14153 14154 14155 14156 14157 14158 14159 14160 14161 14162 14163 14164 14165 14166 14167 14168 14169 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180 14181 14182 14183 14184 14185 14186 14187 14188 14189 14190 14191 14192 14193 14194 14195 14196 14197 14198 14199 14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218 14219 14220 14221 14222 14223 14224 14225 14226 14227 14228 14229 14230 14231 14232 14233 14234 14235 14236 14237 14238 14239 14240 14241 14242 14243 14244 14245 14246 14247 14248 14249 14250 14251 14252 14253 14254 14255 14256 14257 14258 14259 14260 14261 14262 14263 14264 14265 14266 14267 14268 14269 14270 14271 14272 14273 14274 14275 14276 14277 14278 14279 14280 14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 14296 14297 14298 14299 14300 14301 14302 14303 14304 14305 14306 14307 14308 14309 14310 14311 14312 14313 14314 14315 14316 14317 14318 14319 14320 14321 14322 14323 14324 14325 14326 14327 14328 14329 14330 14331 14332 14333 14334 14335 14336 14337 14338 14339 14340 14341 14342 14343 14344 14345 14346 14347 14348 14349 14350 14351 14352 14353 14354 14355 14356 14357 14358 14359 14360 14361 14362 14363 14364 14365 14366 14367 14368 14369 14370 14371 14372 14373 14374 14375 14376 14377 14378 14379 14380 14381 14382 14383 14384 14385 14386 14387 14388 14389 14390 14391 14392 14393 14394 14395 14396 14397 14398 14399 14400 14401 14402 14403 14404 14405 14406 14407 14408 14409 14410 14411 14412 14413 14414 14415 14416 14417 14418 14419 14420 14421 14422 14423 14424 14425 14426 14427 14428 14429 14430 14431 14432 14433 14434 14435 14436 14437 14438 14439 14440 14441 14442 14443 14444 14445 14446 14447 14448 14449 14450 14451 14452 14453 14454 14455 14456 14457 14458 14459 14460 14461 14462 14463 14464 14465 14466 14467 14468 14469 14470 14471 14472 14473 14474 14475 14476 14477 14478 14479 14480 14481 14482 14483 14484 14485 14486 14487 14488 14489 14490 14491 14492 14493 14494 14495 14496 14497 14498 14499 14500 14501 14502 14503 14504 14505 14506 14507 14508 14509 14510 14511 14512 14513 14514 14515 14516 14517 14518 14519 14520 14521 14522 14523 14524 14525 14526 14527 14528 14529 14530 14531 14532 14533 14534 14535 14536 14537 14538 14539 14540 14541 14542 14543 14544 14545 14546 14547 14548 14549 14550 14551 14552 14553 14554 14555 14556 14557 14558 14559 14560 14561 14562 14563 14564 14565 14566 14567 14568 14569 14570 14571 14572 14573 14574 14575 14576 14577 14578 14579 14580 14581 14582 14583 14584 14585 14586 14587 14588 14589 14590 14591 14592 14593 14594 14595 14596 14597 14598 14599 14600 14601 14602 14603 14604 14605 14606 14607 14608 14609 14610 14611 14612 14613 14614 14615 14616 14617 14618 14619 14620 14621 14622 14623 14624 14625 14626 14627 14628 14629 14630 14631 14632 14633 14634 14635 14636 14637 14638 14639 14640 14641 14642 14643 14644 14645 14646 14647 14648 14649 14650 14651 14652 14653 14654 14655 14656 14657 14658 14659 14660 14661 14662 14663 14664 14665 14666 14667 14668 14669 14670 14671 14672 14673 14674 14675 14676 14677 14678 14679 14680 14681 14682 14683 14684 14685 14686 14687 14688 14689 14690 14691 14692 14693 14694 14695 14696 14697 14698 14699 14700 14701 14702 14703 14704 14705 14706 14707 14708 14709 14710 14711 14712 14713 14714 14715 14716 14717 14718 14719 14720 14721 14722 14723 14724 14725 14726 14727 14728 14729 14730 14731 14732 14733 14734 14735 14736 14737 14738 14739 14740 14741 14742 14743 14744 14745 14746 14747 14748 14749 14750 14751 14752 14753 14754 14755 14756 14757 14758 14759 14760 14761 14762 14763 14764 14765 14766 14767 14768 14769 14770 14771 14772 14773 14774 14775 14776 14777 14778 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791 14792 14793 14794 14795 14796 14797 14798 14799 14800 14801 14802 14803 14804 14805 14806 14807 14808 14809 14810 14811 14812 14813 14814 14815 14816 14817 14818 14819 14820 14821 14822 14823 14824 14825 14826 14827 14828 14829 14830 14831 14832 14833 14834 14835 14836 14837 14838 14839 14840 14841 14842 14843 14844 14845 14846 14847 14848 14849 14850 14851 14852 14853 14854 14855 14856 14857 14858 14859 14860 14861 14862 14863 14864 14865 14866 14867 14868 14869 14870 14871 14872 14873 14874 14875 14876 14877 14878 14879 14880 14881 14882 14883 14884 14885 14886 14887 14888 14889 14890 14891 14892 14893 14894 14895 14896 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 14909 14910 14911 14912 14913 14914 14915 14916 14917 14918 14919 14920 14921 14922 14923 14924 14925 14926 14927 14928 14929 14930 14931 14932 14933 14934 14935 14936 14937 14938 14939 14940 14941 14942 14943 14944 14945 14946 14947 14948 14949 14950 14951 14952 14953 14954 14955 14956 14957 14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971 14972 14973 14974 14975 14976 14977 14978 14979 14980 14981 14982 14983 14984 14985 14986 14987 14988 14989 14990 14991 14992 14993 14994 14995 14996 14997 14998 14999 15000 15001 15002 15003 15004 15005 15006 15007 15008 15009 15010 15011 15012 15013 15014 15015 15016 15017 15018 15019 15020 15021 15022 15023 15024 15025 15026 15027 15028 15029 15030 15031 15032 15033 15034 15035 15036 15037 15038 15039 15040 15041 15042 15043 15044 15045 15046 15047 15048 15049 15050 15051 15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069 15070 15071 15072 15073 15074 15075 15076 15077 15078 15079 15080 15081 15082 15083 15084 15085 15086 15087 15088 15089 15090 15091 15092 15093 15094 15095 15096 15097 15098 15099 15100 15101 15102 15103 15104 15105 15106 15107 15108 15109 15110 15111 15112 15113 15114 15115 15116 15117 15118 15119 15120 15121 15122 15123 15124 15125 15126 15127 15128 15129 15130 15131 15132 15133 15134 15135 15136 15137 15138 15139 15140 15141 15142 15143 15144 15145 15146 15147 15148 15149 15150 15151 15152 15153 15154 15155 15156 15157 15158 15159 15160 15161 15162 15163 15164 15165 15166 15167 15168 15169 15170 15171 15172 15173 15174 15175 15176 15177 15178 15179 15180 15181 15182 15183 15184 15185 15186 15187 15188 15189 15190 15191 15192 15193 15194 15195 15196 15197 15198 15199 15200 15201 15202 15203 15204 15205 15206 15207 15208 15209 15210 15211 15212 15213 15214 15215 15216 15217 15218 15219 15220 15221 15222 15223 15224 15225 15226 15227 15228 15229 15230 15231 15232 15233 15234 15235 15236 15237 15238 15239 15240 15241 15242 15243 15244 15245 15246 15247 15248 15249 15250 15251 15252 15253 15254 15255 15256 15257 15258 15259 15260 15261 15262 15263 15264 15265 15266 15267 15268 15269 15270 15271 15272 15273 15274 15275 15276 15277 15278 15279 15280 15281 15282 15283 15284 15285 15286 15287 15288 15289 15290 15291 15292 15293 15294 15295 15296 15297 15298 15299 15300 15301 15302 15303 15304 15305 15306 15307 15308 15309 15310 15311 15312 15313 15314 15315 15316 15317 15318 15319 15320 15321 15322 15323 15324 15325 15326 15327 15328 15329 15330 15331 15332 15333 15334 15335 15336 15337 15338 15339 15340 15341 15342 15343 15344 15345 15346 15347 15348 15349 15350 15351 15352 15353 15354 15355 15356 15357 15358 15359 15360 15361 15362 15363 15364 15365 15366 15367 15368 15369 15370 15371 15372 15373 15374 15375 15376 15377 15378 15379 15380 15381 15382 15383 15384 15385 15386 15387 15388 15389 15390 15391 15392 15393 15394 15395 15396 15397 15398 15399 15400 15401 15402 15403 15404 15405 15406 15407 15408 15409 15410 15411 15412 15413 15414 15415 15416 15417 15418 15419 15420 15421 15422 15423 15424 15425 15426 15427 15428 15429 15430 15431 15432 15433 15434 15435 15436 15437 15438 15439 15440 15441 15442 15443 15444 15445 15446 15447 15448 15449 15450 15451 15452 15453 15454 15455 15456 15457 15458 15459 15460 15461 15462 15463 15464 15465 15466 15467 15468 15469 15470 15471 15472 15473 15474 15475 15476 15477 15478 15479 15480 15481 15482 15483 15484 15485 15486 15487 15488 15489 15490 15491 15492 15493 15494 15495 15496 15497 15498 15499 15500 15501 15502 15503 15504 15505 15506 15507 15508 15509 15510 15511 15512 15513 15514 15515 15516 15517 15518 15519 15520 15521 15522 15523 15524 15525 15526 15527 15528 15529 15530 15531 15532 15533 15534 15535 15536 15537 15538 15539 15540 15541 15542 15543 15544 15545 15546 15547 15548 15549 15550 15551 15552 15553 15554 15555 15556 15557 15558 15559 15560 15561 15562 15563 15564 15565 15566 15567 15568 15569 15570 15571 15572 15573 15574 15575 15576 15577 15578 15579 15580 15581 15582 15583 15584 15585 15586 15587 15588 15589 15590 15591 15592 15593 15594 15595 15596 15597 15598 15599 15600 15601 15602 15603 15604 15605 15606 15607 15608 15609 15610 15611 15612 15613 15614 15615 15616 15617 15618 15619 15620 15621 15622 15623 15624 15625 15626 15627 15628 15629 15630 15631 15632 15633 15634 15635 15636 15637 15638 15639 15640 15641 15642 15643 15644 15645 15646 15647 15648 15649 15650 15651 15652 15653 15654 15655 15656 15657 15658 15659 15660 15661 15662 15663 15664 15665 15666 15667 15668 15669 15670 15671 15672 15673 15674 15675 15676 15677 15678 15679 15680 15681 15682 15683 15684 15685 15686 15687 15688 15689 15690 15691 15692 15693 15694 15695 15696 15697 15698 15699 15700 15701 15702 15703 15704 15705 15706 15707 15708 15709 15710 15711 15712 15713 15714 15715 15716 15717 15718 15719 15720 15721 15722 15723 15724 15725 15726 15727 15728 15729 15730 15731 15732 15733 15734 15735 15736 15737 15738 15739 15740 15741 15742 15743 15744 15745 15746 15747 15748 15749 15750 15751 15752 15753 15754 15755 15756 15757 15758 15759 15760 15761 15762 15763 15764 15765 15766 15767 15768 15769 15770 15771 15772 15773 15774 15775 15776 15777 15778 15779 15780 15781 15782 15783 15784 15785 15786 15787 15788 15789 15790 15791 15792 15793 15794 15795 15796 15797 15798 15799 15800 15801 15802 15803 15804 15805 15806 15807 15808 15809 15810 15811 15812 15813 15814 15815 15816 15817 15818 15819 15820 15821 15822 15823 15824 15825 15826 15827 15828 15829 15830 15831 15832 15833 15834 15835 15836 15837 15838 15839 15840 15841 15842 15843 15844 15845 15846 15847 15848 15849 15850 15851 15852 15853 15854 15855 15856 15857 15858 15859 15860 15861 15862 15863 15864 15865 15866 15867 15868 15869 15870 15871 15872 15873 15874 15875 15876 15877 15878 15879 15880 15881 15882 15883 15884 15885 15886 15887 15888 15889 15890 15891 15892 15893 15894 15895 15896 15897 15898 15899 15900 15901 15902 15903 15904 15905 15906 15907 15908 15909 15910 15911 15912 15913 15914 15915 15916 15917 15918 15919 15920 15921 15922 15923 15924 15925 15926 15927 15928 15929 15930 15931 15932 15933 15934 15935 15936 15937 15938 15939 15940 15941 15942 15943 15944 15945 15946 15947 15948 15949 15950 15951 15952 15953 15954 15955 15956 15957 15958 15959 15960 15961 15962 15963 15964 15965 15966 15967 15968 15969 15970 15971 15972 15973 15974 15975 15976 15977 15978 15979 15980 15981 15982 15983 15984 15985 15986 15987 15988 15989 15990 15991 15992 15993 15994 15995 15996 15997 15998 15999 16000 16001 16002 16003 16004 16005 16006 16007 16008 16009 16010 16011 16012 16013 16014 16015 16016 16017 16018 16019 16020 16021 16022 16023 16024 16025 16026 16027 16028 16029 16030 16031 16032 16033 16034 16035 16036 16037 16038 16039 16040 16041 16042 16043 16044 16045 16046 16047 16048 16049 16050 16051 16052 16053 16054 16055 16056 16057 16058 16059 16060 16061 16062 16063 16064 16065 16066 16067 16068 16069 16070 16071 16072 16073 16074 16075 16076 16077 16078 16079 16080 16081 16082 16083 16084 16085 16086 16087 16088 16089 16090 16091 16092 16093 16094 16095 16096 16097 16098 16099 16100 16101 16102 16103 16104 16105 16106 16107 16108 16109 16110 16111 16112 16113 16114 16115 16116 16117 16118 16119 16120 16121 16122 16123 16124 16125 16126 16127 16128 16129 16130 16131 16132 16133 16134 16135 16136 16137 16138 16139 16140 16141 16142 16143 16144 16145 16146 16147 16148 16149 16150 16151 16152 16153 16154 16155 16156 16157 16158 16159 16160 16161 16162 16163 16164 16165 16166 16167 16168 16169 16170 16171 16172 16173 16174 16175 16176 16177 16178 16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191 16192 16193 16194 16195 16196 16197 16198 16199 16200 16201 16202 16203 16204 16205 16206 16207 16208 16209 16210 16211 16212 16213 16214 16215 16216 16217 16218 16219 16220 16221 16222 16223 16224 16225 16226 16227 16228 16229 16230 16231 16232 16233 16234 16235 16236 16237 16238 16239 16240 16241 16242 16243 16244 16245 16246 16247 16248 16249 16250 16251 16252 16253 16254 16255 16256 16257 16258 16259 16260 16261 16262 16263 16264 16265 16266 16267 16268 16269 16270 16271 16272 16273 16274 16275 16276 16277 16278 16279 16280 16281 16282 16283 16284 16285 16286 16287 16288 16289 16290 16291 16292 16293 16294 16295 16296 16297 16298 16299 16300 16301 16302 16303 16304 16305 16306 16307 16308 16309 16310 16311 16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 16324 16325 16326 16327 16328 16329 16330 16331 16332 16333 16334 16335 16336 16337 16338 16339 16340 16341 16342 16343 16344 16345 16346 16347 16348 16349 16350 16351 16352 16353 16354 16355 16356 16357 16358 16359 16360 16361 16362 16363 16364 16365 16366 16367 16368 16369 16370 16371 16372 16373 16374 16375 16376 16377 16378 16379 16380 16381 16382 16383 16384 16385 16386 16387 16388 16389 16390 16391 16392 16393 16394 16395 16396 16397 16398 16399 16400 16401 16402 16403 16404 16405 16406 16407 16408 16409 16410 16411 16412 16413 16414 16415 16416 16417 16418 16419 16420 16421 16422 16423 16424 16425 16426 16427 16428 16429 16430 16431 16432 16433 16434 16435 16436 16437 16438 16439 16440 16441 16442 16443 16444 16445 16446 16447 16448 16449 16450 16451 16452 16453 16454 16455 16456 16457 16458 16459 16460 16461 16462 16463 16464 16465 16466 16467 16468 16469 16470 16471 16472 16473 16474 16475 16476 16477 16478 16479 16480 16481 16482 16483 16484 16485 16486 16487 16488 16489 16490 16491 16492 16493 16494 16495 16496 16497 16498 16499 16500 16501 16502 16503 16504 16505 16506 16507 16508 16509 16510 16511 16512 16513 16514 16515 16516 16517 16518 16519 16520 16521 16522 16523 16524 16525 16526 16527 16528 16529 16530 16531 16532 16533 16534 16535 16536 16537 16538 16539 16540 16541 16542 16543 16544 16545 16546 16547 16548 16549 16550 16551 16552 16553 16554 16555 16556 16557 16558 16559 16560 16561 16562 16563 16564 16565 16566 16567 16568 16569 16570 16571 16572 16573 16574 16575 16576 16577 16578 16579 16580 16581 16582 16583 16584 16585 16586 16587 16588 16589 16590 16591 16592 16593 16594 16595 16596 16597 16598 16599 16600 16601 16602 16603 16604 16605 16606 16607 16608 16609 16610 16611 16612 16613 16614 16615 16616 16617 16618 16619 16620 16621 16622 16623 16624 16625 16626 16627 16628 16629 16630 16631 16632 16633 16634 16635 16636 16637 16638 16639 16640 16641 16642 16643 16644 16645 16646 16647 16648 16649 16650 16651 16652 16653 16654 16655 16656 16657 16658 16659 16660 16661 16662 16663 16664 16665 16666 16667 16668 16669 16670 16671 16672 16673 16674 16675 16676 16677 16678 16679 16680 16681 16682 16683 16684 16685 16686 16687 16688 16689 16690 16691 16692 16693 16694 16695 16696 16697 16698 16699 16700 16701 16702 16703 16704 16705 16706 16707 16708 16709 16710 16711 16712 16713 16714 16715 16716 16717 16718 16719 16720 16721 16722 16723 16724 16725 16726 16727 16728 16729 16730 16731 16732 16733 16734 16735 16736 16737 16738 16739 16740 16741 16742 16743 16744 16745 16746 16747 16748 16749 16750 16751 16752 16753 16754 16755 16756 16757 16758 16759 16760 16761 16762 16763 16764 16765 16766 16767 16768 16769 16770 16771 16772 16773 16774 16775 16776 16777 16778 16779 16780 16781 16782 16783 16784 16785 16786 16787 16788 16789 16790 16791 16792 16793 16794 16795 16796 16797 16798 16799 16800 16801 16802 16803 16804 16805 16806 16807 16808 16809 16810 16811 16812 16813 16814 16815 16816 16817 16818 16819 16820 16821 16822 16823 16824 16825 16826 16827 16828 16829 16830 16831 16832 16833 16834 16835 16836 16837 16838 16839 16840 16841 16842 16843 16844 16845 16846 16847 16848 16849 16850 16851 16852 16853 16854 16855 16856 16857 16858 16859 16860 16861 16862 16863 16864 16865 16866 16867 16868 16869 16870 16871 16872 16873 16874 16875 16876 16877 16878 16879 16880 16881 16882 16883 16884 16885 16886 16887 16888 16889 16890 16891 16892 16893 16894 16895 16896 16897 16898 16899 16900 16901 16902 16903 16904 16905 16906 16907 16908 16909 16910 16911 16912 16913 16914 16915 16916 16917 16918 16919 16920 16921 16922 16923 16924 16925 16926 16927 16928 16929 16930 16931 16932 16933 16934 16935 16936 16937 16938 16939 16940 16941 16942 16943 16944 16945 16946 16947 16948 16949 16950 16951 16952 16953 16954 16955 16956 16957 16958 16959 16960 16961 16962 16963 16964 16965 16966 16967 16968 16969 16970 16971 16972 16973 16974 16975 16976 16977 16978 16979 16980 16981 16982 16983 16984 16985 16986 16987 16988 16989 16990 16991 16992 16993 16994 16995 16996 16997 16998 16999 17000 17001 17002 17003 17004 17005 17006 17007 17008 17009 17010 17011 17012 17013 17014 17015 17016 17017 17018 17019 17020 17021 17022 17023 17024 17025 17026 17027 17028 17029 17030 17031 17032 17033 17034 17035 17036 17037 17038 17039 17040 17041 17042 17043 17044 17045 17046 17047 17048 17049 17050 17051 17052 17053 17054 17055 17056 17057 17058 17059 17060 17061 17062 17063 17064 17065 17066 17067 17068 17069 17070 17071 17072 17073 17074 17075 17076 17077 17078 17079 17080 17081 17082 17083 17084 17085 17086 17087 17088 17089 17090 17091 17092 17093 17094 17095 17096 17097 17098 17099 17100 17101 17102 17103 17104 17105 17106 17107 17108 17109 17110 17111 17112 17113 17114 17115 17116 17117 17118 17119 17120 17121 17122 17123 17124 17125 17126 17127 17128 17129 17130 17131 17132 17133 17134 17135 17136 17137 17138 17139 17140 17141 17142 17143 17144 17145 17146 17147 17148 17149 17150 17151 17152 17153 17154 17155 17156 17157 17158 17159 17160 17161 17162 17163 17164 17165 17166 17167 17168 17169 17170 17171 17172 17173 17174 17175 17176 17177 17178 17179 17180 17181 17182 17183 17184 17185 17186 17187 17188 17189 17190 17191 17192 17193 17194 17195 17196 17197 17198 17199 17200 17201 17202 17203 17204 17205 17206 17207 17208 17209 17210 17211 17212 17213 17214 17215 17216 17217 17218 17219 17220 17221 17222 17223 17224 17225 17226 17227 17228 17229 17230 17231 17232 17233 17234 17235 17236 17237 17238 17239 17240 17241 17242 17243 17244 17245 17246 17247 17248 17249 17250 17251 17252 17253 17254 17255 17256 17257 17258 17259 17260 17261 17262 17263 17264 17265 17266 17267 17268 17269 17270 17271 17272 17273 17274 17275 17276 17277 17278 17279 17280 17281 17282 17283 17284 17285 17286 17287 17288 17289 17290 17291 17292 17293 17294 17295 17296 17297 17298 17299 17300 17301 17302 17303 17304 17305 17306 17307 17308 17309 17310 17311 17312 17313 17314 17315 17316 17317 17318 17319 17320 17321 17322 17323 17324 17325 17326 17327 17328 17329 17330 17331 17332 17333 17334 17335 17336 17337 17338 17339 17340 17341 17342 17343 17344 17345 17346 17347 17348 17349 17350 17351 17352 17353 17354 17355 17356 17357 17358 17359 17360 17361 17362 17363 17364 17365 17366 17367 17368 17369 17370 17371 17372 17373 17374 17375 17376 17377 17378 17379 17380 17381 17382 17383 17384 17385 17386 17387 17388 17389 17390 17391 17392 17393 17394 17395 17396 17397 17398 17399 17400 17401 17402 17403 17404 17405 17406 17407 17408 17409 17410 17411 17412 17413 17414 17415 17416 17417 17418 17419 17420 17421 17422 17423 17424 17425 17426 17427 17428 17429 17430 17431 17432 17433 17434 17435 17436 17437 17438 17439 17440 17441 17442 17443 17444 17445 17446 17447 17448 17449 17450 17451 17452 17453 17454 17455 17456 17457 17458 17459 17460 17461 17462 17463 17464 17465 17466 17467 17468 17469 17470 17471 17472 17473 17474 17475 17476 17477 17478 17479 17480 17481 17482 17483 17484 17485 17486 17487 17488 17489 17490 17491 17492 17493 17494 17495 17496 17497 17498 17499 17500 17501 17502 17503 17504 17505 17506 17507 17508 17509 17510 17511 17512 17513 17514 17515 17516 17517 17518 17519 17520 17521 17522 17523 17524 17525 17526 17527 17528 17529 17530 17531 17532 17533 17534 17535 17536 17537 17538 17539 17540 17541 17542 17543 17544 17545 17546 17547 17548 17549 17550 17551 17552 17553 17554 17555 17556 17557 17558 17559 17560 17561 17562 17563 17564 17565 17566 17567 17568 17569 17570 17571 17572 17573 17574 17575 17576 17577 17578 17579 17580 17581 17582 17583 17584 17585 17586 17587 17588 17589 17590 17591 17592 17593 17594 17595 17596 17597 17598 17599 17600 17601 17602 17603 17604 17605 17606 17607 17608 17609 17610 17611 17612 17613 17614 17615 17616 17617 17618 17619 17620 17621 17622 17623 17624 17625 17626 17627 17628 17629 17630 17631 17632 17633 17634 17635 17636 17637 17638 17639 17640 17641 17642 17643 17644 17645 17646 17647 17648 17649 17650 17651 17652 17653 17654 17655 17656 17657 17658 17659 17660 17661 17662 17663 17664 17665 17666 17667 17668 17669 17670 17671 17672 17673 17674 17675 17676 17677 17678 17679 17680 17681 17682 17683 17684 17685 17686 17687 17688 17689 17690 17691 17692 17693 17694 17695 17696 17697 17698 17699 17700 17701 17702 17703 17704 17705 17706 17707 17708 17709 17710 17711 17712 17713 17714 17715 17716 17717 17718 17719 17720 17721 17722 17723 17724 17725 17726 17727 17728 17729 17730 17731 17732 17733 17734 17735 17736 17737 17738 17739 17740 17741 17742 17743 17744 17745 17746 17747 17748 17749 17750 17751 17752 17753 17754 17755 17756 17757 17758 17759 17760 17761 17762 17763 17764 17765 17766 17767 17768 17769 17770 17771 17772 17773 17774 17775 17776 17777 17778 17779 17780 17781 17782 17783 17784 17785 17786 17787 17788 17789 17790 17791 17792 17793 17794 17795 17796 17797 17798 17799 17800 17801 17802 17803 17804 17805 17806 17807 17808 17809 17810 17811 17812 17813 17814 17815 17816 17817 17818 17819 17820 17821 17822 17823 17824 17825 17826 17827 17828 17829 17830 17831 17832 17833 17834 17835 17836 17837 17838 17839 17840 17841 17842 17843 17844 17845 17846 17847 17848 17849 17850 17851 17852 17853 17854 17855 17856 17857 17858 17859 17860 17861 17862 17863 17864 17865 17866 17867 17868 17869 17870 17871 17872 17873 17874 17875 17876 17877 17878 17879 17880 17881 17882 17883 17884 17885 17886 17887 17888 17889 17890 17891 17892 17893 17894 17895 17896 17897 17898 17899 17900 17901 17902 17903 17904 17905 17906 17907 17908 17909 17910 17911 17912 17913 17914 17915 17916 17917 17918 17919 17920 17921 17922 17923 17924 17925 17926 17927 17928 17929 17930 17931 17932 17933 17934 17935 17936 17937 17938 17939 17940 17941 17942 17943 17944 17945 17946 17947 17948 17949 17950 17951 17952 17953 17954 17955 17956 17957 17958 17959 17960 17961 17962 17963 17964 17965 17966 17967 17968 17969 17970 17971 17972 17973 17974 17975 17976 17977 17978 17979 17980 17981 17982 17983 17984 17985 17986 17987 17988 17989 17990 17991 17992 17993 17994 17995 17996 17997 17998 17999 18000 18001 18002 18003 18004 18005 18006 18007 18008 18009 18010 18011 18012 18013 18014 18015 18016 18017 18018 18019 18020 18021 18022 18023 18024 18025 18026 18027 18028 18029 18030 18031 18032 18033 18034 18035 18036 18037 18038 18039 18040 18041 18042 18043 18044 18045 18046 18047 18048 18049 18050 18051 18052 18053 18054 18055 18056 18057 18058 18059 18060 18061 18062 18063 18064 18065 18066 18067 18068 18069 18070 18071 18072 18073 18074 18075 18076 18077 18078 18079 18080 18081 18082 18083 18084 18085 18086 18087 18088 18089 18090 18091 18092 18093 18094 18095 18096 18097 18098 18099 18100 18101 18102 18103 18104 18105 18106 18107 18108 18109 18110 18111 18112 18113 18114 18115 18116 18117 18118 18119 18120 18121 18122 18123 18124 18125 18126 18127 18128 18129 18130 18131 18132 18133 18134 18135 18136 18137 18138 18139 18140 18141 18142 18143 18144 18145 18146 18147 18148 18149 18150 18151 18152 18153 18154 18155 18156 18157 18158 18159 18160 18161 18162 18163 18164 18165 18166 18167 18168 18169 18170 18171 18172 18173 18174 18175 18176 18177 18178 18179 18180 18181 18182 18183 18184 18185 18186 18187 18188 18189 18190 18191 18192 18193 18194 18195 18196 18197 18198 18199 18200 18201 18202 18203 18204 18205 18206 18207 18208 18209 18210 18211 18212 18213 18214 18215 18216 18217 18218 18219 18220 18221 18222 18223 18224 18225 18226 18227 18228 18229 18230 18231 18232 18233 18234 18235 18236 18237 18238 18239 18240 18241 18242 18243 18244 18245 18246 18247 18248 18249 18250 18251 18252 18253 18254 18255 18256 18257 18258 18259 18260 18261 18262 18263 18264 18265 18266 18267 18268 18269 18270 18271 18272 18273 18274 18275 18276 18277 18278 18279 18280 18281 18282 18283 18284 18285 18286 18287 18288 18289 18290 18291 18292 18293 18294 18295 18296 18297 18298 18299 18300 18301 18302 18303 18304 18305 18306 18307 18308 18309 18310 18311 18312 18313 18314 18315 18316 18317 18318 18319 18320 18321 18322 18323 18324 18325 18326 18327 18328 18329 18330 18331 18332 18333 18334 18335 18336 18337 18338 18339 18340 18341 18342 18343 18344 18345 18346 18347 18348 18349 18350 18351 18352 18353 18354 18355 18356 18357 18358 18359 18360 18361 18362 18363 18364 18365 18366 18367 18368 18369 18370 18371 18372 18373 18374 18375 18376 18377 18378 18379 18380 18381 18382 18383 18384 18385 18386 18387 18388 18389 18390 18391 18392 18393 18394 18395 18396 18397 18398 18399 18400 18401 18402 18403 18404 18405 18406 18407 18408 18409 18410 18411 18412 18413 18414 18415 18416 18417 18418 18419 18420 18421 18422 18423 18424 18425 18426 18427 18428 18429 18430 18431 18432 18433 18434 18435 18436 18437 18438 18439 18440 18441 18442 18443 18444 18445 18446 18447 18448 18449 18450 18451 18452 18453 18454 18455 18456 18457 18458 18459 18460 18461 18462 18463 18464 18465 18466 18467 18468 18469 18470 18471 18472 18473 18474 18475 18476 18477 18478 18479 18480 18481 18482 18483 18484 18485 18486 18487 18488 18489 18490 18491 18492 18493 18494 18495 18496 18497 18498 18499 18500 18501 18502 18503 18504 18505 18506 18507 18508 18509 18510 18511 18512 18513 18514 18515 18516 18517 18518 18519 18520 18521 18522 18523 18524 18525 18526 18527 18528 18529 18530 18531 18532 18533 18534 18535 18536 18537 18538 18539 18540 18541 18542 18543 18544 18545 18546 18547 18548 18549 18550 18551 18552 18553 18554 18555 18556 18557 18558 18559 18560 18561 18562 18563 18564 18565 18566 18567 18568 18569 18570 18571 18572 18573 18574 18575 18576 18577 18578 18579 18580 18581 18582 18583 18584 18585 18586 18587 18588 18589 18590 18591 18592 18593 18594 18595 18596 18597 18598 18599 18600 18601 18602 18603 18604 18605 18606 18607 18608 18609 18610 18611 18612 18613 18614 18615 18616 18617 18618 18619 18620 18621 18622 18623 18624 18625 18626 18627 18628 18629 18630 18631 18632 18633 18634 18635 18636 18637 18638 18639 18640 18641 18642 18643 18644 18645 18646 18647 18648 18649 18650 18651 18652 18653 18654 18655 18656 18657 18658 18659 18660 18661 18662 18663 18664 18665 18666 18667 18668 18669 18670 18671 18672 18673 18674 18675 18676 18677 18678 18679 18680 18681 18682 18683 18684 18685 18686 18687 18688 18689 18690 18691 18692 18693 18694 18695 18696 18697 18698 18699 18700 18701 18702 18703 18704 18705 18706 18707 18708 18709 18710 18711 18712 18713 18714 18715 18716 18717 18718 18719 18720 18721 18722 18723 18724 18725 18726 18727 18728 18729 18730 18731 18732 18733 18734 18735 18736 18737 18738 18739 18740 18741 18742 18743 18744 18745 18746 18747 18748 18749 18750 18751 18752 18753 18754 18755 18756 18757 18758 18759 18760 18761 18762 18763 18764 18765 18766 18767 18768 18769 18770 18771 18772 18773 18774 18775 18776 18777 18778 18779 18780 18781 18782 18783 18784 18785 18786 18787 18788 18789 18790 18791 18792 18793 18794 18795 18796 18797 18798 18799 18800 18801 18802 18803 18804 18805 18806 18807 18808 18809 18810 18811 18812 18813 18814 18815 18816 18817 18818 18819 18820 18821 18822 18823 18824 18825 18826 18827 18828 18829 18830 18831 18832 18833 18834 18835 18836 18837 18838 18839 18840 18841 18842 18843 18844 18845 18846 18847 18848 18849 18850 18851 18852 18853 18854 18855 18856 18857 18858 18859 18860 18861 18862 18863 18864 18865 18866 18867 18868 18869 18870 18871 18872 18873 18874 18875 18876 18877 18878 18879 18880 18881 18882 18883 18884 18885 18886 18887 18888 18889 18890 18891 18892 18893 18894 18895 18896 18897 18898 18899 18900 18901 18902 18903 18904 18905 18906 18907 18908 18909 18910 18911 18912 18913 18914 18915 18916 18917 18918 18919 18920 18921 18922 18923 18924 18925 18926 18927 18928 18929 18930 18931 18932 18933 18934 18935 18936 18937 18938 18939 18940 18941 18942 18943 18944 18945 18946 18947 18948 18949 18950 18951 18952 18953 18954 18955 18956 18957 18958 18959 18960 18961 18962 18963 18964 18965 18966 18967 18968 18969 18970 18971 18972 18973 18974 18975 18976 18977 18978 18979 18980 18981 18982 18983 18984 18985 18986 18987 18988 18989 18990 18991 18992 18993 18994 18995 18996 18997 18998 18999 19000 19001 19002 19003 19004 19005 19006 19007 19008 19009 19010 19011 19012 19013 19014 19015 19016 19017 19018 19019 19020 19021 19022 19023 19024 19025 19026 19027 19028 19029 19030 19031 19032 19033 19034 19035 19036 19037 19038 19039 19040 19041 19042 19043 19044 19045 19046 19047 19048 19049 19050 19051 19052 19053 19054 19055 19056 19057 19058 19059 19060 19061 19062 19063 19064 19065 19066 19067 19068 19069 19070 19071 19072 19073 19074 19075 19076 19077 19078 19079 19080 19081 19082 19083 19084 19085 19086 19087 19088 19089 19090 19091 19092 19093 19094 19095 19096 19097 19098 19099 19100 19101 19102 19103 19104 19105 19106 19107 19108 19109 19110 19111 19112 19113 19114 19115 19116 19117 19118 19119 19120 19121 19122 19123 19124 19125 19126 19127 19128 19129 19130 19131 19132 19133 19134 19135 19136 19137 19138 19139 19140 19141 19142 19143 19144 19145 19146 19147 19148 19149 19150 19151 19152 19153 19154 19155 19156 19157 19158 19159 19160 19161 19162 19163 19164 19165 19166 19167 19168 19169 19170 19171 19172 19173 19174 19175 19176 19177 19178 19179 19180 19181 19182 19183 19184 19185 19186 19187 19188 19189 19190 19191 19192 19193 19194 19195 19196 19197 19198 19199 19200 19201 19202 19203 19204 19205 19206 19207 19208 19209 19210 19211 19212 19213 19214 19215 19216 19217 19218 19219 19220 19221 19222 19223 19224 19225 19226 19227 19228 19229 19230 19231 19232 19233 19234 19235 19236 19237 19238 19239 19240 19241 19242 19243 19244 19245 19246 19247 19248 19249 19250 19251 19252 19253 19254 19255 19256 19257 19258 19259 19260 19261 19262 19263 19264 19265 19266 19267 19268 19269 19270 19271 19272 19273 19274 19275 19276 19277 19278 19279 19280 19281 19282 19283 19284 19285 19286 19287 19288 19289 19290 19291 19292 19293 19294 19295 19296 19297 19298 19299 19300 19301 19302 19303 19304 19305 19306 19307 19308 19309 19310 19311 19312 19313 19314 19315 19316 19317 19318 19319 19320 19321 19322 19323 19324 19325 19326 19327 19328 19329 19330 19331 19332 19333 19334 19335 19336 19337 19338 19339 19340 19341 19342 19343 19344 19345 19346 19347 19348 19349 19350 19351 19352 19353 19354 19355 19356 19357 19358 19359 19360 19361 19362 19363 19364 19365 19366 19367 19368 19369 19370 19371 19372 19373 19374 19375 19376 19377 19378 19379 19380 19381 19382 19383 19384 19385 19386 19387 19388 19389 19390 19391 19392 19393 19394 19395 19396 19397 19398 19399 19400 19401 19402 19403 19404 19405 19406 19407 19408 19409 19410 19411 19412 19413 19414 19415 19416 19417 19418 19419 19420 19421 19422 19423 19424 19425 19426 19427 19428 19429 19430 19431 19432 19433 19434 19435 19436 19437 19438 19439 19440 19441 19442 19443 19444 19445 19446 19447 19448 19449 19450 19451 19452 19453 19454 19455 19456 19457 19458 19459 19460 19461 19462 19463 19464 19465 19466 19467 19468 19469 19470 19471 19472 19473 19474 19475 19476 19477 19478 19479 19480 19481 19482 19483 19484 19485 19486 19487 19488 19489 19490 19491 19492 19493 19494 19495 19496 19497 19498 19499 19500 19501 19502 19503 19504 19505 19506 19507 19508 19509 19510 19511 19512 19513 19514 19515 19516 19517 19518 19519 19520 19521 19522 19523 19524 19525 19526 19527 19528 19529 19530 19531 19532 19533 19534 19535 19536 19537 19538 19539 19540 19541 19542 19543 19544 19545 19546 19547 19548 19549 19550 19551 19552 19553 19554 19555 19556 19557 19558 19559 19560 19561 19562 19563 19564 19565 19566 19567 19568 19569 19570 19571 19572 19573 19574 19575 19576 19577 19578 19579 19580 19581 19582 19583 19584 19585 19586 19587 19588 19589 19590 19591 19592 19593 19594 19595 19596 19597 19598 19599 19600 19601 19602 19603 19604 19605 19606 19607 19608 19609 19610 19611 19612 19613 19614 19615 19616 19617 19618 19619 19620 19621 19622 19623 19624 19625 19626 19627 19628 19629 19630 19631 19632 19633 19634 19635 19636 19637 19638 19639 19640 19641 19642 19643 19644 19645 19646 19647 19648 19649 19650 19651 19652 19653 19654 19655 19656 19657 19658 19659 19660 19661 19662 19663 19664 19665 19666 19667 19668 19669 19670 19671 19672 19673 19674 19675 19676 19677 19678 19679 19680 19681 19682 19683 19684 19685 19686 19687 19688 19689 19690 19691 19692 19693 19694 19695 19696 19697 19698 19699 19700 19701 19702 19703 19704 19705 19706 19707 19708 19709 19710 19711 19712 19713 19714 19715 19716 19717 19718 19719 19720 19721 19722 19723 19724 19725 19726 19727 19728 19729 19730 19731 19732 19733 19734 19735 19736 19737 19738 19739 19740 19741 19742 19743 19744 19745 19746 19747 19748 19749 19750 19751 19752 19753 19754 19755 19756 19757 19758 19759 19760 19761 19762 19763 19764 19765 19766 19767 19768 19769 19770 19771 19772 19773 19774 19775 19776 19777 19778 19779 19780 19781 19782 19783 19784 19785 19786 19787 19788 19789 19790 19791 19792 19793 19794 19795 19796 19797 19798 19799 19800 19801 19802 19803 19804 19805 19806 19807 19808 19809 19810 19811 19812 19813 19814 19815 19816 19817 19818 19819 19820 19821 19822 19823 19824 19825 19826 19827 19828 19829 19830 19831 19832 19833 19834 19835 19836 19837 19838 19839 19840 19841 19842 19843 19844 19845 19846 19847 19848 19849 19850 19851 19852 19853 19854 19855 19856 19857 19858 19859 19860 19861 19862 19863 19864 19865 19866 19867 19868 19869 19870 19871 19872 19873 19874 19875 19876 19877 19878 19879 19880 19881 19882 19883 19884 19885 19886 19887 19888 19889 19890 19891 19892 19893 19894 19895 19896 19897 19898 19899 19900 19901 19902 19903 19904 19905 19906 19907 19908 19909 19910 19911 19912 19913 19914 19915 19916 19917 19918 19919 19920 19921 19922 19923 19924 19925 19926 19927 19928 19929 19930 19931 19932 19933 19934 19935 19936 19937 19938 19939 19940 19941 19942 19943 19944 19945 19946 19947 19948 19949 19950 19951 19952 19953 19954 19955 19956 19957 19958 19959 19960 19961 19962 19963 19964 19965 19966 19967 19968 19969 19970 19971 19972 19973 19974 19975 19976 19977 19978 19979 19980 19981 19982 19983 19984 19985 19986 19987 19988 19989 19990 19991 19992 19993 19994 19995 19996 19997 19998 19999 20000 20001 20002 20003 20004 20005 20006 20007 20008 20009 20010 20011 20012 20013 20014 20015 20016 20017 20018 20019 20020 20021 20022 20023 20024 20025 20026 20027 20028 20029 20030 20031 20032 20033 20034 20035 20036 20037 20038 20039 20040 20041 20042 20043 20044 20045 20046 20047 20048 20049 20050 20051 20052 20053 20054 20055 20056 20057 20058 20059 20060 20061 20062 20063 20064 20065 20066 20067 20068 20069 20070 20071 20072 20073 20074 20075 20076 20077 20078 20079 20080 20081 20082 20083 20084 20085 20086 20087 20088 20089 20090 20091 20092 20093 20094 20095 20096 20097 20098 20099 20100 20101 20102 20103 20104 20105 20106 20107 20108 20109 20110 20111 20112 20113 20114 20115 20116 20117 20118 20119 20120 20121 20122 20123 20124 20125 20126 20127 20128 20129 20130 20131 20132 20133 20134 20135 20136 20137 20138 20139 20140 20141 20142 20143 20144 20145 20146 20147 20148 20149 20150 20151 20152 20153 20154 20155 20156 20157 20158 20159 20160 20161 20162 20163 20164 20165 20166 20167 20168 20169 20170 20171 20172 20173 20174 20175 20176 20177 20178 20179 20180 20181 20182 20183 20184 20185 20186 20187 20188 20189 20190 20191 20192 20193 20194 20195 20196 20197 20198 20199 20200 20201 20202 20203 20204 20205 20206 20207 20208 20209 20210 20211 20212 20213 20214 20215 20216 20217 20218 20219 20220 20221 20222 20223 20224 20225 20226 20227 20228 20229 20230 20231 20232 20233 20234 20235 20236 20237 20238 20239 20240 20241 20242 20243 20244 20245 20246 20247 20248 20249 20250 20251 20252 20253 20254 20255 20256 20257 20258 20259 20260 20261 20262 20263 20264 20265 20266 20267 20268 20269 20270 20271 20272 20273 20274 20275 20276 20277 20278 20279 20280 20281 20282 20283 20284 20285 20286 20287 20288 20289 20290 20291 20292 20293 20294 20295 20296 20297 20298 20299 20300 20301 20302 20303 20304 20305 20306 20307 20308 20309 20310 20311 20312 20313 20314 20315 20316 20317 20318 20319 20320 20321 20322 20323 20324 20325 20326 20327 20328 20329 20330 20331 20332 20333 20334 20335 20336 20337 20338 20339 20340 20341 20342 20343 20344 20345 20346 20347 20348 20349 20350 20351 20352 20353 20354 20355 20356 20357 20358 20359 20360 20361 20362 20363 20364 20365 20366 20367 20368 20369 20370 20371 20372 20373 20374 20375 20376 20377 20378 20379 20380 20381 20382 20383 20384 20385 20386 20387 20388 20389 20390 20391 20392 20393 20394 20395 20396 20397 20398 20399 20400 20401 20402 20403 20404 20405 20406 20407 20408 20409 20410 20411 20412 20413 20414 20415 20416 20417 20418 20419 20420 20421 20422 20423 20424 20425 20426 20427 20428 20429 20430 20431 20432 20433 20434 20435 20436 20437 20438 20439 20440 20441 20442 20443 20444 20445 20446 20447 20448 20449 20450 20451 20452 20453 20454 20455 20456 20457 20458 20459 20460 20461 20462 20463 20464 20465 20466 20467 20468 20469 20470 20471 20472 20473 20474 20475 20476 20477 20478 20479 20480 20481 20482 20483 20484 20485 20486 20487 20488 20489 20490 20491 20492 20493 20494 20495 20496 20497 20498 20499 20500 20501 20502 20503 20504 20505 20506 20507 20508 20509 20510 20511 20512 20513 20514 20515 20516 20517 20518 20519 20520 20521 20522 20523 20524 20525 20526 20527 20528 20529 20530 20531 20532 20533 20534 20535 20536 20537 20538 20539 20540 20541 20542 20543 20544 20545 20546 20547 20548 20549 20550 20551 20552 20553 20554 20555 20556 20557 20558 20559 20560 20561 20562 20563 20564 20565 20566 20567 20568 20569 20570 20571 20572 20573 20574 20575 20576 20577 20578 20579 20580 20581 20582 20583 20584 20585 20586 20587 20588 20589 20590 20591 20592 20593 20594 20595 20596 20597 20598 20599 20600 20601 20602 20603 20604 20605 20606 20607 20608 20609 20610 20611 20612 20613 20614 20615 20616 20617 20618 20619 20620 20621 20622 20623 20624 20625 20626 20627 20628 20629 20630 20631 20632 20633 20634 20635 20636 20637 20638 20639 20640 20641 20642 20643 20644 20645 20646 20647 20648 20649 20650 20651 20652 20653 20654 20655 20656 20657 20658 20659 20660 20661 20662 20663 20664 20665 20666 20667 20668 20669 20670 20671 20672 20673 20674 20675 20676 20677 20678 20679 20680 20681 20682 20683 20684 20685 20686 20687 20688 20689 20690 20691 20692 20693 20694 20695 20696 20697 20698 20699 20700 20701 20702 20703 20704 20705 20706 20707 20708 20709 20710 20711 20712 20713 20714 20715 20716 20717 20718 20719 20720 20721 20722 20723 20724 20725 20726 20727 20728 20729 20730 20731 20732 20733 20734 20735 20736 20737 20738 20739 20740 20741 20742 20743 20744 20745 20746 20747 20748 20749 20750 20751 20752 20753 20754 20755 20756 20757 20758 20759 20760 20761 20762 20763 20764 20765 20766 20767 20768 20769 20770 20771 20772 20773 20774 20775 20776 20777 20778 20779 20780 20781 20782 20783 20784 20785 20786 20787 20788 20789 20790 20791 20792 20793 20794 20795 20796 20797 20798 20799 20800 20801 20802 20803 20804 20805 20806 20807 20808 20809 20810 20811 20812 20813 20814 20815 20816 20817 20818 20819 20820 20821 20822 20823 20824 20825 20826 20827 20828 20829 20830 20831 20832 20833 20834 20835 20836 20837 20838 20839 20840 20841 20842 20843 20844 20845 20846 20847 20848 20849 20850 20851 20852 20853 20854 20855 20856 20857 20858 20859 20860 20861 20862 20863 20864 20865 20866 20867 20868 20869 20870 20871 20872 20873 20874 20875 20876 20877 20878 20879 20880 20881 20882 20883 20884 20885 20886 20887 20888 20889 20890 20891 20892 20893 20894 20895 20896 20897 20898 20899 20900 20901 20902 20903 20904 20905 20906 20907 20908 20909 20910 20911 20912 20913 20914 20915 20916 20917 20918 20919 20920 20921 20922 20923 20924 20925 20926 20927 20928 20929 20930 20931 20932 20933 20934 20935 20936 20937 20938 20939 20940 20941 20942 20943 20944 20945 20946 20947 20948 20949 20950 20951 20952 20953 20954 20955 20956 20957 20958 20959 20960 20961 20962 20963 20964 20965 20966 20967 20968 20969 20970 20971 20972 20973 20974 20975 20976 20977 20978 20979 20980 20981 20982 20983 20984 20985 20986 20987 20988 20989 20990 20991 20992 20993 20994 20995 20996 20997 20998 20999 21000 21001 21002 21003 21004 21005 21006 21007 21008 21009 21010 21011 21012 21013 21014 21015 21016 21017 21018 21019 21020 21021 21022 21023 21024 21025 21026 21027 21028 21029 21030 21031 21032 21033 21034 21035 21036 21037 21038 21039 21040 21041 21042 21043 21044 21045 21046 21047 21048 21049 21050 21051 21052 21053 21054 21055 21056 21057 21058 21059 21060 21061 21062 21063 21064 21065 21066 21067 21068 21069 21070 21071 21072 21073 21074 21075 21076 21077 21078 21079 21080 21081 21082 21083 21084 21085 21086 21087 21088 21089 21090 21091 21092 21093 21094 21095 21096 21097 21098 21099 21100 21101 21102 21103 21104 21105 21106 21107 21108 21109 21110 21111 21112 21113 21114 21115 21116 21117 21118 21119 21120 21121 21122 21123 21124 21125 21126 21127 21128 21129 21130 21131 21132 21133 21134 21135 21136 21137 21138 21139 21140 21141 21142 21143 21144 21145 21146 21147 21148 21149 21150 21151 21152 21153 21154 21155 21156 21157 21158 21159 21160 21161 21162 21163 21164 21165 21166 21167 21168 21169 21170 21171 21172 21173 21174 21175 21176 21177 21178 21179 21180 21181 21182 21183 21184 21185 21186 21187 21188 21189 21190 21191 21192 21193 21194 21195 21196 21197 21198 21199 21200 21201 21202 21203 21204 21205 21206 21207 21208 21209 21210 21211 21212 21213 21214 21215 21216 21217 21218 21219 21220 21221 21222 21223 21224 21225 21226 21227 21228 21229 21230 21231 21232 21233 21234 21235 21236 21237 21238 21239 21240 21241 21242 21243 21244 21245 21246 21247 21248 21249 21250 21251 21252 21253 21254 21255 21256 21257 21258 21259 21260 21261 21262 21263 21264 21265 21266 21267 21268 21269 21270 21271 21272 21273 21274 21275 21276 21277 21278 21279 21280 21281 21282 21283 21284 21285 21286 21287 21288 21289 21290 21291 21292 21293 21294 21295 21296 21297 21298 21299 21300 21301 21302 21303 21304 21305 21306 21307 21308 21309 21310 21311 21312 21313 21314 21315 21316 21317 21318 21319 21320 21321 21322 21323 21324 21325 21326 21327 21328 21329 21330 21331 21332 21333 21334 21335 21336 21337 21338 21339 21340 21341 21342 21343 21344 21345 21346 21347 21348 21349 21350 21351 21352 21353 21354 21355 21356 21357 21358 21359 21360 21361 21362 21363 21364 21365 21366 21367 21368 21369 21370 21371 21372 21373 21374 21375 21376 21377 21378 21379 21380 21381 21382 21383 21384 21385 21386 21387 21388 21389 21390 21391 21392 21393 21394 21395 21396 21397 21398 21399 21400 21401 21402 21403 21404 21405 21406 21407 21408 21409 21410 21411 21412 21413 21414 21415 21416 21417 21418 21419 21420 21421 21422 21423 21424 21425 21426 21427 21428 21429 21430 21431 21432 21433 21434 21435 21436 21437 21438 21439 21440 21441 21442 21443 21444 21445 21446 21447 21448 21449 21450 21451 21452 21453 21454 21455 21456 21457 21458 21459 21460 21461 21462 21463 21464 21465 21466 21467 21468 21469 21470 21471 21472 21473 21474 21475 21476 21477 21478 21479 21480 21481 21482 21483 21484 21485 21486 21487 21488 21489 21490 21491 21492 21493 21494 21495 21496 21497 21498 21499 21500 21501 21502 21503 21504 21505 21506 21507 21508 21509 21510 21511 21512 21513 21514 21515 21516 21517 21518 21519 21520 21521 21522 21523 21524 21525 21526 21527 21528 21529 21530 21531 21532 21533 21534 21535 21536 21537 21538 21539 21540 21541 21542 21543 21544 21545 21546 21547 21548 21549 21550 21551 21552 21553 21554 21555 21556 21557 21558 21559 21560 21561 21562 21563 21564 21565 21566 21567 21568 21569 21570 21571 21572 21573 21574 21575 21576 21577 21578 21579 21580 21581 21582 21583 21584 21585 21586 21587 21588 21589 21590 21591 21592 21593 21594 21595 21596 21597 21598 21599 21600 21601 21602 21603 21604 21605 21606 21607 21608 21609 21610 21611 21612 21613 21614 21615 21616 21617 21618 21619 21620 21621 21622 21623 21624 21625 21626 21627 21628 21629 21630 21631 21632 21633 21634 21635 21636 21637 21638 21639 21640 21641 21642 21643 21644 21645 21646 21647 21648 21649 21650 21651 21652 21653 21654 21655 21656 21657 21658 21659 21660 21661 21662 21663 21664 21665 21666 21667 21668 21669 21670 21671 21672 21673 21674 21675 21676 21677 21678 21679 21680 21681 21682 21683 21684 21685 21686 21687 21688 21689 21690 21691 21692 21693 21694 21695 21696 21697 21698 21699 21700 21701 21702 21703 21704 21705 21706 21707 21708 21709 21710 21711 21712 21713 21714 21715 21716 21717 21718 21719 21720 21721 21722 21723 21724 21725 21726 21727 21728 21729 21730 21731 21732 21733 21734 21735 21736 21737 21738 21739 21740 21741 21742 21743 21744 21745 21746 21747 21748 21749 21750 21751 21752 21753 21754 21755 21756 21757 21758 21759 21760 21761 21762 21763 21764 21765 21766 21767 21768 21769 21770 21771 21772 21773 21774 21775 21776 21777 21778 21779 21780 21781 21782 21783 21784 21785 21786 21787 21788 21789 21790 21791 21792 21793 21794 21795 21796 21797 21798 21799 21800 21801 21802 21803 21804 21805 21806 21807 21808 21809 21810 21811 21812 21813 21814 21815 21816 21817 21818 21819 21820 21821 21822 21823 21824 21825 21826 21827 21828 21829 21830 21831 21832 21833 21834 21835 21836 21837 21838 21839 21840 21841 21842 21843 21844 21845 21846 21847 21848 21849 21850 21851 21852 21853 21854 21855 21856 21857 21858 21859 21860 21861 21862 21863 21864 21865 21866 21867 21868 21869 21870 21871 21872 21873 21874 21875 21876 21877 21878 21879 21880 21881 21882 21883 21884 21885 21886 21887 21888 21889 21890 21891 21892 21893 21894 21895 21896 21897 21898 21899 21900 21901 21902 21903 21904 21905 21906 21907 21908 21909 21910 21911 21912 21913 21914 21915 21916 21917 21918 21919 21920 21921 21922 21923 21924 21925 21926 21927 21928 21929 21930 21931 21932 21933 21934 21935 21936 21937 21938 21939 21940 21941 21942 21943 21944 21945 21946 21947 21948 21949 21950 21951 21952 21953 21954 21955 21956 21957 21958 21959 21960 21961 21962 21963 21964 21965 21966 21967 21968 21969 21970 21971 21972 21973 21974 21975 21976 21977 21978 21979 21980 21981 21982 21983 21984 21985 21986 21987 21988 21989 21990 21991 21992 21993 21994 21995 21996 21997 21998 21999 22000 22001 22002 22003 22004 22005 22006 22007 22008 22009 22010 22011 22012 22013 22014 22015 22016 22017 22018 22019 22020 22021 22022 22023 22024 22025 22026 22027 22028 22029 22030 22031 22032 22033 22034 22035 22036 22037 22038 22039 22040 22041 22042 22043 22044 22045 22046 22047 22048 22049 22050 22051 22052 22053 22054 22055 22056 22057 22058 22059 22060 22061 22062 22063 22064 22065 22066 22067 22068 22069 22070 22071 22072 22073 22074 22075 22076 22077 22078 22079 22080 22081 22082 22083 22084 22085 22086 22087 22088 22089 22090 22091 22092 22093 22094 22095 22096 22097 22098 22099 22100 22101 22102 22103 22104 22105 22106 22107 22108 22109 22110 22111 22112 22113 22114 22115 22116 22117 22118 22119 22120 22121 22122 22123 22124 22125 22126 22127 22128 22129 22130 22131 22132 22133 22134 22135 22136 22137 22138 22139 22140 22141 22142 22143 22144 22145 22146 22147 22148 22149 22150 22151 22152 22153 22154 22155 22156 22157 22158 22159 22160 22161 22162 22163 22164 22165 22166 22167 22168 22169 22170 22171 22172 22173 22174 22175 22176 22177 22178 22179 22180 22181 22182 22183 22184 22185 22186 22187 22188 22189 22190 22191 22192 22193 22194 22195 22196 22197 22198 22199 22200 22201 22202 22203 22204 22205 22206 22207 22208 22209 22210 22211 22212 22213 22214 22215 22216 22217 22218 22219 22220 22221 22222 22223 22224 22225 22226 22227 22228 22229 22230 22231 22232 22233 22234 22235 22236 22237 22238 22239 22240 22241 22242 22243 22244 22245 22246 22247 22248 22249 22250 22251 22252 22253 22254 22255 22256 22257 22258 22259 22260 22261 22262 22263 22264 22265 22266 22267 22268 22269 22270 22271 22272 22273 22274 22275 22276 22277 22278 22279 22280 22281 22282 22283 22284 22285 22286 22287 22288 22289 22290 22291 22292 22293 22294 22295 22296 22297 22298 22299 22300 22301 22302 22303 22304 22305 22306 22307 22308 22309 22310 22311 22312 22313 22314 22315 22316 22317 22318 22319 22320 22321 22322 22323 22324 22325 22326 22327 22328 22329 22330 22331 22332 22333 22334 22335 22336 22337 22338 22339 22340 22341 22342 22343 22344 22345 22346 22347 22348 22349 22350 22351 22352 22353 22354 22355 22356 22357 22358 22359 22360 22361 22362 22363 22364 22365 22366 22367 22368 22369 22370 22371 22372 22373 22374 22375 22376 22377 22378 22379 22380 22381 22382 22383 22384 22385 22386 22387 22388 22389 22390 22391 22392 22393 22394 22395 22396 22397 22398 22399 22400 22401 22402 22403 22404 22405 22406 22407 22408 22409 22410 22411 22412 22413 22414 22415 22416 22417 22418 22419 22420 22421 22422 22423 22424 22425 22426 22427 22428 22429 22430 22431 22432 22433 22434 22435 22436 22437 22438 22439 22440 22441 22442 22443 22444 22445 22446 22447 22448 22449 22450 22451 22452 22453 22454 22455 22456 22457 22458 22459 22460 22461 22462 22463 22464 22465 22466 22467 22468 22469 22470 22471 22472 22473 22474 22475 22476 22477 22478 22479 22480 22481 22482 22483 22484 22485 22486 22487 22488 22489 22490 22491 22492 22493 22494 22495 22496 22497 22498 22499 22500 22501 22502 22503 22504 22505 22506 22507 22508 22509 22510 22511 22512 22513 22514 22515 22516 22517 22518 22519 22520 22521 22522 22523 22524 22525 22526 22527 22528 22529 22530 22531 22532 22533 22534 22535 22536 22537 22538 22539 22540 22541 22542 22543 22544 22545 22546 22547 22548 22549 22550 22551 22552 22553 22554 22555 22556 22557 22558 22559 22560 22561 22562 22563 22564 22565 22566 22567 22568 22569 22570 22571 22572 22573 22574 22575 22576 22577 22578 22579 22580 22581 22582 22583 22584 22585 22586 22587 22588 22589 22590 22591 22592 22593 22594 22595 22596 22597 22598 22599 22600 22601 22602 22603 22604 22605 22606 22607 22608 22609 22610 22611 22612 22613 22614 22615 22616 22617 22618 22619 22620 22621 22622 22623 22624 22625 22626 22627 22628 22629 22630 22631 22632 22633 22634 22635 22636 22637 22638 22639 22640 22641 22642 22643 22644 22645 22646 22647 22648 22649 22650 22651 22652 22653 22654 22655 22656 22657 22658 22659 22660 22661 22662 22663 22664 22665 22666 22667 22668 22669 22670 22671 22672 22673 22674 22675 22676 22677 22678 22679 22680 22681 22682 22683 22684 22685 22686 22687 22688 22689 22690 22691 22692 22693 22694 22695 22696 22697 22698 22699 22700 22701 22702 22703 22704 22705 22706 22707 22708 22709 22710 22711 22712 22713 22714 22715 22716 22717 22718 22719 22720 22721 22722 22723 22724 22725 22726 22727 22728 22729 22730 22731 22732 22733 22734 22735 22736 22737 22738 22739 22740 22741 22742 22743 22744 22745 22746 22747 22748 22749 22750 22751 22752 22753 22754 22755 22756 22757 22758 22759 22760 22761 22762 22763 22764 22765 22766 22767 22768 22769 22770 22771 22772 22773 22774 22775 22776 22777 22778 22779 22780 22781 22782 22783 22784 22785 22786 22787 22788 22789 22790 22791 22792 22793 22794 22795 22796 22797 22798 22799 22800 22801 22802 22803 22804 22805 22806 22807 22808 22809 22810 22811 22812 22813 22814 22815 22816 22817 22818 22819 22820 22821 22822 22823 22824 22825 22826 22827 22828 22829 22830 22831 22832 22833 22834 22835 22836 22837 22838 22839 22840 22841 22842 22843 22844 22845 22846 22847 22848 22849 22850 22851 22852 22853 22854 22855 22856 22857 22858 22859 22860 22861 22862 22863 22864 22865 22866 22867 22868 22869 22870 22871 22872 22873 22874 22875 22876 22877 22878 22879 22880 22881 22882 22883 22884 22885 22886 22887 22888 22889 22890 22891 22892 22893 22894 22895 22896 22897 22898 22899 22900 22901 22902 22903 22904 22905 22906 22907 22908 22909 22910 22911 22912 22913 22914 22915 22916 22917 22918 22919 22920 22921 22922 22923 22924 22925 22926 22927 22928 22929 22930 22931 22932 22933 22934 22935 22936 22937 22938 22939 22940 22941 22942 22943 22944 22945 22946 22947 22948 22949 22950 22951 22952 22953 22954 22955 22956 22957 22958 22959 22960 22961 22962 22963 22964 22965 22966 22967 22968 22969 22970 22971 22972 22973 22974 22975 22976 22977 22978 22979 22980 22981 22982 22983 22984 22985 22986 22987 22988 22989 22990 22991 22992 22993 22994 22995 22996 22997 22998 22999 23000 23001 23002 23003 23004 23005 23006 23007 23008 23009 23010 23011 23012 23013 23014 23015 23016 23017 23018 23019 23020 23021 23022 23023 23024 23025 23026 23027 23028 23029 23030 23031 23032 23033 23034 23035 23036 23037 23038 23039 23040 23041 23042 23043 23044 23045 23046 23047 23048 23049 23050 23051 23052 23053 23054 23055 23056 23057 23058 23059 23060 23061 23062 23063 23064 23065 23066 23067 23068 23069 23070 23071 23072 23073 23074 23075 23076 23077 23078 23079 23080 23081 23082 23083 23084 23085 23086 23087 23088 23089 23090 23091 23092 23093 23094 23095 23096 23097 23098 23099 23100 23101 23102 23103 23104 23105 23106 23107 23108 23109 23110 23111 23112 23113 23114 23115 23116 23117 23118 23119 23120 23121 23122 23123 23124 23125 23126 23127 23128 23129 23130 23131 23132 23133 23134 23135 23136 23137 23138 23139 23140 23141 23142 23143 23144 23145 23146 23147 23148 23149 23150 23151 23152 23153 23154 23155 23156 23157 23158 23159 23160 23161 23162 23163 23164 23165 23166 23167 23168 23169 23170 23171 23172 23173 23174 23175 23176 23177 23178 23179 23180 23181 23182 23183 23184 23185 23186 23187 23188 23189 23190 23191 23192 23193 23194 23195 23196 23197 23198 23199 23200 23201 23202 23203 23204 23205 23206 23207 23208 23209 23210 23211 23212 23213 23214 23215 23216 23217 23218 23219 23220 23221 23222 23223 23224 23225 23226 23227 23228 23229 23230 23231 23232 23233 23234 23235 23236 23237 23238 23239 23240 23241 23242 23243 23244 23245 23246 23247 23248 23249 23250 23251 23252 23253 23254 23255 23256 23257 23258 23259 23260 23261 23262 23263 23264 23265 23266 23267 23268 23269 23270 23271 23272 23273 23274 23275 23276 23277 23278 23279 23280 23281 23282 23283 23284 23285 23286 23287 23288 23289 23290 23291 23292 23293 23294 23295 23296 23297 23298 23299 23300 23301 23302 23303 23304 23305 23306 23307 23308 23309 23310 23311 23312 23313 23314 23315 23316 23317 23318 23319 23320 23321 23322 23323 23324 23325 23326 23327 23328 23329 23330 23331 23332 23333 23334 23335 23336 23337 23338 23339 23340 23341 23342 23343 23344 23345 23346 23347 23348 23349 23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360 23361 23362 23363 23364 23365 23366 23367 23368 23369 23370 23371 23372 23373 23374 23375 23376 23377 23378 23379 23380 23381 23382 23383 23384 23385 23386 23387 23388 23389 23390 23391 23392 23393 23394 23395 23396 23397 23398 23399 23400 23401 23402 23403 23404 23405 23406 23407 23408 23409 23410 23411 23412 23413 23414 23415 23416 23417 23418 23419 23420 23421 23422 23423 23424 23425 23426 23427 23428 23429 23430 23431 23432 23433 23434 23435 23436 23437 23438 23439 23440 23441 23442 23443 23444 23445 23446 23447 23448 23449 23450 23451 23452 23453 23454 23455 23456 23457 23458 23459 23460 23461 23462 23463 23464 23465 23466 23467 23468 23469 23470 23471 23472 23473 23474 23475 23476 23477 23478 23479 23480 23481 23482 23483 23484 23485 23486 23487 23488 23489 23490 23491 23492 23493 23494 23495 23496 23497 23498 23499 23500 23501 23502 23503 23504 23505 23506 23507 23508 23509 23510 23511 23512 23513 23514 23515 23516 23517 23518 23519 23520 23521 23522 23523 23524 23525 23526 23527 23528 23529 23530 23531 23532 23533 23534 23535 23536 23537 23538 23539 23540 23541 23542 23543 23544 23545 23546 23547 23548 23549 23550 23551 23552 23553 23554 23555 23556 23557 23558 23559 23560 23561 23562 23563 23564 23565 23566 23567 23568 23569 23570 23571 23572 23573 23574 23575 23576 23577 23578 23579 23580 23581 23582 23583 23584 23585 23586 23587 23588 23589 23590 23591 23592 23593 23594 23595 23596 23597 23598 23599 23600 23601 23602 23603 23604 23605 23606 23607 23608 23609 23610 23611 23612 23613 23614 23615 23616 23617 23618 23619 23620 23621 23622 23623 23624 23625 23626 23627 23628 23629 23630 23631 23632 23633 23634 23635 23636 23637 23638 23639 23640 23641 23642 23643 23644 23645 23646 23647 23648 23649 23650 23651 23652 23653 23654 23655 23656 23657 23658 23659 23660 23661 23662 23663 23664 23665 23666 23667 23668 23669 23670 23671 23672 23673 23674 23675 23676 23677 23678 23679 23680 23681 23682 23683 23684 23685 23686 23687 23688 23689 23690 23691 23692 23693 23694 23695 23696 23697 23698 23699 23700 23701 23702 23703 23704 23705 23706 23707 23708 23709 23710 23711 23712 23713 23714 23715 23716 23717 23718 23719 23720 23721 23722 23723 23724 23725 23726 23727 23728 23729 23730 23731 23732 23733 23734 23735 23736 23737 23738 23739 23740 23741 23742 23743 23744 23745 23746 23747 23748 23749 23750 23751 23752 23753 23754 23755 23756 23757 23758 23759 23760 23761 23762 23763 23764 23765 23766 23767 23768 23769 23770 23771 23772 23773 23774 23775 23776 23777 23778 23779 23780 23781 23782 23783 23784 23785 23786 23787 23788 23789 23790 23791 23792 23793 23794 23795 23796 23797 23798 23799 23800 23801 23802 23803 23804 23805 23806 23807 23808 23809 23810 23811 23812 23813 23814 23815 23816 23817 23818 23819 23820 23821 23822 23823 23824 23825 23826 23827 23828 23829 23830 23831 23832 23833 23834 23835 23836 23837 23838 23839 23840 23841 23842 23843 23844 23845 23846 23847 23848 23849 23850 23851 23852 23853 23854 23855 23856 23857 23858 23859 23860 23861 23862 23863 23864 23865 23866 23867 23868 23869 23870 23871 23872 23873 23874 23875 23876 23877 23878 23879 23880 23881 23882 23883 23884 23885 23886 23887 23888 23889 23890 23891 23892 23893 23894 23895 23896 23897 23898 23899 23900 23901 23902 23903 23904 23905 23906 23907 23908 23909 23910 23911 23912 23913 23914 23915 23916 23917 23918 23919 23920 23921 23922 23923 23924 23925 23926 23927 23928 23929 23930 23931 23932 23933 23934 23935 23936 23937 23938 23939 23940 23941 23942 23943 23944 23945 23946 23947 23948 23949 23950 23951 23952 23953 23954 23955 23956 23957 23958 23959 23960 23961 23962 23963 23964 23965 23966 23967 23968 23969 23970 23971 23972 23973 23974 23975 23976 23977 23978 23979 23980 23981 23982 23983 23984 23985 23986 23987 23988 23989 23990 23991 23992 23993 23994 23995 23996 23997 23998 23999 24000 24001 24002 24003 24004 24005 24006 24007 24008 24009 24010 24011 24012 24013 24014 24015 24016 24017 24018 24019 24020 24021 24022 24023 24024 24025 24026 24027 24028 24029 24030 24031 24032 24033 24034 24035 24036 24037 24038 24039 24040 24041 24042 24043 24044 24045 24046 24047 24048 24049 24050 24051 24052 24053 24054 24055 24056 24057 24058 24059 24060 24061 24062 24063 24064 24065 24066 24067 24068 24069 24070 24071 24072 24073 24074 24075 24076 24077 24078 24079 24080 24081 24082 24083 24084 24085 24086 24087 24088 24089 24090 24091 24092 24093 24094 24095 24096 24097 24098 24099 24100 24101 24102 24103 24104 24105 24106 24107 24108 24109 24110 24111 24112 24113 24114 24115 24116 24117 24118 24119 24120 24121 24122 24123 24124 24125 24126 24127 24128 24129 24130 24131 24132 24133 24134 24135 24136 24137 24138 24139 24140 24141 24142 24143 24144 24145 24146 24147 24148 24149 24150 24151 24152 24153 24154 24155 24156 24157 24158 24159 24160 24161 24162 24163 24164 24165 24166 24167 24168 24169 24170 24171 24172 24173 24174 24175 24176 24177 24178 24179 24180 24181 24182 24183 24184 24185 24186 24187 24188 24189 24190 24191 24192 24193 24194 24195 24196 24197 24198 24199 24200 24201 24202 24203 24204 24205 24206 24207 24208 24209 24210 24211 24212 24213 24214 24215 24216 24217 24218 24219 24220 24221 24222 24223 24224 24225 24226 24227 24228 24229 24230 24231 24232 24233 24234 24235 24236 24237 24238 24239 24240 24241 24242 24243 24244 24245 24246 24247 24248 24249 24250 24251 24252 24253 24254 24255 24256 24257 24258 24259 24260 24261 24262 24263 24264 24265 24266 24267 24268 24269 24270 24271 24272 24273 24274 24275 24276 24277 24278 24279 24280 24281 24282 24283 24284 24285 24286 24287 24288 24289 24290 24291 24292 24293 24294 24295 24296 24297 24298 24299 24300 24301 24302 24303 24304 24305 24306 24307 24308 24309 24310 24311 24312 24313 24314 24315 24316 24317 24318 24319 24320 24321 24322 24323 24324 24325 24326 24327 24328 24329 24330 24331 24332 24333 24334 24335 24336 24337 24338 24339 24340 24341 24342 24343 24344 24345 24346 24347 24348 24349 24350 24351 24352 24353 24354 24355 24356 24357 24358 24359 24360 24361 24362 24363 24364 24365 24366 24367 24368 24369 24370 24371 24372 24373 24374 24375 24376 24377 24378 24379 24380 24381 24382 24383 24384 24385 24386 24387 24388 24389 24390 24391 24392 24393 24394 24395 24396 24397 24398 24399 24400 24401 24402 24403 24404 24405 24406 24407 24408 24409 24410 24411 24412 24413 24414 24415 24416 24417 24418 24419 24420 24421 24422 24423 24424 24425 24426 24427 24428 24429 24430 24431 24432 24433 24434 24435 24436 24437 24438 24439 24440 24441 24442 24443 24444 24445 24446 24447 24448 24449 24450 24451 24452 24453 24454 24455 24456 24457 24458 24459 24460 24461 24462 24463 24464 24465 24466 24467 24468 24469 24470 24471 24472 24473 24474 24475 24476 24477 24478 24479 24480 24481 24482 24483 24484 24485 24486 24487 24488 24489 24490 24491 24492 24493 24494 24495 24496 24497 24498 24499 24500 24501 24502 24503 24504 24505 24506 24507 24508 24509 24510 24511 24512 24513 24514 24515 24516 24517 24518 24519 24520 24521 24522 24523 24524 24525 24526 24527 24528 24529 24530 24531 24532 24533 24534 24535 24536 24537 24538 24539 24540 24541 24542 24543 24544 24545 24546 24547 24548 24549 24550 24551 24552 24553 24554 24555 24556 24557 24558 24559 24560 24561 24562 24563 24564 24565 24566 24567 24568 24569 24570 24571 24572 24573 24574 24575 24576 24577 24578 24579 24580 24581 24582 24583 24584 24585 24586 24587 24588 24589 24590 24591 24592 24593 24594 24595 24596 24597 24598 24599 24600 24601 24602 24603 24604 24605 24606 24607 24608 24609 24610 24611 24612 24613 24614 24615 24616 24617 24618 24619 24620 24621 24622 24623 24624 24625 24626 24627 24628 24629 24630 24631 24632 24633 24634 24635 24636 24637 24638 24639 24640 24641 24642 24643 24644 24645 24646 24647 24648 24649 24650 24651 24652 24653 24654 24655 24656 24657 24658 24659 24660 24661 24662 24663 24664 24665 24666 24667 24668 24669 24670 24671 24672 24673 24674 24675 24676 24677 24678 24679 24680 24681 24682 24683 24684 24685 24686 24687 24688 24689 24690 24691 24692 24693 24694 24695 24696 24697 24698 24699 24700 24701 24702 24703 24704 24705 24706 24707 24708 24709 24710 24711 24712 24713 24714 24715 24716 24717 24718 24719 24720 24721 24722 24723 24724 24725 24726 24727 24728 24729 24730 24731 24732 24733 24734 24735 24736 24737 24738 24739 24740 24741 24742 24743 24744 24745 24746 24747 24748 24749 24750 24751 24752 24753 24754 24755 24756 24757 24758 24759 24760 24761 24762 24763 24764 24765 24766 24767 24768 24769 24770 24771 24772 24773 24774 24775 24776 24777 24778 24779 24780 24781 24782 24783 24784 24785 24786 24787 24788 24789 24790 24791 24792 24793 24794 24795 24796 24797 24798 24799 24800 24801 24802 24803 24804 24805 24806 24807 24808 24809 24810 24811 24812 24813 24814 24815 24816 24817 24818 24819 24820 24821 24822 24823 24824 24825 24826 24827 24828 24829 24830 24831 24832 24833 24834 24835 24836 24837 24838 24839 24840 24841 24842 24843 24844 24845 24846 24847 24848 24849 24850 24851 24852 24853 24854 24855 24856 24857 24858 24859 24860 24861 24862 24863 24864 24865 24866 24867 24868 24869 24870 24871 24872 24873 24874 24875 24876 24877 24878 24879 24880 24881 24882 24883 24884 24885 24886 24887 24888 24889 24890 24891 24892 24893 24894 24895 24896 24897 24898 24899 24900 24901 24902 24903 24904 24905 24906 24907 24908 24909 24910 24911 24912 24913 24914 24915 24916 24917 24918 24919 24920 24921 24922 24923 24924 24925 24926 24927 24928 24929 24930 24931 24932 24933 24934 24935 24936 24937 24938 24939 24940 24941 24942 24943 24944 24945 24946 24947 24948 24949 24950 24951 24952 24953 24954 24955 24956 24957 24958 24959 24960 24961 24962 24963 24964 24965 24966 24967 24968 24969 24970 24971 24972 24973 24974 24975 24976 24977 24978 24979 24980 24981 24982 24983 24984 24985 24986 24987 24988 24989 24990 24991 24992 24993 24994 24995 24996 24997 24998 24999 25000 25001 25002 25003 25004 25005 25006 25007 25008 25009 25010 25011 25012 25013 25014 25015 25016 25017 25018 25019 25020 25021 25022 25023 25024 25025 25026 25027 25028 25029 25030 25031 25032 25033 25034 25035 25036 25037 25038 25039 25040 25041 25042 25043 25044 25045 25046 25047 25048 25049 25050 25051 25052 25053 25054 25055 25056 25057 25058 25059 25060 25061 25062 25063 25064 25065 25066 25067 25068 25069 25070 25071 25072 25073 25074 25075 25076 25077 25078 25079 25080 25081 25082 25083 25084 25085 25086 25087 25088 25089 25090 25091 25092 25093 25094 25095 25096 25097 25098 25099 25100 25101 25102 25103 25104 25105 25106 25107 25108 25109 25110 25111 25112 25113 25114 25115 25116 25117 25118 25119 25120 25121 25122 25123 25124 25125 25126 25127 25128 25129 25130 25131 25132 25133 25134 25135 25136 25137 25138 25139 25140 25141 25142 25143 25144 25145 25146 25147 25148 25149 25150 25151 25152 25153 25154 25155 25156 25157 25158 25159 25160 25161 25162 25163 25164 25165 25166 25167 25168 25169 25170 25171 25172 25173 25174 25175 25176 25177 25178 25179 25180 25181 25182 25183 25184 25185 25186 25187 25188 25189 25190 25191 25192 25193 25194 25195 25196 25197 25198 25199 25200 25201 25202 25203 25204 25205 25206 25207 25208 25209 25210 25211 25212 25213 25214 25215 25216 25217 25218 25219 25220 25221 25222 25223 25224 25225 25226 25227 25228 25229 25230 25231 25232 25233 25234 25235 25236 25237 25238 25239 25240 25241 25242 25243 25244 25245 25246 25247 25248 25249 25250 25251 25252 25253 25254 25255 25256 25257 25258 25259 25260 25261 25262 25263 25264 25265 25266 25267 25268 25269 25270 25271 25272 25273 25274 25275 25276 25277 25278 25279 25280 25281 25282 25283 25284 25285 25286 25287 25288 25289 25290 25291 25292 25293 25294 25295 25296 25297 25298 25299 25300 25301 25302 25303 25304 25305 25306 25307 25308 25309 25310 25311 25312 25313 25314 25315 25316 25317 25318 25319 25320 25321 25322 25323 25324 25325 25326 25327 25328 25329 25330 25331 25332 25333 25334 25335 25336 25337 25338 25339 25340 25341 25342 25343 25344 25345 25346 25347 25348 25349 25350 25351 25352 25353 25354 25355 25356 25357 25358 25359 25360 25361 25362 25363 25364 25365 25366 25367 25368 25369 25370 25371 25372 25373 25374 25375 25376 25377 25378 25379 25380 25381 25382 25383 25384 25385 25386 25387 25388 25389 25390 25391 25392 25393 25394 25395 25396 25397 25398 25399 25400 25401 25402 25403 25404 25405 25406 25407 25408 25409 25410 25411 25412 25413 25414 25415 25416 25417 25418 25419 25420 25421 25422 25423 25424 25425 25426 25427 25428 25429 25430 25431 25432 25433 25434 25435 25436 25437 25438 25439 25440 25441 25442 25443 25444 25445 25446 25447 25448 25449 25450 25451 25452 25453 25454 25455 25456 25457 25458 25459 25460 25461 25462 25463 25464 25465 25466 25467 25468 25469 25470 25471 25472 25473 25474 25475 25476 25477 25478 25479 25480 25481 25482 25483 25484 25485 25486 25487 25488 25489 25490 25491 25492 25493 25494 25495 25496 25497 25498 25499 25500 25501 25502 25503 25504 25505 25506 25507 25508 25509 25510 25511 25512 25513 25514 25515 25516 25517 25518 25519 25520 25521 25522 25523 25524 25525 25526 25527 25528 25529 25530 25531 25532 25533 25534 25535 25536 25537 25538 25539 25540 25541 25542 25543 25544 25545 25546 25547 25548 25549 25550 25551 25552 25553 25554 25555 25556 25557 25558 25559 25560 25561 25562 25563 25564 25565 25566 25567 25568 25569 25570 25571 25572 25573 25574 25575 25576 25577 25578 25579 25580 25581 25582 25583 25584 25585 25586 25587 25588 25589 25590 25591 25592 25593 25594 25595 25596 25597 25598 25599 25600 25601 25602 25603 25604 25605 25606 25607 25608 25609 25610 25611 25612 25613 25614 25615 25616 25617 25618 25619 25620 25621 25622 25623 25624 25625 25626 25627 25628 25629 25630 25631 25632 25633 25634 25635 25636 25637 25638 25639 25640 25641 25642 25643 25644 25645 25646 25647 25648 25649 25650 25651 25652 25653 25654 25655 25656 25657 25658 25659 25660 25661 25662 25663 25664 25665 25666 25667 25668 25669 25670 25671 25672 25673 25674 25675 25676 25677 25678 25679 25680 25681 25682 25683 25684 25685 25686 25687 25688 25689 25690 25691 25692 25693 25694 25695 25696 25697 25698 25699 25700 25701 25702 25703 25704 25705 25706 25707 25708 25709 25710 25711 25712 25713 25714 25715 25716 25717 25718 25719 25720 25721 25722 25723 25724 25725 25726 25727 25728 25729 25730 25731 25732 25733 25734 25735 25736 25737 25738 25739 25740 25741 25742 25743 25744 25745 25746 25747 25748 25749 25750 25751 25752 25753 25754 25755 25756 25757 25758 25759 25760 25761 25762 25763 25764 25765 25766 25767 25768 25769 25770 25771 25772 25773 25774 25775 25776 25777 25778 25779 25780 25781 25782 25783 25784 25785 25786 25787 25788 25789 25790 25791 25792 25793 25794 25795 25796 25797 25798 25799 25800 25801 25802 25803 25804 25805 25806 25807 25808 25809 25810 25811 25812 25813 25814 25815 25816 25817 25818 25819 25820 25821 25822 25823 25824 25825 25826 25827 25828 25829 25830 25831 25832 25833 25834 25835 25836 25837 25838 25839 25840 25841 25842 25843 25844 25845 25846 25847 25848 25849 25850 25851 25852 25853 25854 25855 25856 25857 25858 25859 25860 25861 25862 25863 25864 25865 25866 25867 25868 25869 25870 25871 25872 25873 25874 25875 25876 25877 25878 25879 25880 25881 25882 25883 25884 25885 25886 25887 25888 25889 25890 25891 25892 25893 25894 25895 25896 25897 25898 25899 25900 25901 25902 25903 25904 25905 25906 25907 25908 25909 25910 25911 25912 25913 25914 25915 25916 25917 25918 25919 25920 25921 25922 25923 25924 25925 25926 25927 25928 25929 25930 25931 25932 25933 25934 25935 25936 25937 25938 25939 25940 25941 25942 25943 25944 25945 25946 25947 25948 25949 25950 25951 25952 25953 25954 25955 25956 25957 25958 25959 25960 25961 25962 25963 25964 25965 25966 25967 25968 25969 25970 25971 25972 25973 25974 25975 25976 25977 25978 25979 25980 25981 25982 25983 25984 25985 25986 25987 25988 25989 25990 25991 25992 25993 25994 25995 25996 25997 25998 25999 26000 26001 26002 26003 26004 26005 26006 26007 26008 26009 26010 26011 26012 26013 26014 26015 26016 26017 26018 26019 26020 26021 26022 26023 26024 26025 26026 26027 26028 26029 26030 26031 26032 26033 26034 26035 26036 26037 26038 26039 26040 26041 26042 26043 26044 26045 26046 26047 26048 26049 26050 26051 26052 26053 26054 26055 26056 26057 26058 26059 26060 26061 26062 26063 26064 26065 26066 26067 26068 26069 26070 26071 26072 26073 26074 26075 26076 26077 26078 26079 26080 26081 26082 26083 26084 26085 26086 26087 26088 26089 26090 26091 26092 26093 26094 26095 26096 26097 26098 26099 26100 26101 26102 26103 26104 26105 26106 26107 26108 26109 26110 26111 26112 26113 26114 26115 26116 26117 26118 26119 26120 26121 26122 26123 26124 26125 26126 26127 26128 26129 26130 26131 26132 26133 26134 26135 26136 26137 26138 26139 26140 26141 26142 26143 26144 26145 26146 26147 26148 26149 26150 26151 26152 26153 26154 26155 26156 26157 26158 26159 26160 26161 26162 26163 26164 26165 26166 26167 26168 26169 26170 26171 26172 26173 26174 26175 26176 26177 26178 26179 26180 26181 26182 26183 26184 26185 26186 26187 26188 26189 26190 26191 26192 26193 26194 26195 26196 26197 26198 26199 26200 26201 26202 26203 26204 26205 26206 26207 26208 26209 26210 26211 26212 26213 26214 26215 26216 26217 26218 26219 26220 26221 26222 26223 26224 26225 26226 26227 26228 26229 26230 26231 26232 26233 26234 26235 26236 26237 26238 26239 26240 26241 26242 26243 26244 26245 26246 26247 26248 26249 26250 26251 26252 26253 26254 26255 26256 26257 26258 26259 26260 26261 26262 26263 26264 26265 26266 26267 26268 26269 26270 26271 26272 26273 26274 26275 26276 26277 26278 26279 26280 26281 26282 26283 26284 26285 26286 26287 26288 26289 26290 26291 26292 26293 26294 26295 26296 26297 26298 26299 26300 26301 26302 26303 26304 26305 26306 26307 26308 26309 26310 26311 26312 26313 26314 26315 26316 26317 26318 26319 26320 26321 26322 26323 26324 26325 26326 26327 26328 26329 26330 26331 26332 26333 26334 26335 26336 26337 26338 26339 26340 26341 26342 26343 26344 26345 26346 26347 26348 26349 26350 26351 26352 26353 26354 26355 26356 26357 26358 26359 26360 26361 26362 26363 26364 26365 26366 26367 26368 26369 26370 26371 26372 26373 26374 26375 26376 26377 26378 26379 26380 26381 26382 26383 26384 26385 26386 26387 26388 26389 26390 26391 26392 26393 26394 26395 26396 26397 26398 26399 26400 26401 26402 26403 26404 26405 26406 26407 26408 26409 26410 26411 26412 26413 26414 26415 26416 26417 26418 26419 26420 26421 26422 26423 26424 26425 26426 26427 26428 26429 26430 26431 26432 26433 26434 26435 26436 26437 26438 26439 26440 26441 26442 26443 26444 26445 26446 26447 26448 26449 26450 26451 26452 26453 26454 26455 26456 26457 26458 26459 26460 26461 26462 26463 26464 26465 26466 26467 26468 26469 26470 26471 26472 26473 26474 26475 26476 26477 26478 26479 26480 26481 26482 26483 26484 26485 26486 26487 26488 26489 26490 26491 26492 26493 26494 26495 26496 26497 26498 26499 26500 26501 26502 26503 26504 26505 26506 26507 26508 26509 26510 26511 26512 26513 26514 26515 26516 26517 26518 26519 26520 26521 26522 26523 26524 26525 26526 26527 26528 26529 26530 26531 26532 26533 26534 26535 26536 26537 26538 26539 26540 26541 26542 26543 26544 26545 26546 26547 26548 26549 26550 26551 26552 26553 26554 26555 26556 26557 26558 26559 26560 26561 26562 26563 26564 26565 26566 26567 26568 26569 26570 26571 26572 26573 26574 26575 26576 26577 26578 26579 26580 26581 26582 26583 26584 26585 26586 26587 26588 26589 26590 26591 26592 26593 26594 26595 26596 26597 26598 26599 26600 26601 26602 26603 26604 26605 26606 26607 26608 26609 26610 26611 26612 26613 26614 26615 26616 26617 26618 26619 26620 26621 26622 26623 26624 26625 26626 26627 26628 26629 26630 26631 26632 26633 26634 26635 26636 26637 26638 26639 26640 26641 26642 26643 26644 26645 26646 26647 26648 26649 26650 26651 26652 26653 26654 26655 26656 26657 26658 26659 26660 26661 26662 26663 26664 26665 26666 26667 26668 26669 26670 26671 26672 26673 26674 26675 26676 26677 26678 26679 26680 26681 26682 26683 26684 26685 26686 26687 26688 26689 26690 26691 26692 26693 26694 26695 26696 26697 26698 26699 26700 26701 26702 26703 26704 26705 26706 26707 26708 26709 26710 26711 26712 26713 26714 26715 26716 26717 26718 26719 26720 26721 26722 26723 26724 26725 26726 26727 26728 26729 26730 26731 26732 26733 26734 26735 26736 26737 26738 26739 26740 26741 26742 26743 26744 26745 26746 26747 26748 26749 26750 26751 26752 26753 26754 26755 26756 26757 26758 26759 26760 26761 26762 26763 26764 26765 26766 26767 26768 26769 26770 26771 26772 26773 26774 26775 26776 26777 26778 26779 26780 26781 26782 26783 26784 26785 26786 26787 26788 26789 26790 26791 26792 26793 26794 26795 26796 26797 26798 26799 26800 26801 26802 26803 26804 26805 26806 26807 26808 26809 26810 26811 26812 26813 26814 26815 26816 26817 26818 26819 26820 26821 26822 26823 26824 26825 26826 26827 26828 26829 26830 26831 26832 26833 26834 26835 26836 26837 26838 26839 26840 26841 26842 26843 26844 26845 26846 26847 26848 26849 26850 26851 26852 26853 26854 26855 26856 26857 26858 26859 26860 26861 26862 26863 26864 26865 26866 26867 26868 26869 26870 26871 26872 26873 26874 26875 26876 26877 26878 26879 26880 26881 26882 26883 26884 26885 26886 26887 26888 26889 26890 26891 26892 26893 26894 26895 26896 26897 26898 26899 26900 26901 26902 26903 26904 26905 26906 26907 26908 26909 26910 26911 26912 26913 26914 26915 26916 26917 26918 26919 26920 26921 26922 26923 26924 26925 26926 26927 26928 26929 26930 26931 26932 26933 26934 26935 26936 26937 26938 26939 26940 26941 26942 26943 26944 26945 26946 26947 26948 26949 26950 26951 26952 26953 26954 26955 26956 26957 26958 26959 26960 26961 26962 26963 26964 26965 26966 26967 26968 26969 26970 26971 26972 26973 26974 26975 26976 26977 26978 26979 26980 26981 26982 26983 26984 26985 26986 26987 26988 26989 26990 26991 26992 26993 26994 26995 26996 26997 26998 26999 27000 27001 27002 27003 27004 27005 27006 27007 27008 27009 27010 27011 27012 27013 27014 27015 27016 27017 27018 27019 27020 27021 27022 27023 27024 27025 27026 27027 27028 27029 27030 27031 27032 27033 27034 27035 27036 27037 27038 27039 27040 27041 27042 27043 27044 27045 27046 27047 27048 27049 27050 27051 27052 27053 27054 27055 27056 27057 27058 27059 27060 27061 27062 27063 27064 27065 27066 27067 27068 27069 27070 27071 27072 27073 27074 27075 27076 27077 27078 27079 27080 27081 27082 27083 27084 27085 27086 27087 27088 27089 27090 27091 27092 27093 27094 27095 27096 27097 27098 27099 27100 27101 27102 27103 27104 27105 27106 27107 27108 27109 27110 27111 27112 27113 27114 27115 27116 27117 27118 27119 27120 27121 27122 27123 27124 27125 27126 27127 27128 27129 27130 27131 27132 27133 27134 27135 27136 27137 27138 27139 27140 27141 27142 27143 27144 27145 27146 27147 27148 27149 27150 27151 27152 27153 27154 27155 27156 27157 27158 27159 27160 27161 27162 27163 27164 27165 27166 27167 27168 27169 27170 27171 27172 27173 27174 27175 27176 27177 27178 27179 27180 27181 27182 27183 27184 27185 27186 27187 27188 27189 27190 27191 27192 27193 27194 27195 27196 27197 27198 27199 27200 27201 27202 27203 27204 27205 27206 27207 27208 27209 27210 27211 27212 27213 27214 27215 27216 27217 27218 27219 27220 27221 27222 27223 27224 27225 27226 27227 27228 27229 27230 27231 27232 27233 27234 27235 27236 27237 27238 27239 27240 27241 27242 27243 27244 27245 27246 27247 27248 27249 27250 27251 27252 27253 27254 27255 27256 27257 27258 27259 27260 27261 27262 27263 27264 27265 27266 27267 27268 27269 27270 27271 27272 27273 27274 27275 27276 27277 27278 27279 27280 27281 27282 27283 27284 27285 27286 27287 27288 27289 27290 27291 27292 27293 27294 27295 27296 27297 27298 27299 27300 27301 27302 27303 27304 27305 27306 27307 27308 27309 27310 27311 27312 27313 27314 27315 27316 27317 27318 27319 27320 27321 27322 27323 27324 27325 27326 27327 27328 27329 27330 27331 27332 27333 27334 27335 27336 27337 27338 27339 27340 27341 27342 27343 27344 27345 27346 27347 27348 27349 27350 27351 27352 27353 27354 27355 27356 27357 27358 27359 27360 27361 27362 27363 27364 27365 27366 27367 27368 27369 27370 27371 27372 27373 27374 27375 27376 27377 27378 27379 27380 27381 27382 27383 27384 27385 27386 27387 27388 27389 27390 27391 27392 27393 27394 27395 27396 27397 27398 27399 27400 27401 27402 27403 27404 27405 27406 27407 27408 27409 27410 27411 27412 27413 27414 27415 27416 27417 27418 27419 27420 27421 27422 27423 27424 27425 27426 27427 27428 27429 27430 27431 27432 27433 27434 27435 27436 27437 27438 27439 27440 27441 27442 27443 27444 27445 27446 27447 27448 27449 27450 27451 27452 27453 27454 27455 27456 27457 27458 27459 27460 27461 27462 27463 27464 27465 27466 27467 27468 27469 27470 27471 27472 27473 27474 27475 27476 27477 27478 27479 27480 27481 27482 27483 27484 27485 27486 27487 27488 27489 27490 27491 27492 27493 27494 27495 27496 27497 27498 27499 27500 27501 27502 27503 27504 27505 27506 27507 27508 27509 27510 27511 27512 27513 27514 27515 27516 27517 27518 27519 27520 27521 27522 27523 27524 27525 27526 27527 27528 27529 27530 27531 27532 27533 27534 27535 27536 27537 27538 27539 27540 27541 27542 27543 27544 27545 27546 27547 27548 27549 27550 27551 27552 27553 27554 27555 27556 27557 27558 27559 27560 27561 27562 27563 27564 27565 27566 27567 27568 27569 27570 27571 27572 27573 27574 27575 27576 27577 27578 27579 27580 27581 27582 27583 27584 27585 27586 27587 27588 27589 27590 27591 27592 27593 27594 27595 27596 27597 27598 27599 27600 27601 27602 27603 27604 27605 27606 27607 27608 27609 27610 27611 27612 27613 27614 27615 27616 27617 27618 27619 27620 27621 27622 27623 27624 27625 27626 27627 27628 27629 27630 27631 27632 27633 27634 27635 27636 27637 27638 27639 27640 27641 27642 27643 27644 27645 27646 27647 27648 27649 27650 27651 27652 27653 27654 27655 27656 27657 27658 27659 27660 27661 27662 27663 27664 27665 27666 27667 27668 27669 27670 27671 27672 27673 27674 27675 27676 27677 27678 27679 27680 27681 27682 27683 27684 27685 27686 27687 27688 27689 27690 27691 27692 27693 27694 27695 27696 27697 27698 27699 27700 27701 27702 27703 27704 27705 27706 27707 27708 27709 27710 27711 27712 27713 27714 27715 27716 27717 27718 27719 27720 27721 27722 27723 27724 27725 27726 27727 27728 27729 27730 27731 27732 27733 27734 27735 27736 27737 27738 27739 27740 27741 27742 27743 27744 27745 27746 27747 27748 27749 27750 27751 27752 27753 27754 27755 27756 27757 27758 27759 27760 27761 27762 27763 27764 27765 27766 27767 27768 27769 27770 27771 27772 27773 27774 27775 27776 27777 27778 27779 27780 27781 27782 27783 27784 27785 27786 27787 27788 27789 27790 27791 27792 27793 27794 27795 27796 27797 27798 27799 27800 27801 27802 27803 27804 27805 27806 27807 27808 27809 27810 27811 27812 27813 27814 27815 27816 27817 27818 27819 27820 27821 27822 27823 27824 27825 27826 27827 27828 27829 27830 27831 27832 27833 27834 27835 27836 27837 27838 27839 27840 27841 27842 27843 27844 27845 27846 27847 27848 27849 27850 27851 27852 27853 27854 27855 27856 27857 27858 27859 27860 27861 27862 27863 27864 27865 27866 27867 27868 27869 27870 27871 27872 27873 27874 27875 27876 27877 27878 27879 27880 27881 27882 27883 27884 27885 27886 27887 27888 27889 27890 27891 27892 27893 27894 27895 27896 27897 27898 27899 27900 27901 27902 27903 27904 27905 27906 27907 27908 27909 27910 27911 27912 27913 27914 27915 27916 27917 27918 27919 27920 27921 27922 27923 27924 27925 27926 27927 27928 27929 27930 27931 27932 27933 27934 27935 27936 27937 27938 27939 27940 27941 27942 27943 27944 27945 27946 27947 27948 27949 27950 27951 27952 27953 27954 27955 27956 27957 27958 27959 27960 27961 27962 27963 27964 27965 27966 27967 27968 27969 27970 27971 27972 27973 27974 27975 27976 27977 27978 27979 27980 27981 27982 27983 27984 27985 27986 27987 27988 27989 27990 27991 27992 27993 27994 27995 27996 27997 27998 27999 28000 28001 28002 28003 28004 28005 28006 28007 28008 28009 28010 28011 28012 28013 28014 28015 28016 28017 28018 28019 28020 28021 28022 28023 28024 28025 28026 28027 28028 28029 28030 28031 28032 28033 28034 28035 28036 28037 28038 28039 28040 28041 28042 28043 28044 28045 28046 28047 28048 28049 28050 28051 28052 28053 28054 28055 28056 28057 28058 28059 28060 28061 28062 28063 28064 28065 28066 28067 28068 28069 28070 28071 28072 28073 28074 28075 28076 28077 28078 28079 28080 28081 28082 28083 28084 28085 28086 28087 28088 28089 28090 28091 28092 28093 28094 28095 28096 28097 28098 28099 28100 28101 28102 28103 28104 28105 28106 28107 28108 28109 28110 28111 28112 28113 28114 28115 28116 28117 28118 28119 28120 28121 28122 28123 28124 28125 28126 28127 28128 28129 28130 28131 28132 28133 28134 28135 28136 28137 28138 28139 28140 28141 28142 28143 28144 28145 28146 28147 28148 28149 28150 28151 28152 28153 28154 28155 28156 28157 28158 28159 28160 28161 28162 28163 28164 28165 28166 28167 28168 28169 28170 28171 28172 28173 28174 28175 28176 28177 28178 28179 28180 28181 28182 28183 28184 28185 28186 28187 28188 28189 28190 28191 28192 28193 28194 28195 28196 28197 28198 28199 28200 28201 28202 28203 28204 28205 28206 28207 28208 28209 28210 28211 28212 28213 28214 28215 28216 28217 28218 28219 28220 28221 28222 28223 28224 28225 28226 28227 28228 28229 28230 28231 28232 28233 28234 28235 28236 28237 28238 28239 28240 28241 28242 28243 28244 28245 28246 28247 28248 28249 28250 28251 28252 28253 28254 28255 28256 28257 28258 28259 28260 28261 28262 28263 28264 28265 28266 28267 28268 28269 28270 28271 28272 28273 28274 28275 28276 28277 28278 28279 28280 28281 28282 28283 28284 28285 28286 28287 28288 28289 28290 28291 28292 28293 28294 28295 28296 28297 28298 28299 28300 28301 28302 28303 28304 28305 28306 28307 28308 28309 28310 28311 28312 28313 28314 28315 28316 28317 28318 28319 28320 28321 28322 28323 28324 28325 28326 28327 28328 28329 28330 28331 28332 28333 28334 28335 28336 28337 28338 28339 28340 28341 28342 28343 28344 28345 28346 28347 28348 28349 28350 28351 28352 28353 28354 28355 28356 28357 28358 28359 28360 28361 28362 28363 28364 28365 28366 28367 28368 28369 28370 28371 28372 28373 28374 28375 28376 28377 28378 28379 28380 28381 28382 28383 28384 28385 28386 28387 28388 28389 28390 28391 28392 28393 28394 28395 28396 28397 28398 28399 28400 28401 28402 28403 28404 28405 28406 28407 28408 28409 28410 28411 28412 28413 28414 28415 28416 28417 28418 28419 28420 28421 28422 28423 28424 28425 28426 28427 28428 28429 28430 28431 28432 28433 28434 28435 28436 28437 28438 28439 28440 28441 28442 28443 28444 28445 28446 28447 28448 28449 28450 28451 28452 28453 28454 28455 28456 28457 28458 28459 28460 28461 28462 28463 28464 28465 28466 28467 28468 28469 28470 28471 28472 28473 28474 28475 28476 28477 28478 28479 28480 28481 28482 28483 28484 28485 28486 28487 28488 28489 28490 28491 28492 28493 28494 28495 28496 28497 28498 28499 28500 28501 28502 28503 28504 28505 28506 28507 28508 28509 28510 28511 28512 28513 28514 28515 28516 28517 28518 28519 28520 28521 28522 28523 28524 28525 28526 28527 28528 28529 28530 28531 28532 28533 28534 28535 28536 28537 28538 28539 28540 28541 28542 28543 28544 28545 28546 28547 28548 28549 28550 28551 28552 28553 28554 28555 28556 28557 28558 28559 28560 28561 28562 28563 28564 28565 28566 28567 28568 28569 28570 28571 28572 28573 28574 28575 28576 28577 28578 28579 28580 28581 28582 28583 28584 28585 28586 28587 28588 28589 28590 28591 28592 28593 28594 28595 28596 28597 28598 28599 28600 28601 28602 28603 28604 28605 28606 28607 28608 28609 28610 28611 28612 28613 28614 28615 28616 28617 28618 28619 28620 28621 28622 28623 28624 28625 28626 28627 28628 28629 28630 28631 28632 28633 28634 28635 28636 28637 28638 28639 28640 28641 28642 28643 28644 28645 28646 28647 28648 28649 28650 28651 28652 28653 28654 28655 28656 28657 28658 28659 28660 28661 28662 28663 28664 28665 28666 28667 28668 28669 28670 28671 28672 28673 28674 28675 28676 28677 28678 28679 28680 28681 28682 28683 28684 28685 28686 28687 28688 28689 28690 28691 28692 28693 28694 28695 28696 28697 28698 28699 28700 28701 28702 28703 28704 28705 28706 28707 28708 28709 28710 28711 28712 28713 28714 28715 28716 28717 28718 28719 28720 28721 28722 28723 28724 28725 28726 28727 28728 28729 28730 28731 28732 28733 28734 28735 28736 28737 28738 28739 28740 28741 28742 28743 28744 28745 28746 28747 28748 28749 28750 28751 28752 28753 28754 28755 28756 28757 28758 28759 28760 28761 28762 28763 28764 28765 28766 28767 28768 28769 28770 28771 28772 28773 28774 28775 28776 28777 28778 28779 28780 28781 28782 28783 28784 28785 28786 28787 28788 28789 28790 28791 28792 28793 28794 28795 28796 28797 28798 28799 28800 28801 28802 28803 28804 28805 28806 28807 28808 28809 28810 28811 28812 28813 28814 28815 28816 28817 28818 28819 28820 28821 28822 28823 28824 28825 28826 28827 28828 28829 28830 28831 28832 28833 28834 28835 28836 28837 28838 28839 28840 28841 28842 28843 28844 28845 28846 28847 28848 28849 28850 28851 28852 28853 28854 28855 28856 28857 28858 28859 28860 28861 28862 28863 28864 28865 28866 28867 28868 28869 28870 28871 28872 28873 28874 28875 28876 28877 28878 28879 28880 28881 28882 28883 28884 28885 28886 28887 28888 28889 28890 28891 28892 28893 28894 28895 28896 28897 28898 28899 28900 28901 28902 28903 28904 28905 28906 28907 28908 28909 28910 28911 28912 28913 28914 28915 28916 28917 28918 28919 28920 28921 28922 28923 28924 28925 28926 28927 28928 28929 28930 28931 28932 28933 28934 28935 28936 28937 28938 28939 28940 28941 28942 28943 28944 28945 28946 28947 28948 28949 28950 28951 28952 28953 28954 28955 28956 28957 28958 28959 28960 28961 28962 28963 28964 28965 28966 28967 28968 28969 28970 28971 28972 28973 28974 28975 28976 28977 28978 28979 28980 28981 28982 28983 28984 28985 28986 28987 28988 28989 28990 28991 28992 28993 28994 28995 28996 28997 28998 28999 29000 29001 29002 29003 29004 29005 29006 29007 29008 29009 29010 29011 29012 29013 29014 29015 29016 29017 29018 29019 29020 29021 29022 29023 29024 29025 29026 29027 29028 29029 29030 29031 29032 29033 29034 29035 29036 29037 29038 29039 29040 29041 29042 29043 29044 29045 29046 29047 29048 29049 29050 29051 29052 29053 29054 29055 29056 29057 29058 29059 29060 29061 29062 29063 29064 29065 29066 29067 29068 29069 29070 29071 29072 29073 29074 29075 29076 29077 29078 29079 29080 29081 29082 29083 29084 29085 29086 29087 29088 29089 29090 29091 29092 29093 29094 29095 29096 29097 29098 29099 29100 29101 29102 29103 29104 29105 29106 29107 29108 29109 29110 29111 29112 29113 29114 29115 29116 29117 29118 29119 29120 29121 29122 29123 29124 29125 29126 29127 29128 29129 29130 29131 29132 29133 29134 29135 29136 29137 29138 29139 29140 29141 29142 29143 29144 29145 29146 29147 29148 29149 29150 29151 29152 29153 29154 29155 29156 29157 29158 29159 29160 29161 29162 29163 29164 29165 29166 29167 29168 29169 29170 29171 29172 29173 29174 29175 29176 29177 29178 29179 29180 29181 29182 29183 29184 29185 29186 29187 29188 29189 29190 29191 29192 29193 29194 29195 29196 29197 29198 29199 29200 29201 29202 29203 29204 29205 29206 29207 29208 29209 29210 29211 29212 29213 29214 29215 29216 29217 29218 29219 29220 29221 29222 29223 29224 29225 29226 29227 29228 29229 29230 29231 29232 29233 29234 29235 29236 29237 29238 29239 29240 29241 29242 29243 29244 29245 29246 29247 29248 29249 29250 29251 29252 29253 29254 29255 29256 29257 29258 29259 29260 29261 29262 29263 29264 29265 29266 29267 29268 29269 29270 29271 29272 29273 29274 29275 29276 29277 29278 29279 29280 29281 29282 29283 29284 29285 29286 29287 29288 29289 29290 29291 29292 29293 29294 29295 29296 29297 29298 29299 29300 29301 29302 29303 29304 29305 29306 29307 29308 29309 29310 29311 29312 29313 29314 29315 29316 29317 29318 29319 29320 29321 29322 29323 29324 29325 29326 29327 29328 29329 29330 29331 29332 29333 29334 29335 29336 29337 29338 29339 29340 29341 29342 29343 29344 29345 29346 29347 29348 29349 29350 29351 29352 29353 29354 29355 29356 29357 29358 29359 29360 29361 29362 29363 29364 29365 29366 29367 29368 29369 29370 29371 29372 29373 29374 29375 29376 29377 29378 29379 29380 29381 29382 29383 29384 29385 29386 29387 29388 29389 29390 29391 29392 29393 29394 29395 29396 29397 29398 29399 29400 29401 29402 29403 29404 29405 29406 29407 29408 29409 29410 29411 29412 29413 29414 29415 29416 29417 29418 29419 29420 29421 29422 29423 29424 29425 29426 29427 29428 29429 29430 29431 29432 29433 29434 29435 29436 29437 29438 29439 29440 29441 29442 29443 29444 29445 29446 29447 29448 29449 29450 29451 29452 29453 29454 29455 29456 29457 29458 29459 29460 29461 29462 29463 29464 29465 29466 29467 29468 29469 29470 29471 29472 29473 29474 29475 29476 29477 29478 29479 29480 29481 29482 29483 29484 29485 29486 29487 29488 29489 29490 29491 29492 29493 29494 29495 29496 29497 29498 29499 29500 29501 29502 29503 29504 29505 29506 29507 29508 29509 29510 29511 29512 29513 29514 29515 29516 29517 29518 29519 29520 29521 29522 29523 29524 29525 29526 29527 29528 29529 29530 29531 29532 29533 29534 29535 29536 29537 29538 29539 29540 29541 29542 29543 29544 29545 29546 29547 29548 29549 29550 29551 29552 29553 29554 29555 29556 29557 29558 29559 29560 29561 29562 29563 29564 29565 29566 29567 29568 29569 29570 29571 29572 29573 29574 29575 29576 29577 29578 29579 29580 29581 29582 29583 29584 29585 29586 29587 29588 29589 29590 29591 29592 29593 29594 29595 29596 29597 29598 29599 29600 29601 29602 29603 29604 29605 29606 29607 29608 29609 29610 29611 29612 29613 29614 29615 29616 29617 29618 29619 29620 29621 29622 29623 29624 29625 29626 29627 29628 29629 29630 29631 29632 29633 29634 29635 29636 29637 29638 29639 29640 29641 29642 29643 29644 29645 29646 29647 29648 29649 29650 29651 29652 29653 29654 29655 29656 29657 29658 29659 29660 29661 29662 29663 29664 29665 29666 29667 29668 29669 29670 29671 29672 29673 29674 29675 29676 29677 29678 29679 29680 29681 29682 29683 29684 29685 29686 29687 29688 29689 29690 29691 29692 29693 29694 29695 29696 29697 29698 29699 29700 29701 29702 29703 29704 29705 29706 29707 29708 29709 29710 29711 29712 29713 29714 29715 29716 29717 29718 29719 29720 29721 29722 29723 29724 29725 29726 29727 29728 29729 29730 29731 29732 29733 29734 29735 29736 29737 29738 29739 29740 29741 29742 29743 29744 29745 29746 29747 29748 29749 29750 29751 29752 29753 29754 29755 29756 29757 29758 29759 29760 29761 29762 29763 29764 29765 29766 29767 29768 29769 29770 29771 29772 29773 29774 29775 29776 29777 29778 29779 29780 29781 29782 29783 29784 29785 29786 29787 29788 29789 29790 29791 29792 29793 29794 29795 29796 29797 29798 29799 29800 29801 29802 29803 29804 29805 29806 29807 29808 29809 29810 29811 29812 29813 29814 29815 29816 29817 29818 29819 29820 29821 29822 29823 29824 29825 29826 29827 29828 29829 29830 29831 29832 29833 29834 29835 29836 29837 29838 29839 29840 29841 29842 29843 29844 29845 29846 29847 29848 29849 29850 29851 29852 29853 29854 29855 29856 29857 29858 29859 29860 29861 29862 29863 29864 29865 29866 29867 29868 29869 29870 29871 29872 29873 29874 29875 29876 29877 29878 29879 29880 29881 29882 29883 29884 29885 29886 29887 29888 29889 29890 29891 29892 29893 29894 29895 29896 29897 29898 29899 29900 29901 29902 29903 29904 29905 29906 29907 29908 29909 29910 29911 29912 29913 29914 29915 29916 29917 29918 29919 29920 29921 29922 29923 29924 29925 29926 29927 29928 29929 29930 29931 29932 29933 29934 29935 29936 29937 29938 29939 29940 29941 29942 29943 29944 29945 29946 29947 29948 29949 29950 29951 29952 29953 29954 29955 29956 29957 29958 29959 29960 29961 29962 29963 29964 29965 29966 29967 29968 29969 29970 29971 29972 29973 29974 29975 29976 29977 29978 29979 29980 29981 29982 29983 29984 29985 29986 29987 29988 29989 29990 29991 29992 29993 29994 29995 29996 29997 29998 29999 30000 30001 30002 30003 30004 30005 30006 30007 30008 30009 30010 30011 30012 30013 30014 30015 30016 30017 30018 30019 30020 30021 30022 30023 30024 30025 30026 30027 30028 30029 30030 30031 30032 30033 30034 30035 30036 30037 30038 30039 30040 30041 30042 30043 30044 30045 30046 30047 30048 30049 30050 30051 30052 30053 30054 30055 30056 30057 30058 30059 30060 30061 30062 30063 30064 30065 30066 30067 30068 30069 30070 30071 30072 30073 30074 30075 30076 30077 30078 30079 30080 30081 30082 30083 30084 30085 30086 30087 30088 30089 30090 30091 30092 30093 30094 30095 30096 30097 30098 30099 30100 30101 30102 30103 30104 30105 30106 30107 30108 30109 30110 30111 30112 30113 30114 30115 30116 30117 30118 30119 30120 30121 30122 30123 30124 30125 30126 30127 30128 30129 30130 30131 30132 30133 30134 30135 30136 30137 30138 30139 30140 30141 30142 30143 30144 30145 30146 30147 30148 30149 30150 30151 30152 30153 30154 30155 30156 30157 30158 30159 30160 30161 30162 30163 30164 30165 30166 30167 30168 30169 30170 30171 30172 30173 30174 30175 30176 30177 30178 30179 30180 30181 30182 30183 30184 30185 30186 30187 30188 30189 30190 30191 30192 30193 30194 30195 30196 30197 30198 30199 30200 30201 30202 30203 30204 30205 30206 30207 30208 30209 30210 30211 30212 30213 30214 30215 30216 30217 30218 30219 30220 30221 30222 30223 30224 30225 30226 30227 30228 30229 30230 30231 30232 30233 30234 30235 30236 30237 30238 30239 30240 30241 30242 30243 30244 30245 30246 30247 30248 30249 30250 30251 30252 30253 30254 30255 30256 30257 30258 30259 30260 30261 30262 30263 30264 30265 30266 30267 30268 30269 30270 30271 30272 30273 30274 30275 30276 30277 30278 30279 30280 30281 30282 30283 30284 30285 30286 30287 30288 30289 30290 30291 30292 30293 30294 30295 30296 30297 30298 30299 30300 30301 30302 30303 30304 30305 30306 30307 30308 30309 30310 30311 30312 30313 30314 30315 30316 30317 30318 30319 30320 30321 30322 30323 30324 30325 30326 30327 30328 30329 30330 30331 30332 30333 30334 30335 30336 30337 30338 30339 30340 30341 30342 30343 30344 30345 30346 30347 30348 30349 30350 30351 30352 30353 30354 30355 30356 30357 30358 30359 30360 30361 30362 30363 30364 30365 30366 30367 30368 30369 30370 30371 30372 30373 30374 30375 30376 30377 30378 30379 30380 30381 30382 30383 30384 30385 30386 30387 30388 30389 30390 30391 30392 30393 30394 30395 30396 30397 30398 30399 30400 30401 30402 30403 30404 30405 30406 30407 30408 30409 30410 30411 30412 30413 30414 30415 30416 30417 30418 30419 30420 30421 30422 30423 30424 30425 30426 30427 30428 30429 30430 30431 30432 30433 30434 30435 30436 30437 30438 30439 30440 30441 30442 30443 30444 30445 30446 30447 30448 30449 30450 30451 30452 30453 30454 30455 30456 30457 30458 30459 30460 30461 30462 30463 30464 30465 30466 30467 30468 30469 30470 30471 30472 30473 30474 30475 30476 30477 30478 30479 30480 30481 30482 30483 30484 30485 30486 30487 30488 30489 30490 30491 30492 30493 30494 30495 30496 30497 30498 30499 30500 30501 30502 30503 30504 30505 30506 30507 30508 30509 30510 30511 30512 30513 30514 30515 30516 30517 30518 30519 30520 30521 30522 30523 30524 30525 30526 30527 30528 30529 30530 30531 30532 30533 30534 30535 30536 30537 30538 30539 30540 30541 30542 30543 30544 30545 30546 30547 30548 30549 30550 30551 30552 30553 30554 30555 30556 30557 30558 30559 30560 30561 30562 30563 30564 30565 30566 30567 30568 30569 30570 30571 30572 30573 30574 30575 30576 30577 30578 30579 30580 30581 30582 30583 30584 30585 30586 30587 30588 30589 30590 30591 30592 30593 30594 30595 30596 30597 30598 30599 30600 30601 30602 30603 30604 30605 30606 30607 30608 30609 30610 30611 30612 30613 30614 30615 30616 30617 30618 30619 30620 30621 30622 30623 30624 30625 30626 30627 30628 30629 30630 30631 30632 30633 30634 30635 30636 30637 30638 30639 30640 30641 30642 30643 30644 30645 30646 30647 30648 30649 30650 30651 30652 30653 30654 30655 30656 30657 30658 30659 30660 30661 30662 30663 30664 30665 30666 30667 30668 30669 30670 30671 30672 30673 30674 30675 30676 30677 30678 30679 30680 30681 30682 30683 30684 30685 30686 30687 30688 30689 30690 30691 30692 30693 30694 30695 30696 30697 30698 30699 30700 30701 30702 30703 30704 30705 30706 30707 30708 30709 30710 30711 30712 30713 30714 30715 30716 30717 30718 30719 30720 30721 30722 30723 30724 30725 30726 30727 30728 30729 30730 30731 30732 30733 30734 30735 30736 30737 30738 30739 30740 30741 30742 30743 30744 30745 30746 30747 30748 30749 30750 30751 30752 30753 30754 30755 30756 30757 30758 30759 30760 30761 30762 30763 30764 30765 30766 30767 30768 30769 30770 30771 30772 30773 30774 30775 30776 30777 30778 30779 30780 30781 30782 30783 30784 30785 30786 30787 30788 30789 30790 30791 30792 30793 30794 30795 30796 30797 30798 30799 30800 30801 30802 30803 30804 30805 30806 30807 30808 30809 30810 30811 30812 30813 30814 30815 30816 30817 30818 30819 30820 30821 30822 30823 30824 30825 30826 30827 30828 30829 30830 30831 30832 30833 30834 30835 30836 30837 30838 30839 30840 30841 30842 30843 30844 30845 30846 30847 30848 30849 30850 30851 30852 30853 30854 30855 30856 30857 30858 30859 30860 30861 30862 30863 30864 30865 30866 30867 30868 30869 30870 30871 30872 30873 30874 30875 30876 30877 30878 30879 30880 30881 30882 30883 30884 30885 30886 30887 30888 30889 30890 30891 30892 30893 30894 30895 30896 30897 30898 30899 30900 30901 30902 30903 30904 30905 30906 30907 30908 30909 30910 30911 30912 30913 30914 30915 30916 30917 30918 30919 30920 30921 30922 30923 30924 30925 30926 30927 30928 30929 30930 30931 30932 30933 30934 30935 30936 30937 30938 30939 30940 30941 30942 30943 30944 30945 30946 30947 30948 30949 30950 30951 30952 30953 30954 30955 30956 30957 30958 30959 30960 30961 30962 30963 30964 30965 30966 30967 30968 30969 30970 30971 30972 30973 30974 30975 30976 30977 30978 30979 30980 30981 30982 30983 30984 30985 30986 30987 30988 30989 30990 30991 30992 30993 30994 30995 30996 30997 30998 30999 31000 31001 31002 31003 31004 31005 31006 31007 31008 31009 31010 31011 31012 31013 31014 31015 31016 31017 31018 31019 31020 31021 31022 31023 31024 31025 31026 31027 31028 31029 31030 31031 31032 31033 31034 31035 31036 31037 31038 31039 31040 31041 31042 31043 31044 31045 31046 31047 31048 31049 31050 31051 31052 31053 31054 31055 31056 31057 31058 31059 31060 31061 31062 31063 31064 31065 31066 31067 31068 31069 31070 31071 31072 31073 31074 31075 31076 31077 31078 31079 31080 31081 31082 31083 31084 31085 31086 31087 31088 31089 31090 31091 31092 31093 31094 31095 31096 31097 31098 31099 31100 31101 31102 31103 31104 31105 31106 31107 31108 31109 31110 31111 31112 31113 31114 31115 31116 31117 31118 31119 31120 31121 31122 31123 31124 31125 31126 31127 31128 31129 31130 31131 31132 31133 31134 31135 31136 31137 31138 31139 31140 31141 31142 31143 31144 31145 31146 31147 31148 31149 31150 31151 31152 31153 31154 31155 31156 31157 31158 31159 31160 31161 31162 31163 31164 31165 31166 31167 31168 31169 31170 31171 31172 31173 31174 31175 31176 31177 31178 31179 31180 31181 31182 31183 31184 31185 31186 31187 31188 31189 31190 31191 31192 31193 31194 31195 31196 31197 31198 31199 31200 31201 31202 31203 31204 31205 31206 31207 31208 31209 31210 31211 31212 31213 31214 31215 31216 31217 31218 31219 31220 31221 31222 31223 31224 31225 31226 31227 31228 31229 31230 31231 31232 31233 31234 31235 31236 31237 31238 31239 31240 31241 31242 31243 31244 31245 31246 31247 31248 31249 31250 31251 31252 31253 31254 31255 31256 31257 31258 31259 31260 31261 31262 31263 31264 31265 31266 31267 31268 31269 31270 31271 31272 31273 31274 31275 31276 31277 31278 31279 31280 31281 31282 31283 31284 31285 31286 31287 31288 31289 31290 31291 31292 31293 31294 31295 31296 31297 31298 31299 31300 31301 31302 31303 31304 31305 31306 31307 31308 31309 31310 31311 31312 31313 31314 31315 31316 31317 31318 31319 31320 31321 31322 31323 31324 31325 31326 31327 31328 31329 31330 31331 31332 31333 31334 31335 31336 31337 31338 31339 31340 31341 31342 31343 31344 31345 31346 31347 31348 31349 31350 31351 31352 31353 31354 31355 31356 31357 31358 31359 31360 31361 31362 31363 31364 31365 31366 31367 31368 31369 31370 31371 31372 31373 31374 31375 31376 31377 31378 31379 31380 31381 31382 31383 31384 31385 31386 31387 31388 31389 31390 31391 31392 31393 31394 31395 31396 31397 31398 31399 31400 31401 31402 31403 31404 31405 31406 31407 31408 31409 31410 31411 31412 31413 31414 31415 31416 31417 31418 31419 31420 31421 31422 31423 31424 31425 31426 31427 31428 31429 31430 31431 31432 31433 31434 31435 31436 31437 31438 31439 31440 31441 31442 31443 31444 31445 31446 31447 31448 31449 31450 31451 31452 31453 31454 31455 31456 31457 31458 31459 31460 31461 31462 31463 31464 31465 31466 31467 31468 31469 31470 31471 31472 31473 31474 31475 31476 31477 31478 31479 31480 31481 31482 31483 31484 31485 31486 31487 31488 31489 31490 31491 31492 31493 31494 31495 31496 31497 31498 31499 31500 31501 31502 31503 31504 31505 31506 31507 31508 31509 31510 31511 31512 31513 31514 31515 31516 31517 31518 31519 31520 31521 31522 31523 31524 31525 31526 31527 31528 31529 31530 31531 31532 31533 31534 31535 31536 31537 31538 31539 31540 31541 31542 31543 31544 31545 31546 31547 31548 31549 31550 31551 31552 31553 31554 31555 31556 31557 31558 31559 31560 31561 31562 31563 31564 31565 31566 31567 31568 31569 31570 31571 31572 31573 31574 31575 31576 31577 31578 31579 31580 31581 31582 31583 31584 31585 31586 31587 31588 31589 31590 31591 31592 31593 31594 31595 31596 31597 31598 31599 31600 31601 31602 31603 31604 31605 31606 31607 31608 31609 31610 31611 31612 31613 31614 31615 31616 31617 31618 31619 31620 31621 31622 31623 31624 31625 31626 31627 31628 31629 31630 31631 31632 31633 31634 31635 31636 31637 31638 31639 31640 31641 31642 31643 31644 31645 31646 31647 31648 31649 31650 31651 31652 31653 31654 31655 31656 31657 31658 31659 31660 31661 31662 31663 31664 31665 31666 31667 31668 31669 31670 31671 31672 31673 31674 31675 31676 31677 31678 31679 31680 31681 31682 31683 31684 31685 31686 31687 31688 31689 31690 31691 31692 31693 31694 31695 31696 31697 31698 31699 31700 31701 31702 31703 31704 31705 31706 31707 31708 31709 31710 31711 31712 31713 31714 31715 31716 31717 31718 31719 31720 31721 31722 31723 31724 31725 31726 31727 31728 31729 31730 31731 31732 31733 31734 31735 31736 31737 31738 31739 31740 31741 31742 31743 31744 31745 31746 31747 31748 31749 31750 31751 31752 31753 31754 31755 31756 31757 31758 31759 31760 31761 31762 31763 31764 31765 31766 31767 31768 31769 31770 31771 31772 31773 31774 31775 31776 31777 31778 31779 31780 31781 31782 31783 31784 31785 31786 31787 31788 31789 31790 31791 31792 31793 31794 31795 31796 31797 31798 31799 31800 31801 31802 31803 31804 31805 31806 31807 31808 31809 31810 31811 31812 31813 31814 31815 31816 31817 31818 31819 31820 31821 31822 31823 31824 31825 31826 31827 31828 31829 31830 31831 31832 31833 31834 31835 31836 31837 31838 31839 31840 31841 31842 31843 31844 31845 31846 31847 31848 31849 31850 31851 31852 31853 31854 31855 31856 31857 31858 31859 31860 31861 31862 31863 31864 31865 31866 31867 31868 31869 31870 31871 31872 31873 31874 31875 31876 31877 31878 31879 31880 31881 31882 31883 31884 31885 31886 31887 31888 31889 31890 31891 31892 31893 31894 31895 31896 31897 31898 31899 31900 31901 31902 31903 31904 31905 31906 31907 31908 31909 31910 31911 31912 31913 31914 31915 31916 31917 31918 31919 31920 31921 31922 31923 31924 31925 31926 31927 31928 31929 31930 31931 31932 31933 31934 31935 31936 31937 31938 31939 31940 31941 31942 31943 31944 31945 31946 31947 31948 31949 31950 31951 31952 31953 31954 31955 31956 31957 31958 31959 31960 31961 31962 31963 31964 31965 31966 31967 31968 31969 31970 31971 31972 31973 31974 31975 31976 31977 31978 31979 31980 31981 31982 31983 31984 31985 31986 31987 31988 31989 31990 31991 31992 31993 31994 31995 31996 31997 31998 31999 32000 32001 32002 32003 32004 32005 32006 32007 32008 32009 32010 32011 32012 32013 32014 32015 32016 32017 32018 32019 32020 32021 32022 32023 32024 32025 32026 32027 32028 32029 32030 32031 32032 32033 32034 32035 32036 32037 32038 32039 32040 32041 32042 32043 32044 32045 32046 32047 32048 32049 32050 32051 32052 32053 32054 32055 32056 32057 32058 32059 32060 32061 32062 32063 32064 32065 32066 32067 32068 32069 32070 32071 32072 32073 32074 32075 32076 32077 32078 32079 32080 32081 32082 32083 32084 32085 32086 32087 32088 32089 32090 32091 32092 32093 32094 32095 32096 32097 32098 32099 32100 32101 32102 32103 32104 32105 32106 32107 32108 32109 32110 32111 32112 32113 32114 32115 32116 32117 32118 32119 32120 32121 32122 32123 32124 32125 32126 32127 32128 32129 32130 32131 32132 32133 32134 32135 32136 32137 32138 32139 32140 32141 32142 32143 32144 32145 32146 32147 32148 32149 32150 32151 32152 32153 32154 32155 32156 32157 32158 32159 32160 32161 32162 32163 32164 32165 32166 32167 32168 32169 32170 32171 32172 32173 32174 32175 32176 32177 32178 32179 32180 32181 32182 32183 32184 32185 32186 32187 32188 32189 32190 32191 32192 32193 32194 32195 32196 32197 32198 32199 32200 32201 32202 32203 32204 32205 32206 32207 32208 32209 32210 32211 32212 32213 32214 32215 32216 32217 32218 32219 32220 32221 32222 32223 32224 32225 32226 32227 32228 32229 32230 32231 32232 32233 32234 32235 32236 32237 32238 32239 32240 32241 32242 32243 32244 32245 32246 32247 32248 32249 32250 32251 32252 32253 32254 32255 32256 32257 32258 32259 32260 32261 32262 32263 32264 32265 32266 32267 32268 32269 32270 32271 32272 32273 32274 32275 32276 32277 32278 32279 32280 32281 32282 32283 32284 32285 32286 32287 32288 32289 32290 32291 32292 32293 32294 32295 32296 32297 32298 32299 32300 32301 32302 32303 32304 32305 32306 32307 32308 32309 32310 32311 32312 32313 32314 32315 32316 32317 32318 32319 32320 32321 32322 32323 32324 32325 32326 32327 32328 32329 32330 32331 32332 32333 32334 32335 32336 32337 32338 32339 32340 32341 32342 32343 32344 32345 32346 32347 32348 32349 32350 32351 32352 32353 32354 32355 32356 32357 32358 32359 32360 32361 32362 32363 32364 32365 32366 32367 32368 32369 32370 32371 32372 32373 32374 32375 32376 32377 32378 32379 32380 32381 32382 32383 32384 32385 32386 32387 32388 32389 32390 32391 32392 32393 32394 32395 32396 32397 32398 32399 32400 32401 32402 32403 32404 32405 32406 32407 32408 32409 32410 32411 32412 32413 32414 32415 32416 32417 32418 32419 32420 32421 32422 32423 32424 32425 32426 32427 32428 32429 32430 32431 32432 32433 32434 32435 32436 32437 32438 32439 32440 32441 32442 32443 32444 32445 32446 32447 32448 32449 32450 32451 32452 32453 32454 32455 32456 32457 32458 32459 32460 32461 32462 32463 32464 32465 32466 32467 32468 32469 32470 32471 32472 32473 32474 32475 32476 32477 32478 32479 32480 32481 32482 32483 32484 32485 32486 32487 32488 32489 32490 32491 32492 32493 32494 32495 32496 32497 32498 32499 32500 32501 32502 32503 32504 32505 32506 32507 32508 32509 32510 32511 32512 32513 32514 32515 32516 32517 32518 32519 32520 32521 32522 32523 32524 32525 32526 32527 32528 32529 32530 32531 32532 32533 32534 32535 32536 32537 32538 32539 32540 32541 32542 32543 32544 32545 32546 32547 32548 32549 32550 32551 32552 32553 32554 32555 32556 32557 32558 32559 32560 32561 32562 32563 32564 32565 32566 32567 32568 32569 32570 32571 32572 32573 32574 32575 32576 32577 32578 32579 32580 32581 32582 32583 32584 32585 32586 32587 32588 32589 32590 32591 32592 32593 32594 32595 32596 32597 32598 32599 32600 32601 32602 32603 32604 32605 32606 32607 32608 32609 32610 32611 32612 32613 32614 32615 32616 32617 32618 32619 32620 32621 32622 32623 32624 32625 32626 32627 32628 32629 32630 32631 32632 32633 32634 32635 32636 32637 32638 32639 32640 32641 32642 32643 32644 32645 32646 32647 32648 32649 32650 32651 32652 32653 32654 32655 32656 32657 32658 32659 32660 32661 32662 32663 32664 32665 32666 32667 32668 32669 32670 32671 32672 32673 32674 32675 32676 32677 32678 32679 32680 32681 32682 32683 32684 32685 32686 32687 32688 32689 32690 32691 32692 32693 32694 32695 32696 32697 32698 32699 32700 32701 32702 32703 32704 32705 32706 32707 32708 32709 32710 32711 32712 32713 32714 32715 32716 32717 32718 32719 32720 32721 32722 32723 32724 32725 32726 32727 32728 32729 32730 32731 32732 32733 32734 32735 32736 32737 32738 32739 32740 32741 32742 32743 32744 32745 32746 32747 32748 32749 32750 32751 32752 32753 32754 32755 32756 32757 32758 32759 32760 32761 32762 32763 32764 32765 32766 32767 32768 32769 32770 32771 32772 32773 32774 32775 32776 32777 32778 32779 32780 32781 32782 32783 32784 32785 32786 32787 32788 32789 32790 32791 32792 32793 32794 32795 32796 32797 32798 32799 32800 32801 32802 32803 32804 32805 32806 32807 32808 32809 32810 32811 32812 32813 32814 32815 32816 32817 32818 32819 32820 32821 32822 32823 32824 32825 32826 32827 32828 32829 32830 32831 32832 32833 32834 32835 32836 32837 32838 32839 32840 32841 32842 32843 32844 32845 32846 32847 32848 32849 32850 32851 32852 32853 32854 32855 32856 32857 32858 32859 32860 32861 32862 32863 32864 32865 32866 32867 32868 32869 32870 32871 32872 32873 32874 32875 32876 32877 32878 32879 32880 32881 32882 32883 32884 32885 32886 32887 32888 32889 32890 32891 32892 32893 32894 32895 32896 32897 32898 32899 32900 32901 32902 32903 32904 32905 32906 32907 32908 32909 32910 32911 32912 32913 32914 32915 32916 32917 32918 32919 32920 32921 32922 32923 32924 32925 32926 32927 32928 32929 32930 32931 32932 32933 32934 32935 32936 32937 32938 32939 32940 32941 32942 32943 32944 32945 32946 32947 32948 32949 32950 32951 32952 32953 32954 32955 32956 32957 32958 32959 32960 32961 32962 32963 32964 32965 32966 32967 32968 32969 32970 32971 32972 32973 32974 32975 32976 32977 32978 32979 32980 32981 32982 32983 32984 32985 32986 32987 32988 32989 32990 32991 32992 32993 32994 32995 32996 32997 32998 32999 33000 33001 33002 33003 33004 33005 33006 33007 33008 33009 33010 33011 33012 33013 33014 33015 33016 33017 33018 33019 33020 33021 33022 33023 33024 33025 33026 33027 33028 33029 33030 33031 33032 33033 33034 33035 33036 33037 33038 33039 33040 33041 33042 33043 33044 33045 33046 33047 33048 33049 33050 33051 33052 33053 33054 33055 33056 33057 33058 33059 33060 33061 33062 33063 33064 33065 33066 33067 33068 33069 33070 33071 33072 33073 33074 33075 33076 33077 33078 33079 33080 33081 33082 33083 33084 33085 33086 33087 33088 33089 33090 33091 33092 33093 33094 33095 33096 33097 33098 33099 33100 33101 33102 33103 33104 33105 33106 33107 33108 33109 33110 33111 33112 33113 33114 33115 33116 33117 33118 33119 33120 33121 33122 33123 33124 33125 33126 33127 33128 33129 33130 33131 33132 33133 33134 33135 33136 33137 33138 33139 33140 33141 33142 33143 33144 33145 33146 33147 33148 33149 33150 33151 33152 33153 33154 33155 33156 33157 33158 33159 33160 33161 33162 33163 33164 33165 33166 33167 33168 33169 33170 33171 33172 33173 33174 33175 33176 33177 33178 33179 33180 33181 33182 33183 33184 33185 33186 33187 33188 33189 33190 33191 33192 33193 33194 33195 33196 33197 33198 33199 33200 33201 33202 33203 33204 33205 33206 33207 33208 33209 33210 33211 33212 33213 33214 33215 33216 33217 33218 33219 33220 33221 33222 33223 33224 33225 33226 33227 33228 33229 33230 33231 33232 33233 33234 33235 33236 33237 33238 33239 33240 33241 33242 33243 33244 33245 33246 33247 33248 33249 33250 33251 33252 33253 33254 33255 33256 33257 33258 33259 33260 33261 33262 33263 33264 33265 33266 33267 33268 33269 33270 33271 33272 33273 33274 33275 33276 33277 33278 33279 33280 33281 33282 33283 33284 33285 33286 33287 33288 33289 33290 33291 33292 33293 33294 33295 33296 33297 33298 33299 33300 33301 33302 33303 33304 33305 33306 33307 33308 33309 33310 33311 33312 33313 33314 33315 33316 33317 33318 33319 33320 33321 33322 33323 33324 33325 33326 33327 33328 33329 33330 33331 33332 33333 33334 33335 33336 33337 33338 33339 33340 33341 33342 33343 33344 33345 33346 33347 33348 33349 33350 33351 33352 33353 33354 33355 33356 33357 33358 33359 33360 33361 33362 33363 33364 33365 33366 33367 33368 33369 33370 33371 33372 33373 33374 33375 33376 33377 33378 33379 33380 33381 33382 33383 33384 33385 33386 33387 33388 33389 33390 33391 33392 33393 33394 33395 33396 33397 33398 33399 33400 33401 33402 33403 33404 33405 33406 33407 33408 33409 33410 33411 33412 33413 33414 33415 33416 33417 33418 33419 33420 33421 33422 33423 33424 33425 33426 33427 33428 33429 33430 33431 33432 33433 33434 33435 33436 33437 33438 33439 33440 33441 33442 33443 33444 33445 33446 33447 33448 33449 33450 33451 33452 33453 33454 33455 33456 33457 33458 33459 33460 33461 33462 33463 33464 33465 33466 33467 33468 33469 33470 33471 33472 33473 33474 33475 33476 33477 33478 33479 33480 33481 33482 33483 33484 33485 33486 33487 33488 33489 33490 33491 33492 33493 33494 33495 33496 33497 33498 33499 33500 33501 33502 33503 33504 33505 33506 33507 33508 33509 33510 33511 33512 33513 33514 33515 33516 33517 33518 33519 33520 33521 33522 33523 33524 33525 33526 33527 33528 33529 33530 33531 33532 33533 33534 33535 33536 33537 33538 33539 33540 33541 33542 33543 33544 33545 33546 33547 33548 33549 33550 33551 33552 33553 33554 33555 33556 33557 33558 33559 33560 33561 33562 33563 33564 33565 33566 33567 33568 33569 33570 33571 33572 33573 33574 33575 33576 33577 33578 33579 33580 33581 33582 33583 33584 33585 33586 33587 33588 33589 33590 33591 33592 33593 33594 33595 33596 33597 33598 33599 33600 33601 33602 33603 33604 33605 33606 33607 33608 33609 33610 33611 33612 33613 33614 33615 33616 33617 33618 33619 33620 33621 33622 33623 33624 33625 33626 33627 33628 33629 33630 33631 33632 33633 33634 33635 33636 33637 33638 33639 33640 33641 33642 33643 33644 33645 33646 33647 33648 33649 33650 33651 33652 33653 33654 33655 33656 33657 33658 33659 33660 33661 33662 33663 33664 33665 33666 33667 33668 33669 33670 33671 33672 33673 33674 33675 33676 33677 33678 33679 33680 33681 33682 33683 33684 33685 33686 33687 33688 33689 33690 33691 33692 33693 33694 33695 33696 33697 33698 33699 33700 33701 33702 33703 33704 33705 33706 33707 33708 33709 33710 33711 33712 33713 33714 33715 33716 33717 33718 33719 33720 33721 33722 33723 33724 33725 33726 33727 33728 33729 33730 33731 33732 33733 33734 33735 33736 33737 33738 33739 33740 33741 33742 33743 33744 33745 33746 33747 33748 33749 33750 33751 33752 33753 33754 33755 33756 33757 33758 33759 33760 33761 33762 33763 33764 33765 33766 33767 33768 33769 33770 33771 33772 33773 33774 33775 33776 33777 33778 33779 33780 33781 33782 33783 33784 33785 33786 33787 33788 33789 33790 33791 33792 33793 33794 33795 33796 33797 33798 33799 33800 33801 33802 33803 33804 33805 33806 33807 33808 33809 33810 33811 33812 33813 33814 33815 33816 33817 33818 33819 33820 33821 33822 33823 33824 33825 33826 33827 33828 33829 33830 33831 33832 33833 33834 33835 33836 33837 33838 33839 33840 33841 33842 33843 33844 33845 33846 33847 33848 33849 33850 33851 33852 33853 33854 33855 33856 33857 33858 33859 33860 33861 33862 33863 33864 33865 33866 33867 33868 33869 33870 33871 33872 33873 33874 33875 33876 33877 33878 33879 33880 33881 33882 33883 33884 33885 33886 33887 33888 33889 33890 33891 33892 33893 33894 33895 33896 33897 33898 33899 33900 33901 33902 33903 33904 33905 33906 33907 33908 33909 33910 33911 33912 33913 33914 33915 33916 33917 33918 33919 33920 33921 33922 33923 33924 33925 33926 33927 33928 33929 33930 33931 33932 33933 33934 33935 33936 33937 33938 33939 33940 33941 33942 33943 33944 33945 33946 33947 33948 33949 33950 33951 33952 33953 33954 33955 33956 33957 33958 33959 33960 33961 33962 33963 33964 33965 33966 33967 33968 33969 33970 33971 33972 33973 33974 33975 33976 33977 33978 33979 33980 33981 33982 33983 33984 33985 33986 33987 33988 33989 33990 33991 33992 33993 33994 33995 33996 33997 33998 33999 34000 34001 34002 34003 34004 34005 34006 34007 34008 34009 34010 34011 34012 34013 34014 34015 34016 34017 34018 34019 34020 34021 34022 34023 34024 34025 34026 34027 34028 34029 34030 34031 34032 34033 34034 34035 34036 34037 34038 34039 34040 34041 34042 34043 34044 34045 34046 34047 34048 34049 34050 34051 34052 34053 34054 34055 34056 34057 34058 34059 34060 34061 34062 34063 34064 34065 34066 34067 34068 34069 34070 34071 34072 34073 34074 34075 34076 34077 34078 34079 34080 34081 34082 34083 34084 34085 34086 34087 34088 34089 34090 34091 34092 34093 34094 34095 34096 34097 34098 34099 34100 34101 34102 34103 34104 34105 34106 34107 34108 34109 34110 34111 34112 34113 34114 34115 34116 34117 34118 34119 34120 34121 34122 34123 34124 34125 34126 34127 34128 34129 34130 34131 34132 34133 34134 34135 34136 34137 34138 34139 34140 34141 34142 34143 34144 34145 34146 34147 34148 34149 34150 34151 34152 34153 34154 34155 34156 34157 34158 34159 34160 34161 34162 34163 34164 34165 34166 34167 34168 34169 34170 34171 34172 34173 34174 34175 34176 34177 34178 34179 34180 34181 34182 34183 34184 34185 34186 34187 34188 34189 34190 34191 34192 34193 34194 34195 34196 34197 34198 34199 34200 34201 34202 34203 34204 34205 34206 34207 34208 34209 34210 34211 34212 34213 34214 34215 34216 34217 34218 34219 34220 34221 34222 34223 34224 34225 34226 34227 34228 34229 34230 34231 34232 34233 34234 34235 34236 34237 34238 34239 34240 34241 34242 34243 34244 34245 34246 34247 34248 34249 34250 34251 34252 34253 34254 34255 34256 34257 34258 34259 34260 34261 34262 34263 34264 34265 34266 34267 34268 34269 34270 34271 34272 34273 34274 34275 34276 34277 34278 34279 34280 34281 34282 34283 34284 34285 34286 34287 34288 34289 34290 34291 34292 34293 34294 34295 34296 34297 34298 34299 34300 34301 34302 34303 34304 34305 34306 34307 34308 34309 34310 34311 34312 34313 34314 34315 34316 34317 34318 34319 34320 34321 34322 34323 34324 34325 34326 34327 34328 34329 34330 34331 34332 34333 34334 34335 34336 34337 34338 34339 34340 34341 34342 34343 34344 34345 34346 34347 34348 34349 34350 34351 34352 34353 34354 34355 34356 34357 34358 34359 34360 34361 34362 34363 34364 34365 34366 34367 34368 34369 34370 34371 34372 34373 34374 34375 34376 34377 34378 34379 34380 34381 34382 34383 34384 34385 34386 34387 34388 34389 34390 34391 34392 34393 34394 34395 34396 34397 34398 34399 34400 34401 34402 34403 34404 34405 34406 34407 34408 34409 34410 34411 34412 34413 34414 34415 34416 34417 34418 34419 34420 34421 34422 34423 34424 34425 34426 34427 34428 34429 34430 34431 34432 34433 34434 34435 34436 34437 34438 34439 34440 34441 34442 34443 34444 34445 34446 34447 34448 34449 34450 34451 34452 34453 34454 34455 34456 34457 34458 34459 34460 34461 34462 34463 34464 34465 34466 34467 34468 34469 34470 34471 34472 34473 34474 34475 34476 34477 34478 34479 34480 34481 34482 34483 34484 34485 34486 34487 34488 34489 34490 34491 34492 34493 34494 34495 34496 34497 34498 34499 34500 34501 34502 34503 34504 34505 34506 34507 34508 34509 34510 34511 34512 34513 34514 34515 34516 34517 34518 34519 34520 34521 34522 34523 34524 34525 34526 34527 34528 34529 34530 34531 34532 34533 34534 34535 34536 34537 34538 34539 34540 34541 34542 34543 34544 34545 34546 34547 34548 34549 34550 34551 34552 34553 34554 34555 34556 34557 34558 34559 34560 34561 34562 34563 34564 34565 34566 34567 34568 34569 34570 34571 34572 34573 34574 34575 34576 34577 34578 34579 34580 34581 34582 34583 34584 34585 34586 34587 34588 34589 34590 34591 34592 34593 34594 34595 34596 34597 34598 34599 34600 34601 34602 34603 34604 34605 34606 34607 34608 34609 34610 34611 34612 34613 34614 34615 34616 34617 34618 34619 34620 34621 34622 34623 34624 34625 34626 34627 34628 34629 34630 34631 34632 34633 34634 34635 34636 34637 34638 34639 34640 34641 34642 34643 34644 34645 34646 34647 34648 34649 34650 34651 34652 34653 34654 34655 34656 34657 34658 34659 34660 34661 34662 34663 34664 34665 34666 34667 34668 34669 34670 34671 34672 34673 34674 34675 34676 34677 34678 34679 34680 34681 34682 34683 34684 34685 34686 34687 34688 34689 34690 34691 34692 34693 34694 34695 34696 34697 34698 34699 34700 34701 34702 34703 34704 34705 34706 34707 34708 34709 34710 34711 34712 34713 34714 34715 34716 34717 34718 34719 34720 34721 34722 34723 34724 34725 34726 34727 34728 34729 34730 34731 34732 34733 34734 34735 34736 34737 34738 34739 34740 34741 34742 34743 34744 34745 34746 34747 34748 34749 34750 34751 34752 34753 34754 34755 34756 34757 34758 34759 34760 34761 34762 34763 34764 34765 34766 34767 34768 34769 34770 34771 34772 34773 34774 34775 34776 34777 34778 34779 34780 34781 34782 34783 34784 34785 34786 34787 34788 34789 34790 34791 34792 34793 34794 34795 34796 34797 34798 34799 34800 34801 34802 34803 34804 34805 34806 34807 34808 34809 34810 34811 34812 34813 34814 34815 34816 34817 34818 34819 34820 34821 34822 34823 34824 34825 34826 34827 34828 34829 34830 34831 34832 34833 34834 34835 34836 34837 34838 34839 34840 34841 34842 34843 34844 34845 34846 34847 34848 34849 34850 34851 34852 34853 34854 34855 34856 34857 34858 34859 34860 34861 34862 34863 34864 34865 34866 34867 34868 34869 34870 34871 34872 34873 34874 34875 34876 34877 34878 34879 34880 34881 34882 34883 34884 34885 34886 34887 34888 34889 34890 34891 34892 34893 34894 34895 34896 34897 34898 34899 34900 34901 34902 34903 34904 34905 34906 34907 34908 34909 34910 34911 34912 34913 34914 34915 34916 34917 34918 34919 34920 34921 34922 34923 34924 34925 34926 34927 34928 34929 34930 34931 34932 34933 34934 34935 34936 34937 34938 34939 34940 34941 34942 34943 34944 34945 34946 34947 34948 34949 34950 34951 34952 34953 34954 34955 34956 34957 34958 34959 34960 34961 34962 34963 34964 34965 34966 34967 34968 34969 34970 34971 34972 34973 34974 34975 34976 34977 34978 34979 34980 34981 34982 34983 34984 34985 34986 34987 34988 34989 34990 34991 34992 34993 34994 34995 34996 34997 34998 34999 35000 35001 35002 35003 35004 35005 35006 35007 35008 35009 35010 35011 35012 35013 35014 35015 35016 35017 35018 35019 35020 35021 35022 35023 35024 35025 35026 35027 35028 35029 35030 35031 35032 35033 35034 35035 35036 35037 35038 35039 35040 35041 35042 35043 35044 35045 35046 35047 35048 35049 35050 35051 35052 35053 35054 35055 35056 35057 35058 35059 35060 35061 35062 35063 35064 35065 35066 35067 35068 35069 35070 35071 35072 35073 35074 35075 35076 35077 35078 35079 35080 35081 35082 35083 35084 35085 35086 35087 35088 35089 35090 35091 35092 35093 35094 35095 35096 35097 35098 35099 35100 35101 35102 35103 35104 35105 35106 35107 35108 35109 35110 35111 35112 35113 35114 35115 35116 35117 35118 35119 35120 35121 35122 35123 35124 35125 35126 35127 35128 35129 35130 35131 35132 35133 35134 35135 35136 35137 35138 35139 35140 35141 35142 35143 35144 35145 35146 35147 35148 35149 35150 35151 35152 35153 35154 35155 35156 35157 35158 35159 35160 35161 35162 35163 35164 35165 35166 35167 35168 35169 35170 35171 35172 35173 35174 35175 35176 35177 35178 35179 35180 35181 35182 35183 35184 35185 35186 35187 35188 35189 35190 35191 35192 35193 35194 35195 35196 35197 35198 35199 35200 35201 35202 35203 35204 35205 35206 35207 35208 35209 35210 35211 35212 35213 35214 35215 35216 35217 35218 35219 35220 35221 35222 35223 35224 35225 35226 35227 35228 35229 35230 35231 35232 35233 35234 35235 35236 35237 35238 35239 35240 35241 35242 35243 35244 35245 35246 35247 35248 35249 35250 35251 35252 35253 35254 35255 35256 35257 35258 35259 35260 35261 35262 35263 35264 35265 35266 35267 35268 35269 35270 35271 35272 35273 35274 35275 35276 35277 35278 35279 35280 35281 35282 35283 35284 35285 35286 35287 35288 35289 35290 35291 35292 35293 35294 35295 35296 35297 35298 35299 35300 35301 35302 35303 35304 35305 35306 35307 35308 35309 35310 35311 35312 35313 35314 35315 35316 35317 35318 35319 35320 35321 35322 35323 35324 35325 35326 35327 35328 35329 35330 35331 35332 35333 35334 35335 35336 35337 35338 35339 35340 35341 35342 35343 35344 35345 35346 35347 35348 35349 35350 35351 35352 35353 35354 35355 35356 35357 35358 35359 35360 35361 35362 35363 35364 35365 35366 35367 35368 35369 35370 35371 35372 35373 35374 35375 35376 35377 35378 35379 35380 35381 35382 35383 35384 35385 35386 35387 35388 35389 35390 35391 35392 35393 35394 35395 35396 35397 35398 35399 35400 35401 35402 35403 35404 35405 35406 35407 35408 35409 35410 35411 35412 35413 35414 35415 35416 35417 35418 35419 35420 35421 35422 35423 35424 35425 35426 35427 35428 35429 35430 35431 35432 35433 35434 35435 35436 35437 35438 35439 35440 35441 35442 35443 35444 35445 35446 35447 35448 35449 35450 35451 35452 35453 35454 35455 35456 35457 35458 35459 35460 35461 35462 35463 35464 35465 35466 35467 35468 35469 35470 35471 35472 35473 35474 35475 35476 35477 35478 35479 35480 35481 35482 35483 35484 35485 35486 35487 35488 35489 35490 35491 35492 35493 35494 35495 35496 35497 35498 35499 35500 35501 35502 35503 35504 35505 35506 35507 35508 35509 35510 35511 35512 35513 35514 35515 35516 35517 35518 35519 35520 35521 35522 35523 35524 35525 35526 35527 35528 35529 35530 35531 35532 35533 35534 35535 35536 35537 35538 35539 35540 35541 35542 35543 35544 35545 35546 35547 35548 35549 35550 35551 35552 35553 35554 35555 35556 35557 35558 35559 35560 35561 35562 35563 35564 35565 35566 35567 35568 35569 35570 35571 35572 35573 35574 35575 35576 35577 35578 35579 35580 35581 35582 35583 35584 35585 35586 35587 35588 35589 35590 35591 35592 35593 35594 35595 35596 35597 35598 35599 35600 35601 35602 35603 35604 35605 35606 35607 35608 35609 35610 35611 35612 35613 35614 35615 35616 35617 35618 35619 35620 35621 35622 35623 35624 35625 35626 35627 35628 35629 35630 35631 35632 35633 35634 35635 35636 35637 35638 35639 35640 35641 35642 35643 35644 35645 35646 35647 35648 35649 35650 35651 35652 35653 35654 35655 35656 35657 35658 35659 35660 35661 35662 35663 35664 35665 35666 35667 35668 35669 35670 35671 35672 35673 35674 35675 35676 35677 35678 35679 35680 35681 35682 35683 35684 35685 35686 35687 35688 35689 35690 35691 35692 35693 35694 35695 35696 35697 35698 35699 35700 35701 35702 35703 35704 35705 35706 35707 35708 35709 35710 35711 35712 35713 35714 35715 35716 35717 35718 35719 35720 35721 35722 35723 35724 35725 35726 35727 35728 35729 35730 35731 35732 35733 35734 35735 35736 35737 35738 35739 35740 35741 35742 35743 35744 35745 35746 35747 35748 35749 35750 35751 35752 35753 35754 35755 35756 35757 35758 35759 35760 35761 35762 35763 35764 35765 35766 35767 35768 35769 35770 35771 35772 35773 35774 35775 35776 35777 35778 35779 35780 35781 35782 35783 35784 35785 35786 35787 35788 35789 35790 35791 35792 35793 35794 35795 35796 35797 35798 35799 35800 35801 35802 35803 35804 35805 35806 35807 35808 35809 35810 35811 35812 35813 35814 35815 35816 35817 35818 35819 35820 35821 35822 35823 35824 35825 35826 35827 35828 35829 35830 35831 35832 35833 35834 35835 35836 35837 35838 35839 35840 35841 35842 35843 35844 35845 35846 35847 35848 35849 35850 35851 35852 35853 35854 35855 35856 35857 35858 35859 35860 35861 35862 35863 35864 35865 35866 35867 35868 35869 35870 35871 35872 35873 35874 35875 35876 35877 35878 35879 35880 35881 35882 35883 35884 35885 35886 35887 35888 35889 35890 35891 35892 35893 35894 35895 35896 35897 35898 35899 35900 35901 35902 35903 35904 35905 35906 35907 35908 35909 35910 35911 35912 35913 35914 35915 35916 35917 35918 35919 35920 35921 35922 35923 35924 35925 35926 35927 35928 35929 35930 35931 35932 35933 35934 35935 35936 35937 35938 35939 35940 35941 35942 35943 35944 35945 35946 35947 35948 35949 35950 35951 35952 35953 35954 35955 35956 35957 35958 35959 35960 35961 35962 35963 35964 35965 35966 35967 35968 35969 35970 35971 35972 35973 35974 35975 35976 35977 35978 35979 35980 35981 35982 35983 35984 35985 35986 35987 35988 35989 35990 35991 35992 35993 35994 35995 35996 35997 35998 35999 36000 36001 36002 36003 36004 36005 36006 36007 36008 36009 36010 36011 36012 36013 36014 36015 36016 36017 36018 36019 36020 36021 36022 36023 36024 36025 36026 36027 36028 36029 36030 36031 36032 36033 36034 36035 36036 36037 36038 36039 36040 36041 36042 36043 36044 36045 36046 36047 36048 36049 36050 36051 36052 36053 36054 36055 36056 36057 36058 36059 36060 36061 36062 36063 36064 36065 36066 36067 36068 36069 36070 36071 36072 36073 36074 36075 36076 36077 36078 36079 36080 36081 36082 36083 36084 36085 36086 36087 36088 36089 36090 36091 36092 36093 36094 36095 36096 36097 36098 36099 36100 36101 36102 36103 36104 36105 36106 36107 36108 36109 36110 36111 36112 36113 36114 36115 36116 36117 36118 36119 36120 36121 36122 36123 36124 36125 36126 36127 36128 36129 36130 36131 36132 36133 36134 36135 36136 36137 36138 36139 36140 36141 36142 36143 36144 36145 36146 36147 36148 36149 36150 36151 36152 36153 36154 36155 36156 36157 36158 36159 36160 36161 36162 36163 36164 36165 36166 36167 36168 36169 36170 36171 36172 36173 36174 36175 36176 36177 36178 36179 36180 36181 36182 36183 36184 36185 36186 36187 36188 36189 36190 36191 36192 36193 36194 36195 36196 36197 36198 36199 36200 36201 36202 36203 36204 36205 36206 36207 36208 36209 36210 36211 36212 36213 36214 36215 36216 36217 36218 36219 36220 36221 36222 36223 36224 36225 36226 36227 36228 36229 36230 36231 36232 36233 36234 36235 36236 36237 36238 36239 36240 36241 36242 36243 36244 36245 36246 36247 36248 36249 36250 36251 36252 36253 36254 36255 36256 36257 36258 36259 36260 36261 36262 36263 36264 36265 36266 36267 36268 36269 36270 36271 36272 36273 36274 36275 36276 36277 36278 36279 36280 36281 36282 36283 36284 36285 36286 36287 36288 36289 36290 36291 36292 36293 36294 36295 36296 36297 36298 36299 36300 36301 36302 36303 36304 36305 36306 36307 36308 36309 36310 36311 36312 36313 36314 36315 36316 36317 36318 36319 36320 36321 36322 36323 36324 36325 36326 36327 36328 36329 36330 36331 36332 36333 36334 36335 36336 36337 36338 36339 36340 36341 36342 36343 36344 36345 36346 36347 36348 36349 36350 36351 36352 36353 36354 36355 36356 36357 36358 36359 36360 36361 36362 36363 36364 36365 36366 36367 36368 36369 36370 36371 36372 36373 36374 36375 36376 36377 36378 36379 36380 36381 36382 36383 36384 36385 36386 36387 36388 36389 36390 36391 36392 36393 36394 36395 36396 36397 36398 36399 36400 36401 36402 36403 36404 36405 36406 36407 36408 36409 36410 36411 36412 36413 36414 36415 36416 36417 36418 36419 36420 36421 36422 36423 36424 36425 36426 36427 36428 36429 36430 36431 36432 36433 36434 36435 36436 36437 36438 36439 36440 36441 36442 36443 36444 36445 36446 36447 36448 36449 36450 36451 36452 36453 36454 36455 36456 36457 36458 36459 36460 36461 36462 36463 36464 36465 36466 36467 36468 36469 36470 36471 36472 36473 36474 36475 36476 36477 36478 36479 36480 36481 36482 36483 36484 36485 36486 36487 36488 36489 36490 36491 36492 36493 36494 36495 36496 36497 36498 36499 36500 36501 36502 36503 36504 36505 36506 36507 36508 36509 36510 36511 36512 36513 36514 36515 36516 36517 36518 36519 36520 36521 36522 36523 36524 36525 36526 36527 36528 36529 36530 36531 36532 36533 36534 36535 36536 36537 36538 36539 36540 36541 36542 36543 36544 36545 36546 36547 36548 36549 36550 36551 36552 36553 36554 36555 36556 36557 36558 36559 36560 36561 36562 36563 36564 36565 36566 36567 36568 36569 36570 36571 36572 36573 36574 36575 36576 36577 36578 36579 36580 36581 36582 36583 36584 36585 36586 36587 36588 36589 36590 36591 36592 36593 36594 36595 36596 36597 36598 36599 36600 36601 36602 36603 36604 36605 36606 36607 36608 36609 36610 36611 36612 36613 36614 36615 36616 36617 36618 36619 36620 36621 36622 36623 36624 36625 36626 36627 36628 36629 36630 36631 36632 36633 36634 36635 36636 36637 36638 36639 36640 36641 36642 36643 36644 36645 36646 36647 36648 36649 36650 36651 36652 36653 36654 36655 36656 36657 36658 36659 36660 36661 36662 36663 36664 36665 36666 36667 36668 36669 36670 36671 36672 36673 36674 36675 36676 36677 36678 36679 36680 36681 36682 36683 36684 36685 36686 36687 36688 36689 36690 36691 36692 36693 36694 36695 36696 36697 36698 36699 36700 36701 36702 36703 36704 36705 36706 36707 36708 36709 36710 36711 36712 36713 36714 36715 36716 36717 36718 36719 36720 36721 36722 36723 36724 36725 36726 36727 36728 36729 36730 36731 36732 36733 36734 36735 36736 36737 36738 36739 36740 36741 36742 36743 36744 36745 36746 36747 36748 36749 36750 36751 36752 36753 36754 36755 36756 36757 36758 36759 36760 36761 36762 36763 36764 36765 36766 36767 36768 36769 36770 36771 36772 36773 36774 36775 36776 36777 36778 36779 36780 36781 36782 36783 36784 36785 36786 36787 36788 36789 36790 36791 36792 36793 36794 36795 36796 36797 36798 36799 36800 36801 36802 36803 36804 36805 36806 36807 36808 36809 36810 36811 36812 36813 36814 36815 36816 36817 36818 36819 36820 36821 36822 36823 36824 36825 36826 36827 36828 36829 36830 36831 36832 36833 36834 36835 36836 36837 36838 36839 36840 36841 36842 36843 36844 36845 36846 36847 36848 36849 36850 36851 36852 36853 36854 36855 36856 36857 36858 36859 36860 36861 36862 36863 36864 36865 36866 36867 36868 36869 36870 36871 36872 36873 36874 36875 36876 36877 36878 36879 36880 36881 36882 36883 36884 36885 36886 36887 36888 36889 36890 36891 36892 36893 36894 36895 36896 36897 36898 36899 36900 36901 36902 36903 36904 36905 36906 36907 36908 36909 36910 36911 36912 36913 36914 36915 36916 36917 36918 36919 36920 36921 36922 36923 36924 36925 36926 36927 36928 36929 36930 36931 36932 36933 36934 36935 36936 36937 36938 36939 36940 36941 36942 36943 36944 36945 36946 36947 36948 36949 36950 36951 36952 36953 36954 36955 36956 36957 36958 36959 36960 36961 36962 36963 36964 36965 36966 36967 36968 36969 36970 36971 36972 36973 36974 36975 36976 36977 36978 36979 36980 36981 36982 36983 36984 36985 36986 36987 36988 36989 36990 36991 36992 36993 36994 36995 36996 36997 36998 36999 37000 37001 37002 37003 37004 37005 37006 37007 37008 37009 37010 37011 37012 37013 37014 37015 37016 37017 37018 37019 37020 37021 37022 37023 37024 37025 37026 37027 37028 37029 37030 37031 37032 37033 37034 37035 37036 37037 37038 37039 37040 37041 37042 37043 37044 37045 37046 37047 37048 37049 37050 37051 37052 37053 37054 37055 37056 37057 37058 37059 37060 37061 37062 37063 37064 37065 37066 37067 37068 37069 37070 37071 37072 37073 37074 37075 37076 37077 37078 37079 37080 37081 37082 37083 37084 37085 37086 37087 37088 37089 37090 37091 37092 37093 37094 37095 37096 37097 37098 37099 37100 37101 37102 37103 37104 37105 37106 37107 37108 37109 37110 37111 37112 37113 37114 37115 37116 37117 37118 37119 37120 37121 37122 37123 37124 37125 37126 37127 37128 37129 37130 37131 37132 37133 37134 37135 37136 37137 37138 37139 37140 37141 37142 37143 37144 37145 37146 37147 37148 37149 37150 37151 37152 37153 37154 37155 37156 37157 37158 37159 37160 37161 37162 37163 37164 37165 37166 37167 37168 37169 37170 37171 37172 37173 37174 37175 37176 37177 37178 37179 37180 37181 37182 37183 37184 37185 37186 37187 37188 37189 37190 37191 37192 37193 37194 37195 37196 37197 37198 37199 37200 37201 37202 37203 37204 37205 37206 37207 37208 37209 37210 37211 37212 37213 37214 37215 37216 37217 37218 37219 37220 37221 37222 37223 37224 37225 37226 37227 37228 37229 37230 37231 37232 37233 37234 37235 37236 37237 37238 37239 37240 37241 37242 37243 37244 37245 37246 37247 37248 37249 37250 37251 37252 37253 37254 37255 37256 37257 37258 37259 37260 37261 37262 37263 37264 37265 37266 37267 37268 37269 37270 37271 37272 37273 37274 37275 37276 37277 37278 37279 37280 37281 37282 37283 37284 37285 37286 37287 37288 37289 37290 37291 37292 37293 37294 37295 37296 37297 37298 37299 37300 37301 37302 37303 37304 37305 37306 37307 37308 37309 37310 37311 37312 37313 37314 37315 37316 37317 37318 37319 37320 37321 37322 37323 37324 37325 37326 37327 37328 37329 37330 37331 37332 37333 37334 37335 37336 37337 37338 37339 37340 37341 37342 37343 37344 37345 37346 37347 37348 37349 37350 37351 37352 37353 37354 37355 37356 37357 37358 37359 37360 37361 37362 37363 37364 37365 37366 37367 37368 37369 37370 37371 37372 37373 37374 37375 37376 37377 37378 37379 37380 37381 37382 37383 37384 37385 37386 37387 37388 37389 37390 37391 37392 37393 37394 37395 37396 37397 37398 37399 37400 37401 37402 37403 37404 37405 37406 37407 37408 37409 37410 37411 37412 37413 37414 37415 37416 37417 37418 37419 37420 37421 37422 37423 37424 37425 37426 37427 37428 37429 37430 37431 37432 37433 37434 37435 37436 37437 37438 37439 37440 37441 37442 37443 37444 37445 37446 37447 37448 37449 37450 37451 37452 37453 37454 37455 37456 37457 37458 37459 37460 37461 37462 37463 37464 37465 37466 37467 37468 37469 37470 37471 37472 37473 37474 37475 37476 37477 37478 37479 37480 37481 37482 37483 37484 37485 37486 37487 37488 37489 37490 37491 37492 37493 37494 37495 37496 37497 37498 37499 37500 37501 37502 37503 37504 37505 37506 37507 37508 37509 37510 37511 37512 37513 37514 37515 37516 37517 37518 37519 37520 37521 37522 37523 37524 37525 37526 37527 37528 37529 37530 37531 37532 37533 37534 37535 37536 37537 37538 37539 37540 37541 37542 37543 37544 37545 37546 37547 37548 37549 37550 37551 37552 37553 37554 37555 37556 37557 37558 37559 37560 37561 37562 37563 37564 37565 37566 37567 37568 37569 37570 37571 37572 37573 37574 37575 37576 37577 37578 37579 37580 37581 37582 37583 37584 37585 37586 37587 37588 37589 37590 37591 37592 37593 37594 37595 37596 37597 37598 37599 37600 37601 37602 37603 37604 37605 37606 37607 37608 37609 37610 37611 37612 37613 37614 37615 37616 37617 37618 37619 37620 37621 37622 37623 37624 37625 37626 37627 37628 37629 37630 37631 37632 37633 37634 37635 37636 37637 37638 37639 37640 37641 37642 37643 37644 37645 37646 37647 37648 37649 37650 37651 37652 37653 37654 37655 37656 37657 37658 37659 37660 37661 37662 37663 37664 37665 37666 37667 37668 37669 37670 37671 37672 37673 37674 37675 37676 37677 37678 37679 37680 37681 37682 37683 37684 37685 37686 37687 37688 37689 37690 37691 37692 37693 37694 37695 37696 37697 37698 37699 37700 37701 37702 37703 37704 37705 37706 37707 37708 37709 37710 37711 37712 37713 37714 37715 37716 37717 37718 37719 37720 37721 37722 37723 37724 37725 37726 37727 37728 37729 37730 37731 37732 37733 37734 37735 37736 37737 37738 37739 37740 37741 37742 37743 37744 37745 37746 37747 37748 37749 37750 37751 37752 37753 37754 37755 37756 37757 37758 37759 37760 37761 37762 37763 37764 37765 37766 37767 37768 37769 37770 37771 37772 37773 37774 37775 37776 37777 37778 37779 37780 37781 37782 37783 37784 37785 37786 37787 37788 37789 37790 37791 37792 37793 37794 37795 37796 37797 37798 37799 37800 37801 37802 37803 37804 37805 37806 37807 37808 37809 37810 37811 37812 37813 37814 37815 37816 37817 37818 37819 37820 37821 37822 37823 37824 37825 37826 37827 37828 37829 37830 37831 37832 37833 37834 37835 37836 37837 37838 37839 37840 37841 37842 37843 37844 37845 37846 37847 37848 37849 37850 37851 37852 37853 37854 37855 37856 37857 37858 37859 37860 37861 37862 37863 37864 37865 37866 37867 37868 37869 37870 37871 37872 37873 37874 37875 37876 37877 37878 37879 37880 37881 37882 37883 37884 37885 37886 37887 37888 37889 37890 37891 37892 37893 37894 37895 37896 37897 37898 37899 37900 37901 37902 37903 37904 37905 37906 37907 37908 37909 37910 37911 37912 37913 37914 37915 37916 37917 37918 37919 37920 37921 37922 37923 37924 37925 37926 37927 37928 37929 37930 37931 37932 37933 37934 37935 37936 37937 37938 37939 37940 37941 37942 37943 37944 37945 37946 37947 37948 37949 37950 37951 37952 37953 37954 37955 37956 37957 37958 37959 37960 37961 37962 37963 37964 37965 37966 37967 37968 37969 37970 37971 37972 37973 37974 37975 37976 37977 37978 37979 37980 37981 37982 37983 37984 37985 37986 37987 37988 37989 37990 37991 37992 37993 37994 37995 37996 37997 37998 37999 38000 38001 38002 38003 38004 38005 38006 38007 38008 38009 38010 38011 38012 38013 38014 38015 38016 38017 38018 38019 38020 38021 38022 38023 38024 38025 38026 38027 38028 38029 38030 38031 38032 38033 38034 38035 38036 38037 38038 38039 38040 38041 38042 38043 38044 38045 38046 38047 38048 38049 38050 38051 38052 38053 38054 38055 38056 38057 38058 38059 38060 38061 38062 38063 38064 38065 38066 38067 38068 38069 38070 38071 38072 38073 38074 38075 38076 38077 38078 38079 38080 38081 38082 38083 38084 38085 38086 38087 38088 38089 38090 38091 38092 38093 38094 38095 38096 38097 38098 38099 38100 38101 38102 38103 38104 38105 38106 38107 38108 38109 38110 38111 38112 38113 38114 38115 38116 38117 38118 38119 38120 38121 38122 38123 38124 38125 38126 38127 38128 38129 38130 38131 38132 38133 38134 38135 38136 38137 38138 38139 38140 38141 38142 38143 38144 38145 38146 38147 38148 38149 38150 38151 38152 38153 38154 38155 38156 38157 38158
|
<chapter label="rdfandsparql.xml" id="rdfandsparql"><title>RDF Data Access and Data Management</title>
<abstract>
<para>
Starting with version 4.5, Virtuoso provides built-in support for SPARQL, the standard query language for RDF and the semantic web.
Adoption of SPARQL with Virtuoso is effortless, as any existing SQL client applications and stored procedures can take advantage of SPARQL simply by using it in the place of or inside SQL queries. Additionally, Virtuoso offers the standard SPARQL protocol to HTTP clients.
From version 5.0.7, Virtuoso can be used as the RDF store/query processor of the Jena and Sesame RDF frameworks.
</para>
<para>
This chapter discusses Virtuoso's RDF triple storage and query capabilities.
This discusses storing RDF data as well as mapping existing relational data into RDF for SPARQL access. Numerous SPARQL language extensions and standard compliance are covered.
</para>
<para>In this chapter SPARQL and SPASQL are used as siblings.</para>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="virtodbcsparql">Virtuoso ODBC RDF extensions for SPASQL</link></listitem>
</itemizedlist>
</tip>
</abstract>
<sect1 id="rdfdatarepresentation"><title>Data Representation</title>
<para>This section covers how Virtuoso stores RDF triples. The IRI_ID built-in data type is introduced, along with the default table structures used for triple persistency.
These details are mostly hidden from users of RDF, thus this section is not necessary reading for typical use of Virtuoso with RDF.
</para>
<sect2 id="rdfiriidtype"><title>IRI_ID Type</title>
<para>The central notion of RDF is the IRI, or URI, which serves as the globally unique label of named nodes. The subject and predicate of a triple are always IRI's and the object may be an IRI or any other XML Schema scalar data type. In any case, an IRI is always distinct from any instance of any other data type.</para>
<para>Virtuoso supports a native IRI_ID data type, internally an unsigned 32 bit or unsigned 64 bit integer value.
Small databases can use 32 bit values but if database becomes big then the administrator should execute
<function>DB.DBA.RDF_64BIT_UPGRADE</function>() procedure that will switch to 64-bit values. This procedure takes time so if it is known in advance that the database will grow to billions of nodes then it could be convenient to upgrade it while it is empty.
An IRI_ID is never equal to any instance of any other type.</para>
<para>Thus, the object column of a table storing triples can be declared as ANY and IRI values will be distinguishable without recourse to any extra flag and IRI's will naturally occupy their own contiguous segment in the ANY type collation sequence. Indices can be defined over such columns. An IRI_ID is never automatically cast into any other type nor any other type into IRI_ID.</para>
<para>The functions iri_id_num (in i IRI_ID) and iri_id_from_num (in n INT) convert between signed integers and IRI_ID's. The function isiri_id (in i any) returns nonzero if the argument is of type IRI_ID, zero otherwise.</para>
<para>The syntax for an IRI_ID literal is <emphasis>#i<NNN></emphasis> or <emphasis>#ib<NNN></emphasis>, where <emphasis><NNN></emphasis> is up to 20 decimal digits. <emphasis>#i12345</emphasis> is equal to <emphasis>iri_id_from_num (12345)</emphasis> and <emphasis>#ib12345</emphasis> is equal to <emphasis>iri_id_from_num (12345) + min_64bit_bnode_iri_id ()</emphasis>.</para>
<para>When received by a SQL client application, the ODBC driver or
interactive SQL will bind an IRI_ID to a character buffer, producing
the <emphasis>#i<NNN></emphasis> syntax. When passing IRI_ID's from a client, one can pass an
integer and use the iri_id_from_num () function in the statement to
convert server side. A SQL client will normally not be exposed to
IRI_ID's since the SPARQL implementation returns IRI's in their text
form, not as internal id's. These will however be seen if reading the
internal tables directly.</para>
<note><para>Nobody, even DBA, should write directly to internal RDF tables, because some data from that tables are cached in a special way and cache is not automatically updated when content of tables has changed.</para></note>
<para><emphasis>Example</emphasis></para>
<para>The following example demonstrates IRI type usage as Virtuoso PL function parameter:</para>
<programlisting><![CDATA[
SQL>create procedure vs_property_label (in _uri varchar)
{
declare res varchar;
result_names (res);
for (sparql define input:storage "" select distinct ?graph_rvr_fixed where { graph `iri(?:_uri)` { ?qmv virtrdf:qmGraphRange-rvrFixedValue ?graph_rvr_fixed}})
do {
result ("graph_rvr_fixed");
}
}
;
Done. -- 0 msec.
SQL>select vs_property_label('http://www.openlinksw.com/schemas/virtrdf#');
res
VARCHAR
_______________________________________________________________________________
http://demo.openlinksw.com/Northwind
http://demo.openlinksw.com/tpch
http://demo.openlinksw.com/tpcd
http://demo.openlinksw.com/bsbm
http://demo.openlinksw.com/tutorial/Northwind
http://demo.openlinksw.com/thalia
http://demo.openlinksw.com/tutorial_view
http://demo.openlinksw.com/ecrm
http://demo.openlinksw.com/sys
http://demo.openlinksw.com/Doc
http://demo.openlinksw.com/informix/stores_demo
http://demo.openlinksw.com/oraclehr
http://demo.openlinksw.com/db2sample
http://demo.openlinksw.com/ingrestut
http://demo.openlinksw.com/sybasepubs2
http://demo.openlinksw.com/MSPetShop#
http://demo.openlinksw.com/oracle#
http://demo.openlinksw.com/progress/isports
http://demo.openlinksw.com/wpl_v
http://demo.openlinksw.com/mw_v
http://demo.openlinksw.com/drupal_v
0
22 Rows. -- 241 msec.
]]></programlisting>
</sect2>
<sect2 id="rdfboxtype"><title>RDF_BOX Type</title>
<para>While strings, numbers, dates and XML entities are "native" SQL datatypes,
RDF literal with non-default type or language have no exact matches among standard SQL types.
Virtuoso introduces a special data type called "RDF_BOX" in order to handle that cases.
Instance of RDF_BOX consists of data type, language, the content (or beginning characters of a long content)
and a possible reference to DB.DBA.RDF_OBJ table if the object is too long to be held in-line in some table or should be outlined for free-text indexing.</para>
<para>Usually applications do not need to access internals of an RDF boxes. This datatype is used in system tables but almost all SPARQL and RDF operations use standard SQL datatypes for arguments and return values.</para>
</sect2>
<sect2 id="rdfquadtables"><title>RDF_QUAD and other tables</title>
<para>The main tables of the default RDF storage system are:</para>
<programlisting>
create table DB.DBA.RDF_QUAD (
G IRI_ID,
S IRI_ID,
P IRI_ID,
O any,
primary key (G,S,P,O) );
create bitmap index RDF_QUAD_OGPS on DB.DBA.RDF_QUAD (O, G, P, S);
</programlisting>
<para>Each triple (more correctly, each quad) is represented by one row in RDF_QUAD.
The columns represent the graph, subject, predicate and object.
The IRI_ID type columns reference RDF_IRI, which translates the internal id to the external name of the IRI.
The O column is of type ANY.
If the O value is a non-string SQL scalar, such as a number or date or IRI, it is stored in its native binary representation.
If it is a "very short" string (20 characters or less), it is also stored "as is".
Long strings and RDF literal with non-default type or language are stored as RDF_BOX values.
Instance of rdf_box consists of data type, language, the content (or beginning characters of a long content)
and a possible reference to RDF_OBJ if the object is too long to be held in-line in this table or should be outlined for free-text indexing.
</para>
<programlisting>
create table DB.DBA.RDF_PREFIX (
RP_NAME varchar primary key,
RP_ID int not null unique );
create table DB.DBA.RDF_IRI (
RI_NAME varchar primary key,
RI_ID IRI_ID not null unique );
</programlisting>
<para>These two tables store a mapping between internal IRI id's and their external string form.
A memory-resident cache contains recently used IRIs to reduce access to this table.
Function id_to_iri (in id IRI_ID) returns the IRI by its ID.
Function iri_to_id (in iri varchar, in may_create_new_id) returns an IRI_ID for given string;
if the string is not used before as an IRI then either NULL is returned or a new ID is allocated, depending on the second argument.
</para>
<programlisting>
create table DB.DBA.RDF_OBJ (
RO_ID integer primary key,
RO_VAL varchar,
RO_LONG long varchar,
RO_DIGEST any
)
create index RO_VAL on DB.DBA.RDF_OBJ (RO_VAL)
create index RO_DIGEST on DB.DBA.RDF_OBJ (RO_DIGEST)
;
</programlisting>
<para>When an O value of RDF_QUAD is longer than a certain limit or should be free-text indexed, the value is stored in this table.
Depending on the length of the value, it goes into the varchar or the long varchar column.
The RO_ID is contained in rdf_box object that is stored in the O column.
Still, the truncated value of O can be used for determining equality and range matching,
even if < and > of closely matching values need to look at the real string in RDF_OBJ.
When RO_LONG is used to store very long value, RO_VAL contains a simple checksum of the value, to accelerate search for identical values when the table is populated by new values.
</para>
<programlisting>
create table DB.DBA.RDF_DATATYPE (
RDT_IID IRI_ID not null primary key,
RDT_TWOBYTE integer not null unique,
RDT_QNAME varchar );
</programlisting>
<para>The XML Schema data type of a typed string O represented as 2 bytes in the O varchar value. This table maps this into the broader IRI space where the type URI is given an IRI number.</para>
<programlisting>
create table DB.DBA.RDF_LANGUAGE (
RL_ID varchar not null primary key,
RL_TWOBYTE integer not null unique );
</programlisting>
<para>The varchar representation of a O which is a string with language has a two byte field for language. This table maps the short integer language id to the real language name such as 'en', 'en-US' or 'x-any'.</para>
<para><emphasis>Note that unlike datatype names, language names are not URIs.</emphasis></para>
<para>A short integer value can be used in both RDF_DATATYPE and RDF_LANGUAGE tables for two different purposes. E.g. an integer 257 is for 'unspecified datatype' as well as for 'unspecified language'.</para>
</sect2>
<sect2 id="rdfsqlmodes"><title>Short, Long and SQL Values</title>
<para>When processing an O, the SPARQL implementation may have it in one of three internal formats, called "valmodes". The below cases apply for strings:</para>
<para>The short format is the format where an O is stored in RDF_QUAD.</para>
<para>The long value is similar to short one but an rdf_box object, that consists of six fields:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>short integer id of type referencing RDT_TWOBYTE, 257 if the type is not specified,</listitem>
<listitem>the string as inlined in O or as stored in RO_VAL or RO_LONG,</listitem>
<listitem>the RO_ID if the string is from RDF_OBJ (otherwise zero),</listitem>
<listitem>the short integer id of language referencing RL_TWOBYTE, 257 if the language is not specified,</listitem>
<listitem>flag whether the stored string value is complete or it is only the beginning that is inlined in O.</listitem>
</itemizedlist>
<para>The SQL value is the string as a narrow string representing the UTF8 encoding of the value, stripped of data type and language tag.</para>
<para>The SQL form of an IRI is the string. The long and short forms are the IRI_ID referencing RU_IRI_ID of RDF_URL.</para>
<para>For all non-string, non-IRI types, the short, long and SQL values are the same SQL scalar of the appropriate native SQL type. A SQL host variable meant to receive an O should be of the ANY type.</para>
<para>The SPARQL implementation will usually translate results to the SQL format before returning them.
Internally, it uses the shortest possible form suited to the operation. For equalities and joining, the
short form is always good. For range comparisons, the long form is needed etc. For arithmetic,
all three forms will do since the arguments are expected to be numbers which are stored as their binary
selves in O, thus the O column unaltered and uncast will do as an argument of arithmetic or numeric
comparison with, say, SQL literal constants.</para>
</sect2>
<sect2 id="rdfsqlsparqlresolve"><title>Programatically resolving DB.DBA.RDF_QUAD.O to SQL</title>
<para>This section describes how to resolve programatically the internal representation of DB.DBA.RDF_QUAD.O to its SQL value.</para>
<para>When operating over RDF_QUAD table directly, in order to transform all values obtained from column
O to the explicit SQL type in a programmatic way, should be used the following hints depending on the case:
</para>
<itemizedlist mark="bullet">
<listitem>The SQL value can be extracted as <emphasis>__ro2sq(O)</emphasis>.</listitem>
<listitem>The datatype can be extracted as <emphasis>DB.DBA.RDF_DATATYPE_OF_OBJ (O)</emphasis> if IRI_ID of the type is enough or <emphasis>__ro2sq ( DB.DBA.RDF_DATATYPE_OF_OBJ(O))</emphasis></listitem>
<listitem>The language can be extracted as <emphasis>DB.DBA.RDF_LANGUAGE_OF_OBJ (O)</emphasis>.</listitem>
</itemizedlist>
<para>It could be helpful to be created an RDF View for a custom table with formats rdfdf:default or rdfdf:default-nullable
for columns similar to O, and let SPARQL perform the rest.</para>
<para>To track SPARQL, use the following functions:</para>
<programlisting><![CDATA[
select sparql_to_sql_text ('query text here without a leading SPARQL keyword and trailing semicolon')
]]></programlisting>
<para>or</para>
<programlisting><![CDATA[
string_to_file ('filename.sql', sparql_to_sql_text ('query text'), -2);
]]></programlisting>
<para>So for example to track the following SPARQL query:</para>
<programlisting><![CDATA[
SPARQL define input:storage ""
select distinct ?graph_rvr_fixed
from <http://www.openlinksw.com/schemas/virtrdf#>
where { ?qmv virtrdf:qmGraphRange-rvrFixedValue ?graph_rvr_fixed }
]]></programlisting>
<para>execute</para>
<programlisting><![CDATA[
SQL>select sparql_to_sql_text('define input:storage "" select distinct ?graph_rvr_fixed from <http://www.openlinksw.com/schemas/virtrdf#> where { ?qmv virtrdf:qmGraphRange-rvrFixedValue ?graph_rvr_fixed }');
callret
VARCHAR
_______________________________________________________________________________
SELECT __ro2sq ("s-1-0_rbc"."graph_rvr_fixed") AS "graph_rvr_fixed" FROM (SELECT DISTINCT __rdf_sqlval_of_obj ( /*retval[*/ "s-1-1-t0"."O" /* graph_
rvr_fixed */ /*]retval*/ ) AS /*tmpl*/ "graph_rvr_fixed"
FROM DB.DBA.RDF_QUAD AS "s-1-1-t0"
WHERE /* field equal to URI ref */
"s-1-1-t0"."G" = __i2idn ( /* UNAME as sqlval */ __box_flags_tweak ( 'http://www.openlinksw.com/schemas/virtrdf#' , 1))
AND /* field equal to URI ref */
"s-1-1-t0"."P" = __i2idn ( /* UNAME as sqlval */ __box_flags_tweak ( 'http://www.openlinksw.com/schemas/virtrdf#qmGraphRange-rvrFixedValue' ,
1))
OPTION (QUIETCAST)) AS "s-1-0_rbc"
1 Rows. -- 321 msec.
]]></programlisting>
<para>or</para>
<programlisting><![CDATA[
SQL>string_to_file ('mytest.sql', sparql_to_sql_text ('define input:storage "" select distinct ?graph_rvr_fixed from <http://www.openlinksw.com/schemas/virtrdf#> where { ?qmv virtrdf:qmGraphRange-rvrFixedValue ?graph_rvr_fixed }'), -2);
]]></programlisting>
<para>As result will be created file with the given name, i.e. mytest.sql and its content should be:</para>
<programlisting><![CDATA[
SELECT __ro2sq ("s-1-0_rbc"."graph_rvr_fixed") AS "graph_rvr_fixed" FROM (SELECT DISTINCT __rdf_sqlval_of_obj ( /*retval[*/ "s-1-1-t0"."O" /* graph_rvr_fixed */ /*]retval*/ ) AS /*tmpl*/ "graph_rvr_fixed"
FROM DB.DBA.RDF_QUAD AS "s-1-1-t0"
WHERE /* field equal to URI ref */
"s-1-1-t0"."G" = __i2idn ( /* UNAME as sqlval */ __box_flags_tweak ( 'http://www.openlinksw.com/schemas/virtrdf#' , 1))
AND /* field equal to URI ref */
"s-1-1-t0"."P" = __i2idn ( /* UNAME as sqlval */ __box_flags_tweak ( 'http://www.openlinksw.com/schemas/virtrdf#qmGraphRange-rvrFixedValue' , 1))
OPTION (QUIETCAST)) AS "s-1-0_rbc"
]]></programlisting>
</sect2>
<sect2 id="rdfxmlschemacompat"><title>Special Cases and XML Schema Compatibility</title>
<para>We note that since we store numbers as the equivalent SQL binary type, we do not preserve the distinction of byte, boolean etc. These all become integer. If preserving such detail is for some reason important, then storage as a typed string is possible but is not done at present for reasons of compactness and performance.</para>
</sect2>
<sect2 id="rdfquietcast"><title>SQL Compiler Support - QUIETCAST option</title>
<para>The type cast behaviors of SQL and SPARQL are different. SQL will generally signal an error when an automatic cast fails. For example, a string can be compared to a date column if the string can be parsed as a date but otherwise the comparison should signal an error. In SPARQL, such situations are supposed to silently fail. Generally, SPARQL is much more relaxed with respect to data types.</para>
<para>These differences will be specially noticed if actual SQL data is processed with SPARQL via some sort of schema mapping translating references to triples into native tables and columns.</para>
<para>Also, even when dealing with the triple-oriented RDF_QUAD table, there are cases of joining between S and O such that the O can be a heterogeneous set of IRI's and other data whereas the S is always an IRI. The non-IRI to IRI comparison should not give cast errors but should silently fail. Also, in order to keep queries simple and easily optimizable, it should not be necessary to introduce extra predicates for testing if the O is n IRI before comparing with the S.</para>
<para>Due to these considerations, Virtuoso introduces a SQL statement option called QUIETCAST. When given in the OPTION clause of a SELECT, it switches to silent fail mode for automatic type casting.</para>
<para>The syntax is as follows:</para>
<programlisting>
SELECT ...
FROM .... OPTION (QUIETCAST)
</programlisting>
<para>This option is automatically added by the SPARQL to SQL translator. The scope is the enclosing procedure body.</para>
</sect2>
<sect2 id="rdfdynamiclocal"><title>Dynamic Renaming of Local IRI's</title>
<para>
There are cases where it is desirable to have IRI's in RDF storage
that will change to reflect a change of the host name of the containing
store. This is specifically true of DAV resource metadata for local
DAV resources.
Such IRI's must be stored prefixed with <computeroutput>local:</computeroutput>.
</para>
<para>
If a user application makes statements with such a URI, then these statements will be returned with local:
substituted with a prefix taken from the context as described below.
</para>
<para>
When returning IRI's from id's, this prefix is replaced by the Host header of the HTTP request
and if not running with HTTP, with the DefaultHost from URIQA. This behavior is always in effect.
</para>
<para>
When converting strings to IRI id's, the <computeroutput>local:</computeroutput> prefix may or may not be introduced depending on ini file and other context factors.
If <link linkend="VIRTINI">DynamicLocal</link> defined in the [URIQA] section of the Virtuoso INI file is on and the host part of the IRI matches the Host header of the HTTP request in context or the DefaultHost if outside of HTTP context, then this is replaced with local: before looking up the IRI ID. Even if DynamicLocal is not on and the <computeroutput>local:</computeroutput> prefix occurs in the IRI string being translated to id, the translating the IRI_ID back to the IRI name will depend on the context as described above.
</para>
<para>
The effects of DynamicLocal = 1 can be very confusing since many names
can refer to the exact same thing. For example, if the DefaultHost is
dbpedia.org,
<computeroutput>iri_to_id ('http://dbpedia.org/resource/Paris') = iri_to_id ('local:///resource/Paris) </computeroutput>
is true and so is
<computeroutput>'http://dbpedia.org/resource/Paris' = id_to_iri (iri_to_id ('local://resource/Paris'))</computeroutput>
These hold in a SQL client context, i.e. also when connected through RDF frameworks like Jena or Sesame.
When running a SPARQL protocol request, the Host: header influences the behavior, likewise when using web interactive SQL in Conductor.
Also be careful when loading RDF files that may have URI's corresponding to the local host name.
</para>
</sect2>
</sect1>
<sect1 id="rdfsparql"><title>SPARQL</title>
<sect2 id="rdfsparqlimplementationextent"><title>SPARQL Implementation Details</title>
<para>Virtuoso's RDF support includes in-built support for the SPARQL query language. It also includes a number of powerful extensions that cover path traversal and business intelligence features. In addition, there is in-built security based on Virtuoso's support for row level policy-based security, custom authentication, and named graphs.</para>
<para>The current implementation does not support some SPARQL features:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Unicode characters in names are not supported.</listitem>
<listitem>Comments inside SPARQL queries are not supported when the query is inlined in SQL code.</listitem>
</itemizedlist>
<para>On the other hand, Virtuoso implements some extensions to SPARQL:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>SPARUL statements, such as <emphasis>insert</emphasis>, <emphasis>modify</emphasis>, <emphasis>load</emphasis> etc, are supported.</listitem>
<listitem>The SPARQL compiler can be configured using <emphasis>define ...</emphasis> clauses, e.g. <emphasis>define output:valmode "LONG"</emphasis>.</listitem>
<listitem>Expressions are allowed in triple patterns, both in a <emphasis>where</emphasis> clause and in constructor patterns. Such expressions are delimited by backquotes.</listitem>
<listitem>Expressions are allowed in select statement result lists.</listitem>
<listitem>Parameters can be passed to the query from outside, using <emphasis>?:variablename</emphasis> syntax.</listitem>
<listitem>Aggregate functions are supported.</listitem>
<listitem>Subqueries may appear where group patterns are allowed.</listitem>
<listitem>A set of operators has been added to configure the mapping of relational data to RDF (aka RDF Views).</listitem>
</itemizedlist>
<para>The following listing shows the SPARQL grammar expressed in BNF, including all Virtuoso extensions but excluding rules for the syntax of each lexical element.
Rule numbers in square brackets are from W3C normative SPARQL grammar. An asterisk indicates that the rule differs from the W3C grammar due to Virtuoso extensions -
<emphasis>[Virt]</emphasis> means that the rule is Virtuoso-specific,
<emphasis>[DML]</emphasis> indicates a data manipulation language extension from SPARUL.
</para>
<programlisting><![CDATA[
[1]* Query ::= Prolog ( QueryBody | SparulAction* | ( QmStmt ('.' QmStmt)* '.'? ) )
[1] QueryBody ::= SelectQuery | ConstructQuery | DescribeQuery | AskQuery
[2]* Prolog ::= Define* BaseDecl? PrefixDecl*
[Virt] Define ::= 'DEFINE' QNAME (QNAME | Q_IRI_REF | String )
[3] BaseDecl ::= 'BASE' Q_IRI_REF
[4] PrefixDecl ::= 'PREFIX' QNAME_NS Q_IRI_REF
[5]* SelectQuery ::= 'SELECT' 'DISTINCT'? ( ( Retcol ( ','? Retcol )* ) | '*' )
DatasetClause* WhereClause SolutionModifier
[6] ConstructQuery ::= 'CONSTRUCT' ConstructTemplate DatasetClause* WhereClause SolutionModifier
DatasetClause* WhereClause? SolutionModifier
[8] AskQuery ::= 'ASK' DatasetClause* WhereClause
[9] DatasetClause ::= 'FROM' ( DefaultGraphClause | NamedGraphClause )
[10]* DefaultGraphClause ::= SourceSelector SpongeOptionList?
[11]* NamedGraphClause ::= 'NAMED' SourceSelector SpongeOptionList?
[Virt] SpongeOptionList ::= 'OPTION' '(' ( SpongeOption ( ',' SpongeOption )* )? ')'
[Virt] SpongeOption ::= QNAME PrecodeExpn
[Virt] PrecodeExpn ::= Expn (* Only global variables can occur in Expn, local cannot *)
[13] WhereClause ::= 'WHERE'? GroupGraphPattern
[14] SolutionModifier ::= OrderClause?
((LimitClause OffsetClause?) | (OffsetClause LimitClause?))?
[15] OrderClause ::= 'ORDER' 'BY' OrderCondition+
[16]* OrderCondition ::= ( 'ASC' | 'DESC' )?
( FunctionCall | Var | ( '(' Expn ')' ) | ( '[' Expn ']' ) )
[17] LimitClause ::= 'LIMIT' INTEGER
[17] LimitClause ::= 'LIMIT' INTEGER
[18] OffsetClause ::= 'OFFSET' INTEGER
[18] OffsetClause ::= 'OFFSET' INTEGER
[19]* GroupGraphPattern ::= '{' ( GraphPattern | SelectQuery ) '}'
[20] GraphPattern ::= Triples? ( GraphPatternNotTriples '.'? GraphPattern )?
[21]* GraphPatternNotTriples ::=
QuadMapGraphPattern
| OptionalGraphPattern
| GroupOrUnionGraphPattern
| GraphGraphPattern
| Constraint
[22] OptionalGraphPattern ::= 'OPTIONAL' GroupGraphPattern
[Virt] QuadMapGraphPattern ::= 'QUAD' 'MAP' ( IRIref | '*' ) GroupGraphPattern
[23] GraphGraphPattern ::= 'GRAPH' VarOrBlankNodeOrIRIref GroupGraphPattern
[24] GroupOrUnionGraphPattern ::= GroupGraphPattern ( 'UNION' GroupGraphPattern )*
[25]* Constraint ::= 'FILTER' ( ( '(' Expn ')' ) | BuiltInCall | FunctionCall )
[26]* ConstructTemplate ::= '{' ConstructTriples '}'
[27] ConstructTriples ::= ( Triples1 ( '.' ConstructTriples )? )?
[28] Triples ::= Triples1 ( '.' Triples? )?
[29] Triples1 ::= VarOrTerm PropertyListNotEmpty | TriplesNode PropertyList
[30] PropertyList ::= PropertyListNotEmpty?
[31] PropertyListNotEmpty ::= Verb ObjectList ( ';' PropertyList )?
[32]* ObjectList ::= ObjGraphNode ( ',' ObjectList )?
[Virt] ObjGraphNode ::= GraphNode TripleOptions?
[Virt] TripleOptions ::= 'OPTION' '(' TripleOption ( ',' TripleOption )? ')'
[Virt] TripleOption ::= 'INFERENCE' ( QNAME | Q_IRI_REF | SPARQL_STRING )
[33] Verb ::= VarOrBlankNodeOrIRIref | 'a'
[34] TriplesNode ::= Collection | BlankNodePropertyList
[35] BlankNodePropertyList ::= '[' PropertyListNotEmpty ']'
[36] Collection ::= '(' GraphNode* ')'
[37] GraphNode ::= VarOrTerm | TriplesNode
[38] VarOrTerm ::= Var | GraphTerm
[39]* VarOrIRIrefOrBackquoted ::= Var | IRIref | Backquoted
[40]* VarOrBlankNodeOrIRIrefOrBackquoted ::= Var | BlankNode | IRIref | Backquoted
[Virt] Retcol ::= ( Var | ( '(' Expn ')' ) | RetAggCall ) ( 'AS' ( VAR1 | VAR2 ) )?
[Virt] RetAggCall ::= AggName '(', ( '*' | ( 'DISTINCT'? Var ) ) ')'
[Virt] AggName ::= 'COUNT' | 'AVG' | 'MIN' | 'MAX' | 'SUM'
[41]* Var ::= VAR1 | VAR2 | GlobalVar | ( Var ( '+>' | '*>' ) IRIref )
[Virt] GlobalVar ::= QUEST_COLON_PARAMNAME | DOLLAR_COLON_PARAMNAME
| QUEST_COLON_PARAMNUM | DOLLAR_COLON_PARAMNUM
[42]* GraphTerm ::= IRIref | RDFLiteral | ( '-' | '+' )? NumericLiteral
| BooleanLiteral | BlankNode | NIL | Backquoted
[Virt] Backquoted ::= '`' Expn '`'
[43] Expn ::= ConditionalOrExpn
[44] ConditionalOrExpn ::= ConditionalAndExpn ( '||' ConditionalAndExpn )*
[45] ConditionalAndExpn ::= ValueLogical ( '&&' ValueLogical )*
[46] ValueLogical ::= RelationalExpn
[47]* RelationalExpn ::= NumericExpn
( ( ('='|'!='|'<'|'>'|'<='|'>='|'LIKE') NumericExpn )
| ( 'IN' '(' Expns ')' ) )?
[49] AdditiveExpn ::= MultiplicativeExpn ( ('+'|'-') MultiplicativeExpn )*
[50] MultiplicativeExpn ::= UnaryExpn ( ('*'|'/') UnaryExpn )*
[51] UnaryExpn ::= ('!'|'+'|'-')? PrimaryExpn
[58] PrimaryExpn ::=
BracketedExpn | BuiltInCall | IRIrefOrFunction
| RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | Var
[55] IRIrefOrFunction ::= IRIref ArgList?
[52]* BuiltInCall ::=
( 'STR' '(' Expn ')' )
| ( 'IRI' '(' Expn ')' )
| ( 'LANG' '(' Expn ')' )
| ( 'LANGMATCHES' '(' Expn ',' Expn ')' )
| ( 'DATATYPE' '(' Expn ')' )
| ( 'BOUND' '(' Var ')' )
| ( 'sameTERM' '(' Expn ',' Expn ')' )
| ( 'isIRI' '(' Expn ')' )
| ( 'isURI' '(' Expn ')' )
| ( 'isBLANK' '(' Expn ')' )
| ( 'isLITERAL' '(' Expn ')' )
| RegexExpn
[53] RegexExpn ::= 'REGEX' '(' Expn ',' Expn ( ',' Expn )? ')'
[54] FunctionCall ::= IRIref ArgList
[56]* ArgList ::= ( NIL | '(' Expns ')' )
[Virt] Expns ::= Expn ( ',' Expn )*
[59] NumericLiteral ::= INTEGER | DECIMAL | DOUBLE
[60] RDFLiteral ::= String ( LANGTAG | ( '^^' IRIref ) )?
[61] BooleanLiteral ::= 'true' | 'false'
[63] IRIref ::= Q_IRI_REF | QName
[64] QName ::= QNAME | QNAME_NS
[65]* BlankNode ::= BLANK_NODE_LABEL | ( '[' ']' )
[DML] SparulAction ::=
CreateAction | DropAction | LoadAction
| InsertAction | InsertDataAction | DeleteAction | DeleteDataAction
| ModifyAction | ClearAction
[DML]* InsertAction ::=
'INSERT' ( ( 'IN' | 'INTO ) 'GRAPH' ( 'IDENTIFIED' 'BY' )? )? PrecodeExpn
ConstructTemplate ( DatasetClause* WhereClause SolutionModifier )?
[DML]* InsertDataAction ::=
'INSERT' 'DATA' ( ( 'IN' | 'INTO ) 'GRAPH' ( 'IDENTIFIED' 'BY' )? )?
PrecodeExpn ConstructTemplate
[DML]* DeleteAction ::=
'DELETE' ( 'FROM' 'GRAPH' ( 'IDENTIFIED' 'BY' )? )? PrecodeExpn
ConstructTemplate ( DatasetClause* WhereClause SolutionModifier )?
[DML]* DeleteDataAction ::=
'DELETE' 'DATA' ( 'FROM' 'GRAPH' ( 'IDENTIFIED' 'BY' )? )?
PrecodeExpn ConstructTemplate
[DML]* ModifyAction ::=
'MODIFY' ( 'GRAPH' ( 'IDENTIFIED' 'BY' )? PrecodeExpn?
'DELETE' ConstructTemplate 'INSERT' ConstructTemplate
( DatasetClause* WhereClause SolutionModifier )?
[DML]* ClearAction ::= 'CLEAR' ( 'GRAPH' ( 'IDENTIFIED' 'BY' )? PrecodeExpn )?
[DML]* LoadAction ::= 'LOAD' PrecodeExpn
( ( 'IN' | 'INTO' ) 'GRAPH' ( 'IDENTIFIED' 'BY' )? PrecodeExpn )?
[DML]* CreateAction ::= 'CREATE' 'SILENT'? 'GRAPH' ( 'IDENTIFIED' 'BY' )? PrecodeExpn
[DML]* DropAction ::= 'DROP' 'SILENT'? 'GRAPH' ( 'IDENTIFIED' 'BY' )? PrecodeExpn
[Virt] QmStmt ::= QmSimpleStmt | QmCreateStorage | QmAlterStorage
[Virt] QmSimpleStmt ::=
QmCreateIRIClass | QmCreateLiteralClass | QmDropIRIClass | QmDropLiteralClass
| QmCreateIRISubclass | QmDropQuadStorage | QmDropQuadMap
[Virt] QmCreateIRIClass ::= 'CREATE' 'IRI' 'CLASS' QmIRIrefConst
( ( String QmSqlfuncArglist )
| ( 'USING' QmSqlfuncHeader ',' QmSqlfuncHeader ) )
[Virt] QmCreateLiteralClass ::= 'CREATE' 'LITERAL' 'CLASS' QmIRIrefConst
'USING' QmSqlfuncHeader ',' QmSqlfuncHeader QmLiteralClassOptions?
[Virt] QmDropIRIClass ::= 'DROP' 'IRI' 'CLASS' QmIRIrefConst
[Virt] QmDropLiteralClass ::= 'DROP' 'LITERAL' 'CLASS' QmIRIrefConst
[Virt] QmCreateIRISubclass ::= 'IRI' 'CLASS' QmIRIrefConst 'SUBCLASS' 'OF' QmIRIrefConst
[Virt] QmIRIClassOptions ::= 'OPTION' '(' QmIRIClassOption (',' QmIRIClassOption)* ')'
[Virt] QmIRIClassOption ::=
'BIJECTION'
| 'DEREF'
| 'RETURNS' STRING ('UNION' STRING)*
[Virt] QmLiteralClassOptions ::= 'OPTION' '(' QmLiteralClassOption (',' QmLiteralClassOption)* ')'
[Virt] QmLiteralClassOption ::=
( 'DATATYPE' QmIRIrefConst )
| ( 'LANG' STRING )
| ( 'LANG' STRING )
| 'BIJECTION'
| 'DEREF'
| 'RETURNS' STRING ('UNION' STRING)*
[Virt] QmCreateStorage ::= 'CREATE' 'QUAD' 'STORAGE' QmIRIrefConst QmSourceDecl* QmMapTopGroup
[Virt] QmAlterStorage ::= 'ALTER' 'QUAD' 'STORAGE' QmIRIrefConst QmSourceDecl* QmMapTopGroup
[Virt] QmDropStorage ::= 'DROP' 'QUAD' 'STORAGE' QmIRIrefConst
[Virt] QmDropQuadMap ::= 'DROP' 'QUAD' 'MAP' 'GRAPH'? QmIRIrefConst
[Virt] QmDrop ::= 'DROP' 'GRAPH'? QmIRIrefConst
[Virt] QmSourceDecl ::=
( 'FROM' QTABLE 'AS' PLAIN_ID QmTextLiteral* )
| ( 'FROM' PLAIN_ID 'AS' PLAIN_ID QmTextLiteral* )
| QmCondition
[Virt] QmTextLiteral ::= 'TEXT' 'XML'? 'LITERAL' QmSqlCol ( 'OF' QmSqlCol )? QmTextLiteralOptions?
[Virt] QmTextLiteralOptions ::= 'OPTION' '(' QmTextLiteralOption ( ',' QmTextLiteralOption )* ')'
[Virt] QmMapTopGroup ::= '{' QmMapTopOp ( '.' QmMapTopOp )* '.'? '}'
[Virt] QmMapTopOp ::= QmMapOp | QmDropQuadMap | QmDrop
[Virt] QmMapGroup ::= '{' QmMapOp ( '.' QmMapOp )* '.'? '}'
[Virt] QmMapOp ::=
( 'CREATE' QmIRIrefConst 'AS' QmMapIdDef )
| ( 'CREATE' 'GRAPH'? QmIRIrefConst 'USING' 'STORAGE' QmIRIrefConst QmOptions? )
| ( QmNamedField+ QmOptions? QmMapGroup )
| QmTriples1
[Virt] QmMapIdDef ::= QmMapTriple | ( QmNamedField+ QmOptions? QmMapGroup )
[Virt] QmMapTriple ::= QmFieldOrBlank QmVerb QmObjField
[Virt] QmTriples1 ::= QmFieldOrBlank QmProps
[Virt] QmNamedField ::= ('GRAPH'|'SUBJECT'|'PREDICATE'|'OBJECT') QmField
[Virt] QmProps ::= QmProp ( ';' QmProp )?
[Virt] QmProp ::= QmVerb QmObjField ( ',' QmObjField )*
[Virt] QmObjField ::= QmFieldOrBlank QmCondition* QmOptions?
[Virt] QmIdSuffix ::= 'AS' QmIRIrefConst
[Virt] QmVerb ::= QmField | ( '[' ']' ) | 'a'
[Virt] QmFieldOrBlank ::= QmField | ( '[' ']' )
[Virt] QmField ::=
NumericLiteral
| RdfLiteral
| ( QmIRIrefConst ( '(' ( QmSqlCol ( ',' QmSqlCol )* )? ')' )? )
| QmSqlCol
[Virt] QmCondition ::= 'WHERE' ( ( '(' SQLTEXT ')' ) | String )
[Virt] QmOptions ::= 'OPTION' '(' QmOption ( ',' QmOption )* ')'
[Virt] QmOption ::= ( 'SOFT'? 'EXCLUSIVE' ) | ( 'ORDER' INTEGER ) | ( 'USING' PLAIN_ID )
[Virt] QmSqlfuncHeader ::= 'FUNCTION' SQL_QTABLECOLNAME QmSqlfuncArglist 'RETURNS' QmSqltype
[Virt] QmSqlfuncArglist ::= '(' ( QmSqlfuncArg ( ',' QmSqlfuncArg )* )? ')'
[Virt] QmSqlfuncArg ::= ('IN' | QmSqlId) QmSqlId QmSqltype
[Virt] QmSqltype ::= QmSqlId ( 'NOT' 'NULL' )?
[Virt] QmSqlCol ::= QmSqlId | spar_qm_sql_id
[Virt] QmSqlId ::= PLAIN_ID | 'TEXT' | 'XML'
[Virt] QmIRIrefConst ::= IRIref | ( 'IRI' '(' String ')' )
]]></programlisting>
<para><emphasis>Example: Using OFFSET and LIMIT</emphasis></para>
<para>
Virtuoso uses a zero-based index for OFFSET. Thus, in the example below, the query returns
1000 rows starting from, and including, record 9001 of the result set. Note that the
default value of the MaxSortedTopRows parameter in the [Parameters] section of the virtuoso.ini configuration
file defaults to 10000, so in this example its value will need to have been increased beforehand.
</para>
<programlisting><![CDATA[
SQL>SELECT ?name
ORDER BY ?name
OFFSET 9000
LIMIT 1000
]]></programlisting>
<para>LIMIT applies to the solution resulting from the graph patterns specified in the WHERE
CLAUSE. This implies that SELECT and CONSTRUCT/DESCRIBE queries will
behave a little differently. In the case of a SELECT, there is a straight
translation i.e. LIMIT 4 implies 4 records in the result set. In the
case of CONSTRUCTs where the solution is a graph (implying that the
existence of duplicates and/or unbound variables is common) LIMIT is
basically a maximum triples threshold of: [Solution Triples] x [LIMIT].
</para>
<para>
Example query:
</para>
<programlisting><![CDATA[
SQL>SPARQL
prefix dct:<http://purl.org/dc/terms/>
prefix rdfs:<http://www.w3.org/2000/01/rdf-schema#>
CONSTRUCT { ?resource dct:title ?title ;
a ?type }
FROM <http://msone.computas.no/graphs/inferred/classification>
FROM <http://msone.computas.no/graphs>
FROM <http://msone.computas.no/graphs/instance/nfi>
FROM <http://msone.computas.no/graphs/instance/mo>
FROM <http://msone.computas.no/graphs/ontology/mediasone>
FROM <http://msone.computas.no/graphs/vocab/mediasone>
FROM <http://msone.computas.no/graphs/inferred/nfi/realisation1>
FROM <http://msone.computas.no/graphs/inferred/mo/realisation1>
FROM <http://msone.computas.no/graphs/inferred/nfi/realisation2>
FROM <http://msone.computas.no/graphs/inferred/mo/realisation2>
FROM <http://msone.computas.no/graphs/inferred/agent-classification>
FROM <http://msone.computas.no/graphs/ontology/mediasone/agent>
WHERE {
{
?resource a ?type .
FILTER (?type = <http://www.w3.org/2002/07/owl#Class> ) .
?resource rdfs:label ?title .
} UNION {
?resource a ?type .
FILTER (?type in (
<http://musicbrainz.org/mm/mm-2.1#Track> ,
<http://www.csd.abdn.ac.uk/~ggrimnes/dev/imdb/IMDB#Movie> ,
<http://xmlns.com/foaf/0.1/Image> ,
<http://www.computas.com/mediasone#Text> ) ) .
?resource dct:title ?title .
}
FILTER regex(?title, "turi", "i")
}
ORDER BY ?title LIMIT 4 OFFSET 0
]]></programlisting>
<sect3 id="rdfsparqlandxquery"><title>SPARQL and XQuery Core Function Library</title>
<para>In the current implementation, the XQuery Core Function Library is not available from SPARQL.</para>
<para>As a temporary workaround, string parsing functions are made available, because they are widely used in W3C DAWG examples and the like. They are:</para>
<programlisting>
xsd:boolean (in strg any) returns integer
xsd:dateTime (in strg any) returns datetime
xsd:double (in strg varchar) returns double precision
xsd:float (in strg varchar) returns float
xsd:integer (in strg varchar) returns integer
</programlisting>
<para>(assuming that the query contains the declaration: 'PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>')</para>
</sect3>
</sect2>
<sect2 id="rdfpredicatessparql"><title>Query Constructs</title>
<para>Starting from Version 5.0, Virtuoso supports filtering RDF objects triples by a given predicate.</para>
<sect3 id="rdfpredicatessparqlexamples"><title>Examples</title>
<para>The boolean functions bif:contains, bif:xcontains, bif:xpath_contains and bif:xquery_contains can be used for objects that come from RDF Views as well
as for regular "physical" triples. Each of these functions takes two arguments and returns a boolean value.
The first argument is a local variable which should also be used as an object field in
the group pattern where the filter condition is placed.
</para>
<para>In order to execute the examples below please run these commands:</para>
<programlisting><![CDATA[
SQL>SPARQL CLEAR GRAPH <http://MyTest.com>;
DB.DBA.RDF_QUAD_URI_L ('http://MyTest.com', 'sxml1', 'p_all1', xtree_doc ('<Hello>world</Hello>'));
DB.DBA.RDF_QUAD_URI_L ('http://MyTest.com', 'sxml2', 'p_all2', xtree_doc ('<Hello2>world</Hello2>'));
DB.DBA.RDF_QUAD_URI_L ('http://MyTest.com', 'nonxml1', 'p_all3', 'Hello world');
VT_INC_INDEX_DB_DBA_RDF_OBJ();
DB.DBA.RDF_OBJ_FT_RULE_ADD ('http://MyTest.com', null, 'My test RDF Data');
]]></programlisting>
<para><emphasis>bif:contains</emphasis></para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://MyTest.com>
WHERE { ?s ?p ?o . ?o bif:contains "world" };
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
sxml1 p_all1 <Hello>world</Hello>
nonxml1 p_all3 Hello world
sxml2 p_all2 <Hello2>world</Hello2>
3 Rows. -- 20 msec.
]]></programlisting>
<para><emphasis>bif:xcontains</emphasis></para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://MyTest.com>
WHERE { ?s ?p ?o . ?o bif:xcontains "//Hello[text-contains (., 'world')]" };
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
sxml1 p_all <Hello>world</Hello>
1 Rows. -- 10 msec.
]]></programlisting>
<para><emphasis>bif:xpath_contains</emphasis></para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://MyTest.com>
WHERE { ?s ?p ?o . ?o bif:xpath_contains "//*" };
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
sxml1 p_all1 <Hello>world</Hello>
sxml2 p_all2 <Hello2>world</Hello2>
2 Rows. -- 20 msec.
]]></programlisting>
<para><emphasis>bif:xquery_contains</emphasis></para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://MyTest.com>
WHERE { ?s ?p ?o . ?o bif:xquery_contains "//Hello2 , world" };
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
sxml2 p_all2 <Hello2>world</Hello2>
1 Rows. -- 20 msec.
]]></programlisting>
</sect3>
</sect2>
<sect2 id="rdfsparqlprotocolendpoint"><title>SPARQL Web Services & APIs</title>
<sect3 id="rdfsparqlprotocolendpointintro"><title>Introduction</title>
<para>The Virtuoso SPARQL query service implements the <ulink url="http://www.w3.org/TR/rdf-sparql-protocol/">SPARQL Protocol for RDF</ulink>
(W3C Working Draft 25 January 2006) providing SPARQL query processing for RDF data available on the open internet.</para>
<para>The query processor extends the standard protocol to provide support for multiple output formats.
At present this uses additional query parameters.</para>
<para>Supported features include:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Support for GET and POST requests</listitem>
<listitem>Support for a variety of transfer MIME-types, including RDF /XML and TURTLE</listitem>
<listitem>Support for a <emphasis>default-graph-uri</emphasis> parameter</listitem>
<listitem>Support for a variety of query types including CONSTRUCT and DESCRIBE</listitem>
</itemizedlist>
</sect3>
<sect3 id="rdfsupportedprotocolendpointuri"><title>Service Endpoint</title>
<para>Virtuoso uses the pre-assigned endpoints "/sparql" and "/SPARQL" as the
defaults for exposing its REST based SPARQL Web Services.</para>
<para>The port number associated with the SPARQL services is determined by the 'ServerPort' key value
in the '[HTTPServer]' section of the virtuoso.ini file. Thus, if the Virtuoso instance is configured
to listen at a none default port e.g. 8890, the SPARQL endpoints would be accessible
at http://example.com:8890/sparql/.</para>
<para>The SPARQL endpoint supports both GET and POST requests. The client chooses between GET and POST
automatically, using the length of query text as the criterion. If the SPARQL endpoint is accessed without
any URL and requisite SPARQL protocol parameters, an interactive HTML page for capturing SPARQL input will
be presented.</para>
<sect4 id="rdfsupportedprotocolendpointuricustm"><title>Customizing SPARQL Endpoint Page</title>
<para>The following steps describe how to change the sparql endpoint page:
</para>
<orderedlist>
<listitem>Create a patched version of the procedure named WS.WS."/!sparql/". Its source text resides in libsrc/Wi/sparql_io.sql .</listitem>
<listitem>Name the new version of the procedure from above with different name, for ex.: WS.WS."/!sparql_new/" </listitem>
<listitem>Load it in ISQL:
<programlisting><![CDATA[
SQL>create procedure WS.WS."/!sparql_new/" (inout path varchar, inout params any, inout lines any)
{..
http(' <p>TEST This query page is designed to help you test OpenLink Virtuoso
..
}
;
Done. -- 60 msec.
SQL>
]]></programlisting>
</listitem>
<listitem>Execute:
<programlisting><![CDATA[
SQL>DB.DBA.VHOST_REMOVE (lpath=>'/sparql');
]]></programlisting>
</listitem>
<listitem>Execute:
<programlisting><![CDATA[
SQL>DB.DBA.VHOST_DEFINE (lpath=>'/sparql/', ppath => '/your-function-name/', is_dav => 1, vsp_user => 'dba', opts => vector('noinherit', 1));
-- so for ex.:
SQL>DB.DBA.VHOST_DEFINE (lpath=>'/sparql/', ppath => '/!sparql_new/', is_dav => 1, vsp_user => 'dba', opts => vector('noinherit', 1));
]]></programlisting>
</listitem>
<listitem>Execute:
<programlisting><![CDATA[
SQL>grant execute on WS.WS."your-function" to "SPARQL";
-- so for ex.:
SQL>grant execute on WS.WS."/!sparql_new/" to "SPARQL";
]]></programlisting>
<itemizedlist mark="bullet">
<listitem>Note: you should use double quotes around name of "SPARQL" user and the upper case, otherwise it will be confused with keyword SPARQL.</listitem>
</itemizedlist>
</listitem>
<listitem>Execute:
<programlisting><![CDATA[
SQL>registry_set ('/your-function-name/', 'no_vsp_recompile');
-- so for ex.:
SQL>registry_set ('/!sparql_new/', 'no_vsp_recompile');
]]></programlisting>
<itemizedlist mark="bullet">
<listitem>Note: if this step is omitted, the HTTP server will try to find the physical path in DAV storage or a filesystem, to read and compile the content as a procedure.</listitem>
</itemizedlist>
</listitem>
<listitem>Access the sparql endpoint page which now as result should contain your changes:
<figure id="spqc1" float="1">
<title>SPARQL Endpoint page</title>
<graphic fileref="ui/spqc1.png"/>
</figure>
</listitem>
</orderedlist>
</sect4>
</sect3>
<sect3 id="rdfrequestparamsextensions"><title>SPARQL Protocol Extensions</title>
<sect4 id="rdfrequestparamsofunctions"><title>Request Parameters</title>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Request Parameters List</title>
<tgroup align="char" charoff="50" char="." cols="3">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>Parameter</entry>
<entry>Notes</entry>
<entry>Required?</entry>
</row>
</thead>
<tbody>
<row>
<entry>service</entry>
<entry>Service URI such as 'http://example.com/sparql/'</entry>
<entry>Yes</entry>
</row>
<row>
<entry>query</entry>
<entry>Text of the query</entry>
<entry>Yes</entry>
</row>
<row>
<entry>dflt_graph</entry>
<entry>Default graph URI (string or NULL)</entry>
<entry>No</entry>
</row>
<row>
<entry>named_graphs</entry>
<entry>Vector of named graphs (or NULL to prevent overriding named graphs specified in the query)</entry>
<entry>Yes</entry>
</row>
<row>
<entry>req_hdr</entry>
<entry>Additional HTTP headers that should be passed to the service, e.g. 'Host: ...'</entry>
<entry>No</entry>
</row>
<row>
<entry>maxrows</entry>
<entry>Limit on the numbers of rows that should be returned (the actual size of the result set may differ)</entry>
<entry>No</entry>
</row>
<row>
<entry>xslt-uri</entry>
<entry>Absolute URL of any XSLT stylesheet file to be applied to the SPARQL query results</entry>
<entry>No</entry>
</row>
<row>
<entry>timeout</entry>
<entry>Timeout for "anytime" query execution, in milliseconds, values less than 1000 are ignored; see
<link linkend="anytimequeries">Anytime Queries</link> for more details</entry>
<entry>No</entry>
</row>
</tbody>
</tgroup>
</table>
</sect4>
<sect4 id="rdfresponsecodeofprotocol"><title>Response Codes</title>
<para>If the query is a CONSTRUCT or a DESCRIBE then the result set
consists of a single row and a single column. The value inside is a
dictionary of triples in 'long valmode'. Note that the dictionary
object cannot be sent to a SQL client, say, via ODBC. The client may
lose the database connection trying to fetch a result set row that
contains a dictionary object. This disconnection does not disrupt the server,
so the client may readily reconnect to the server, but the disconnected
transaction will have been rolled back.</para>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="virtodbcsparql">Virtuoso ODBC RDF extensions for SPASQL</link></listitem>
</itemizedlist>
</tip>
</sect4>
<sect4 id="rdfsupportedmimesofprotocol"><title>Response Format</title>
<para>All the SPARQL protocol standard MIME types are supported by a SPARQL web service client.
Moreover, SPARQL web service endpont supports additional MIME types and in some cases additional
query types for standard MIME types.</para>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Supported MIME Types list</title>
<tgroup align="char" charoff="50" char="." cols="3">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>Content-Type</entry>
<entry>SPARQL query type</entry>
<entry>Support in Virtuoso</entry>
</row>
</thead>
<tbody>
<row>
<entry>'application/sparql-results+xml'</entry>
<entry>SELECT, ASK</entry>
<entry>both client and endpoint</entry>
</row>
<row>
<entry>'application/rdf+xml'</entry>
<entry>CONSTRUCT, DESCRIBE</entry>
<entry>both client and endpoint</entry>
</row>
<row>
<entry>'application/rdf+xml'</entry>
<entry>SELECT</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'application/rdf+json'</entry>
<entry>CONSTRUCT, DESCRIBE</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'text/rdf+n3'</entry>
<entry>CONSTRUCT, DESCRIBE</entry>
<entry>both client and endpoint</entry>
</row>
<row>
<entry>'text/rdf+n3'</entry>
<entry>SELECT, ASK</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'text/html'</entry>
<entry>SELECT</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'application/javascript'</entry>
<entry>SELECT</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'application/sparql-results+json'</entry>
<entry>SELECT, ASK</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'application/vnd.ms-excel'</entry>
<entry>SELECT</entry>
<entry>endpoint only</entry>
</row>
<row>
<entry>'application/soap+xml' and 'application/soap+xml;11'</entry>
<entry>SELECT</entry>
<entry>endpoint only</entry>
</row>
</tbody>
</tgroup>
</table>
<para>The current implementation does not support returning the results of SELECT as RDF/XML or 'sparql-results-2'.</para>
<para>If the HTTP header returned by the remote server does not contain a 'Content-Type' line, the client may guess MIME type from the text of the returned body.</para>
<para>Error messages returned from the service are returned as XML documents, using the MIME type application/xml. The documents consist of a single element containing an error message.</para>
</sect4>
<sect4 id="rdfsupportedmimesofprotocoladdselect"><title>Additional Response Formats -- SELECT</title>
<para>Use the format parameter to select one of the following alternate output formats:</para>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Additional Response formats list -- SELECT</title>
<tgroup align="char" charoff="50" char="." cols="3">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>Format Value</entry>
<entry>Description</entry>
<entry>Mimetype</entry>
</row>
</thead>
<tbody>
<row>
<entry>HTML</entry>
<entry>The result is a HTML document containing query summary and tabular results. The format
is human-readable but not intended for using by applications because it makes strings undistinguishable
from IRIs and loses other details such as exact datatypes of returned values.</entry>
<entry>text/html</entry>
</row>
<row>
<entry>json</entry>
<entry>Two separate MIME types exist for JSON: JSON serialization of results is
'application/sparql-results+json' and confirms to the draft specification "Serializing SPARQL
Query Results in JSON". JSON serialization of triples is 'application/rdf+json' and interoperable
with Talis. Sometimes a client needs a JSON but it does not know the type of query it sends to
Virtuoso web service endpoint. In this case the client can specify either one MIME-type
'application/json' or both 'application/sparql-results+json' and 'application/rdf+json' in the
"Accept" header line and Virtuoso will chose the appropriate one automatically. Similar trick
works for other sorts of result types: Virtuoso inspects the whole "Accept" header line to
find out the most appropriate return type for the given query.
</entry>
<entry>application/sparql-results+json</entry>
</row>
<row>
<entry>json</entry>
<entry></entry>
<entry>application/rdf+json</entry>
</row>
<row>
<entry>js</entry>
<entry>Javascript serialization of results generates an HTML table with the CSS class sparql.
The table contains a column indicating row number and additional columns for each query variable.
Each query solution contributes one row of the table.
Unbound variables are indicated with a non-breaking space in the appropriate table cells.</entry>
<entry>application/javascript</entry>
</row>
<row>
<entry>table</entry>
<entry></entry>
<entry>text/html</entry>
</row>
<row>
<entry>XML</entry>
<entry></entry>
<entry>text/html</entry>
</row>
<row>
<entry>TURTLE</entry>
<entry></entry>
<entry>text/html</entry>
</row>
</tbody>
</tgroup>
</table>
</sect4>
<sect4 id="rdfsupportedmimesofprotocoladdcons"><title>Additional Response Formats -- CONSTRUCT & DESCRIBE</title>
<para><emphasis>Example output of DESCRIBE in rdf+json serialization format</emphasis></para>
<orderedlist>
<listitem>Go to the sparql endpoint at http://host:port/sparql, for ex. at http://dbpedia.org/sparql</listitem>
<listitem>Enter query in the "Query text" area, for ex.:
<programlisting><![CDATA[
DESCRIBE <http://dbpedia.org/resource/%22S%22_Bridge_II>
]]></programlisting>
</listitem>
<listitem>Select for "Display Results As": JSON</listitem>
<listitem>Click "Run Query" button.</listitem>
<listitem>As result should be produced the following output:
<programlisting><![CDATA[
{
{ 'http://dbpedia.org/resource/%22S%22_Bridge_II' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/ontology/Place' } ,
{ 'type' : 'uri', 'value' : 'http://dbpedia.org/ontology/Resource' } ,
{ 'type' : 'uri', 'value' : 'http://dbpedia.org/ontology/HistoricPlace' } } ,
{ 'http://dbpedia.org/ontology/added' : { 'type' : 'literal', 'value' : '1973-04-23' , 'datatype' : 'http://www.w3.org/2001/XMLSchema#date' } } ,
{ 'http://www.w3.org/2003/01/geo/wgs84_pos#lat' : { 'type' : 'literal', 'value' : 39.99305725097656 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#float' } } ,
{ 'http://www.w3.org/2003/01/geo/wgs84_pos#long' : { 'type' : 'literal', 'value' : -81.74666595458984 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#float' } } ,
{ 'http://dbpedia.org/property/wikiPageUsesTemplate' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Template:infobox_nrhp' } } ,
{ 'http://dbpedia.org/property/name' : { 'type' : 'literal', 'value' : '"S" Bridge II' , 'lang' : 'en' } } ,
{ 'http://dbpedia.org/property/nearestCity' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/New_Concord%2C_Ohio' } ,
{ 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Ohio' } } ,
{ 'http://dbpedia.org/property/latDirection' : { 'type' : 'literal', 'value' : 'N' , 'lang' : 'en' } } ,
{ 'http://dbpedia.org/property/governingBody' : { 'type' : 'literal', 'value' : 'State' , 'lang' : 'en' } } ,
{ 'http://www.georss.org/georss/point' : { 'type' : 'literal', 'value' : '39.99305556 -81.74666667' } ,
{ 'type' : 'literal', 'value' : '39.9930555556 -81.7466666667' } } ,
{ 'http://xmlns.com/foaf/0.1/name' : { 'type' : 'literal', 'value' : '"S" Bridge II' } } ,
{ 'http://dbpedia.org/property/latDegrees' : { 'type' : 'literal', 'value' : 39 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://dbpedia.org/property/latMinutes' : { 'type' : 'literal', 'value' : 59 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://dbpedia.org/property/latSeconds' : { 'type' : 'literal', 'value' : 35 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://dbpedia.org/property/longDirection' : { 'type' : 'literal', 'value' : 'W' , 'lang' : 'en' } } ,
{ 'http://dbpedia.org/property/architect' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Benjamin_Latrobe' } } ,
{ 'http://dbpedia.org/property/added' : { 'type' : 'literal', 'value' : '1973-04-23' , 'datatype' : 'http://www.w3.org/2001/XMLSchema#date' } } ,
{ 'http://www.w3.org/2000/01/rdf-schema#label' : { 'type' : 'literal', 'value' : '"S" Bridge II (Muskingum County, Ohio)' , 'lang' : 'nl' } ,
{ 'type' : 'literal', 'value' : '"S" Bridge II' , 'lang' : 'en' } } ,
{ 'http://dbpedia.org/ontology/architect' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Benjamin_Latrobe' } } ,
{ 'http://xmlns.com/foaf/0.1/img' : { 'type' : 'uri', 'value' : 'http://upload.wikimedia.org/wikipedia/commons/d/d4/FoxRunS-Bridge_NewConcordOH.jpg' } } ,
{ 'http://dbpedia.org/property/locmapin' : { 'type' : 'literal', 'value' : 'Ohio' , 'lang' : 'en' } } ,
{ 'http://dbpedia.org/property/refnum' : { 'type' : 'literal', 'value' : 73001513 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://dbpedia.org/property/abstract' : { 'type' : 'literal', 'value' : '"S" Bridge II is a historic S bridge near New Concord, Ohio, United States. A part of the National Road, the first federally-financed highway in the United States, it was built in 1828. Its peculiar shape, typical for an S bridge, is designed to minimize the span and allow easy access. In 1973, it was listed on the National Register of Historic Places.' , 'lang' : 'en' } ,
{ 'type' : 'literal', 'value' : '"S" Bridge II bij New Concord, Ohio, is een deel van de National Road, een van de eerste highways die door de federale overheid vanaf 1811 werden aangelegd. De vorm, die de brug als een S Brug kenmerkt, is bedoeld om de overspanning zo klein mogelijk te houden en toch gemakkelijk toegang tot de brug te verlenen. De brug staat sinds 1973 op de lijst van het National Register of Historic Places als monument vermeld.' , 'lang' : 'nl' } } ,
{ 'http://www.w3.org/2004/02/skos/core#subject' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Category:National_Register_of_Historic_Places_in_Ohio' } ,
{ 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Category:Bridges_on_the_National_Register_of_Historic_Places' } } ,
{ 'http://dbpedia.org/ontology/nearestCity' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/Ohio' } ,
{ 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/New_Concord%2C_Ohio' } } ,
{ 'http://xmlns.com/foaf/0.1/depiction' : { 'type' : 'uri', 'value' : 'http://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/FoxRunS-Bridge_NewConcordOH.jpg/200px-FoxRunS-Bridge_NewConcordOH.jpg' } } ,
{ 'http://dbpedia.org/property/caption' : { 'type' : 'literal', 'value' : 'The bridge in the fall' , 'lang' : 'en' } } ,
{ 'http://dbpedia.org/property/longDegrees' : { 'type' : 'literal', 'value' : 81 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://dbpedia.org/property/longMinutes' : { 'type' : 'literal', 'value' : 44 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://dbpedia.org/property/longSeconds' : { 'type' : 'literal', 'value' : 48 , 'datatype' : 'http://www.w3.org/2001/XMLSchema#integer' } } ,
{ 'http://www.w3.org/2000/01/rdf-schema#comment' : { 'type' : 'literal', 'value' : '"S" Bridge II is a historic S bridge near New Concord, Ohio, United States.' , 'lang' : 'en' } ,
{ 'type' : 'literal', 'value' : '"S" Bridge II bij New Concord, Ohio, is een deel van de National Road, een van de eerste highways die door de federale overheid vanaf 1811 werden aangelegd.' , 'lang' : 'nl' } } ,
{ 'http://xmlns.com/foaf/0.1/page' : { 'type' : 'uri', 'value' : 'http://en.wikipedia.org/wiki/%22S%22_Bridge_II' } } } ,
{ 'http://dbpedia.org/resource/%22S%22_Bridge_II_%28Muskingum_County%2C_Ohio%29' : { 'http://dbpedia.org/property/redirect' : { 'type' : 'uri', 'value' : 'http://dbpedia.org/resource/%22S%22_Bridge_II' } } }
}
]]></programlisting>
</listitem>
</orderedlist>
<para><emphasis>Example output of CONSTRUCT in rdf+json serialization format</emphasis></para>
<orderedlist>
<listitem>Go to the sparql endpoint at http://host:port/sparql, for ex. at http://dbpedia.org/sparql</listitem>
<listitem>Enter query in the "Query text" area, for ex.:
<programlisting><![CDATA[
CONSTRUCT
{
?s a ?Concept .
}
WHERE
{
?s a ?Concept .
}
LIMIT 10
]]></programlisting>
</listitem>
<listitem>Select for "Display Results As": JSON</listitem>
<listitem>Click "Run Query" button.</listitem>
<listitem>As result should be produced the following output:
<programlisting><![CDATA[
{
{ 'http://dbpedia.org/ontology/Place' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/Area' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/City' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/River' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/Road' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/Lake' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/LunarCrater' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/ShoppingMall' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/Park' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } } ,
{ 'http://dbpedia.org/ontology/SiteOfSpecialScientificInterest' : { 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' : { 'type' : 'uri', 'value' : 'http://www.w3.org/2002/07/owl#Class' } } }
}
]]></programlisting>
</listitem>
</orderedlist>
<para>
For interoperability with clients that were developed before current versions of SPARQL protocol and
format specs are issued, Virtuoso supports some obsolete variants of standard MIME types.
'text/rdf+n3', 'text/rdf+ttl', 'application/turtle' and 'application/x-turtle' are understood for
TURTLE output, 'application/x-rdf+json' and 'application/rdf+json' are for "Serializing SPARQL Query
Results in JSON". When a client specifies obsolete MIME type but not its standard variant, an obsolete
variant is returned for interoperability.
</para>
</sect4>
<sect4 id="rdfsupportedmimesaddofprotocol"><title>Virtuoso/PL APIs</title>
<para>Virtuoso also provides SPARQL protocol client APIs in Virtuoso PL, so you can communicate with SPARQL
Query Services from Virtuoso stored procedures. The APIs are as follows:
</para>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Virtuoso/PL APIs</title>
<tgroup align="char" charoff="50" char="." cols="2">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>API</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry>DB.DBA.SPARQL_REXEC</entry>
<entry>Behaves like DBA.SPARQL_EVAL, but executes the query on the specified server. The procedure
does not return anything. Instead, it creates a result set.</entry>
</row>
<row>
<entry>DB.DBA.SPARQL_REXEC_TO_ARRAY</entry>
<entry>Behaves like DBA.SPARQL_EXEC_TO_ARRAY(), but executes the query on the specified server. The
function returns a vector of rows, where every row is represented by a vector of field values.</entry>
</row>
<row>
<entry>DB.DBA.SPARQL_REXEC_WITH_META</entry>
<entry>Has no local SPARQL_EVAL analog. It produces not only an array of result rows together with an array
of result set metadata in a format used by the exec() function.</entry>
</row>
</tbody>
</tgroup>
</table>
</sect4>
<sect4 id="anytimequeriessparql">
<title>SPARQL Anytime Queries</title>
<para>Starting with version 6, Virtuoso offers a partial query evaluation feature that guarantees
answers to arbitrary queries within a fixed time. This is intended for use in publicly available SPARQL
or SQL end points on large databases. This enforces a finite duration to all queries and will strive to
return meaningful partial results. Thus this provides the same security as a transaction timeout but will
be more user friendly since results will generally be returned, also for aggregate queries. Outside of a
public query service, this may also be handy when exploring a large data set with unknown properties.
</para>
<para>The feature is activated with the statement</para>
<programlisting><![CDATA[
set result_timeout == <expression>;
]]></programlisting>
<para>Find more detailed information in the <link linkend="anytimequeries">Anytime Queries</link> section.</para>
</sect4>
</sect3>
<sect3 id="rdfsupportedprotocolendpointuri"><title>Service Endpoint Security</title>
<para>Earlier releases of Virtuoso secured the SPARQL endpoint via privileges assigned to the service-
specific SQL user account "SPARQL". This account was optionally granted "SPARQL_SELECT" or
"SPARQL_UPDATE" roles. By default only the "SPARQL_SELECT" role was assigned, enabling all users
to at least perform SELECT queries. The "SPARQL_UPDATE" role must be granted to allow updates
to the Quad Store - a pre-requisite for the Virtuoso Sponger services to be functional i.e. to
allow the Sponger to populate and update the Quad Store. In Virtuoso release 5.0.7, there is a new "SPARQL_SPONGE" role
which can be assigned specifically to allow Sponger services to update the Quad Store but not
SPARQL users via the SPARQL endpoint.</para>
<para>Restricting a user's access to specific graphs can be done using Virtuoso row-level security
functionality, via one of the Virtuoso Data Access APIs: ODBC, JDBC, ADO.Net or PL code.</para>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="virtodbcsparql">Virtuoso ODBC RDF extensions for SPASQL</link></listitem>
</itemizedlist>
</tip>
<para>For example, users of OpenLink Data Space (ODS) applications are restricted in the RDF graphs accessible to them as follows:</para>
<programlisting><![CDATA[
DB.DBA.TABLE_DROP_POLICY ('DB.DBA.RDF_QUAD', 'S');
create procedure DB.DBA.RDF_POLICY (in tb varchar, in op varchar)
{
declare chost, ret varchar;
chost := DB.DBA.WA_CNAME ();
ret := sprintf ('(ID_TO_IRI (G) NOT LIKE \'http://%s/dataspace/%%/private#\' ' ||
'OR G = IRI_TO_ID (sprintf (\'http://%s/dataspace/%%U/private#\', USER)))', chost, chost);
return ret;
}
;
grant execute on DB.DBA.RDF_POLICY to public;
DB.DBA.TABLE_SET_POLICY ('DB.DBA.RDF_QUAD', 'DB.DBA.RDF_POLICY', 'S');
]]></programlisting>
<para>
where DB.DBA.WA_CNAME () is an ODS function returning the default host name.
</para>
<para>The effect of this policy is to restrict user 'user' to the graph http://cname/dataspace/user/private#</para>
<para>Virtuoso reserves the path '/sparql-auth/' for a SPARQL service supporting authenticated SPARUL.
This endpoint allows specific SQL accounts to perform SPARUL over the SPARQL protocol.
To be allowed to login via SQL or ODBC and update physical triples, a user must be granted "SPARQL_UPDATE" privileges. To grant this role:
</para>
<itemizedlist>
<listitem>Go to the Virtuoso administration UI i.e. http://host:port/conductor</listitem>
<listitem>Login as user dba</listitem>
<listitem>Go to System Admin->User Accounts->Users
<figure id="rdf1" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/usr1.png"/>
</figure>
</listitem>
<listitem>Click the link "Edit"</listitem>
<listitem>In the displayed form check the "Allow SQL/ODBC Logins" check-box.</listitem>
<listitem>Select from the list of available Account Roles "SPARQL_UPDATE" role and
click the ">>" button so to add it to the right-hand list.</listitem>
<figure id="rdf2" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/usr2.png"/>
</figure>
<listitem>Click the "Save" button.</listitem>
</itemizedlist>
<para>Note that if a table is used in an RDF view, and this table is not granted to SPARQL_SELECT permission
(or SPARQL_UPDATE, which implicitly confers SPARQL_SELECT), then all SELECTs on a graph defined by an RDF view will return an access violation error as the user
account has no permissions to read the table. The user must have appropriate privileges on all tables included
in an RDF View in order to be able to select on <emphasis>all</emphasis> graphs.</para>
<sect4 id="sparqwebservicetbl"><title>Managing a SPARQL Web Service Endpoint</title>
<para>
Virtuoso web service endpoints may provide different default configurations for different host names mentioned in an HTTP request.
Host name configuration for SPARQL web service endpoints can be managed via the table <emphasis>DB.DBA.SYS_SPARQL_HOST</emphasis>.
</para>
<programlisting>
create table DB.DBA.SYS_SPARQL_HOST (
SH_HOST varchar not null primary key, -- host mask
SH_GRAPH_URI varchar, -- default 'default graph' uri
SH_USER_URI varchar, -- reserved for any use in applications
SH_DEFINES long varchar -- additional defines for requests
)
</programlisting>
<para>You can find detailed descriptions of the table columns <link linkend="rdfdefaultgraph">here</link>.
Also, please read <link linkend="rdfperfindexes">these notes</link> on managing public web service endpoints.</para>
</sect4>
<sect4 id="sparqloauthendpointauth"><title>Authentication</title>
<para>Virtuoso 5.0.7 introduced a new "SPARQL_SPONGE" role which can be assigned
specifically for controlling Sponger middleware services which perform writes and graph creation in
the RDF Quad Store. This role only allows updates through the Sponger. Quad Store updates via any other route
require granting the SPARQL_UPDATE role.</para>
<para>
Virtuoso 5.0.11 onwards added three new methods for securing SPARQL endpoints that include:
</para>
<itemizedlist mark="bullet">
<listitem>SQL authentication</listitem>
<listitem>OAuth</listitem>
<listitem>FOAF+SSL protocol based authentication</listitem>
</itemizedlist>
<para>
Each of these authentication methods is associated with a purpose specific default SPARQL endpoint along the following lines:
</para>
<itemizedlist mark="bullet">
<listitem>http://<cname>/sparql-auth (SQL authentication)</listitem>
<listitem>http://<cname>/sparql-oauth (OAuth)</listitem>
<listitem>https://<cname>/sparql and https://<cname>/sparql-ssl (FOAF+SSL)</listitem>
</itemizedlist>
<para>The Virtuoso Authentication Server offers a UI with options for managing:</para>
<itemizedlist mark="bullet">
<listitem>
Application keys and protected SPARQL endpoints: OAuth provides a secure data transmission
level mechanism for your SPARQL endpoint. It enables you to interact securely with your RDF database
from a variety of locations. It also allows you to provide controlled access to private data to selected
user profiles.
</listitem>
<listitem>FOAF+SSL ACLs: FOAF+SSL is an implementation of a conceptual authentication and authorization
protocol that links a Web ID to a public key to create a global, decentralized/distributed, and open
yet secure authentication system that functions with existing browsers.</listitem>
</itemizedlist>
<para>Virtuoso Authentication Server can be installed by downloading and installing the
policy_manager_dav.vad package.</para>
<para>The Authentication UI is accessible from the URL http://cname:port/policy_manager</para>
<para>The menu options are:</para>
<itemizedlist mark="bullet">
<listitem><emphasis>Go to Application Keys</emphasis> - in order to create Consumer Key and Secret for the relevant ODS applications.</listitem>
<listitem><emphasis>Go to FOAF+SSL ACLs</emphasis> - in order to use URIs for setup DB level controls for SELECT, UPDATE and DELETE.
(This option requires you be logged in as user dba.)
</listitem>
<listitem><emphasis>Go to Protected SPARQL Endpoint</emphasis> - in order to enter your Application Consumer Key and perform secure SPARQL queries.</listitem>
</itemizedlist>
<figure id="sparqloauthendpoint4" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth4.png"/>
</figure>
<para>Users must have SQL privileges in order to run secure SPARQL statements.</para>
</sect4>
<sect4 id="sparqloauthendpoint"><title>SPARQL OAuth Endpoint</title>
<para>OAuth provides a secure data transmission level mechanism for your SPARQL endpoint.
It enables you to interact securely with your RDF database from a variety of locations. It also
allows you to provide controlled access to private data to selected users.</para>
<para>Virtuoso OAuth Server can be installed by downloading and installing the oauth_dav.vad package.
The OAuth UI is accessible from the URL http://cname:port/oauth</para>
<para>A user must have SQL privileges in order to run secured SPARQL statements.</para>
<para>Here is a sample scenario:</para>
<orderedlist>
<listitem>Install the conductor_dav.vad and policy_manager_dav.vad packages.</listitem>
<listitem>From the Conductor UI, create user test1, allow both SQL/ODBC and DAV logins and assign the SPARQL_UPDATE role to this user:
<orderedlist>
<listitem>Go to http://cname:port/conductor</listitem>
<listitem>Log in as user dba</listitem>
<listitem>Go to System Admin->User Account and click the "Create New Account" link
<figure id="sparqloauthendpoint1" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/SparqlOAuth1.png"/>
</figure>
</listitem>
<listitem>In the displayed form:
<orderedlist>
<listitem>Enter a user name, for example test1, a password and then confirm the password </listitem>
<listitem>Check "Allow DAV Logins" </listitem>
<listitem>Check "Allow SQL/ODBC Logins" </listitem>
<listitem>Add role "SPARQL_UPDATE" from the list of available roles to the "Selected" box.
<figure id="sparqloauthendpoint2" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/SparqlOAuth2.png"/>
</figure>
</listitem>
</orderedlist>
</listitem>
<listitem>Click the "Save" button. </listitem>
<listitem>User test1 will then be created.
<figure id="sparqloauthendpoint3" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/SparqlOAuth3.png"/>
</figure>
</listitem>
</orderedlist>
</listitem>
<listitem>Go to http://cname:port/policy_manager/
<figure id="sparqloauthendpoint4" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth4.png"/>
</figure>
</listitem>
<listitem>Click the "OAuth keys" link</listitem>
<listitem>Log in as user test1
<figure id="sparqloauthendpoint5" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth5.png"/>
</figure>
</listitem>
<listitem>The OAuth application registration form will then be shown.
<figure id="sparqloauthendpoint6" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth6.png"/>
</figure>
</listitem>
<listitem>Generate a key for SPARQL by selecting it from the list of application names and clicking the "Generate Keys" button.</listitem>
<listitem>A SPARQL consumer key will then be generated e.g.:
<programlisting><![CDATA[
cf92411e17f59960a4189451bfb5bf6b92c856e3
]]></programlisting>
<figure id="sparqloauthendpoint7" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth7.png"/>
</figure>
</listitem>
<listitem>Click the "Back to main menu" link.</listitem>
<listitem>Click the "Protected SPARQL Endpoint" link.</listitem>
<listitem>The OpenLink Virtuoso SPARQL Query form will be displayed.
<figure id="sparqloauthendpoint8" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth8.png"/>
</figure>
</listitem>
<listitem>Enter the following URI for Default Graph URI:
<programlisting><![CDATA[
http://myopenlink.net/dataspace/person/kidehen#this
]]></programlisting>
</listitem>
<listitem>Enter for the value below for the "OAuth token":
<programlisting><![CDATA[
cf92411e17f59960a4189451bfb5bf6b92c856e3
]]></programlisting>
<figure id="sparqloauthendpoint9" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth9.png"/>
</figure>
</listitem>
<listitem>Click the "Run Query" button.</listitem>
<listitem>In the OAuth Authorization Service form enter the password for user test1 and click the "Login" button.
<figure id="sparqloauthendpoint10" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth10.png"/>
</figure>
</listitem>
<listitem>In the form depicted below, click the "Authorize" button.
<figure id="sparqloauthendpoint11" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth11.png"/>
</figure>
</listitem>
<listitem>Once authorized, the query results will be returned to the requesting client:
<figure id="sparqloauthendpoint12" float="1">
<title>OAuth UI</title>
<graphic fileref="ui/SparqlOAuth12.png"/>
</figure>
</listitem>
</orderedlist>
</sect4>
<sect4 id="sparqloauthendpointfoafssl"><title>FOAF+SSL ACLs</title>
<para>FOAF+SSL is an implementation of a conceptual authentication and authorization protocol that
links a Web ID to a public key, to create a global decentralized/distributed, and open yet secure
authentication system that functions with existing browsers.</para>
<para>To use FOAF+SSL, download and install the policy_manager_dav.vad VAD package. Once installed, to access the FOAF+SSL ACLs UI, use the URL http://cname:port/policy_manager,
then click the link FOAF+SSL ACLs.</para>
<figure id="sparqloauthendpoint1" float="1">
<title>FOAFSSL</title>
<graphic fileref="ui/SparqlOAuth4.png"/>
</figure>
<para>Note: You must log in as user dba</para>
<para>
Configuring FOAF+SSL ACLs is with a FOAF+SSL certificate and a Web ID allows secure SPARQL queries to be performed against a Virtuoso SPARQL-SSL endpoint and viewing of the query results.
The SPARQL-SSL endpoint URL is of the form https://cname:port/sparql-ssl</para>
<para>The steps required to configure a sample FOAF+SSL ACL are outlined below:</para>
<orderedlist>
<listitem>Install the ods_framework_dav.vad, conductor_dav.vad and policy_manager_dav.vad packages.</listitem>
<listitem>Using the ODS UI, register an ODS user, e.g. user <emphasis>demo</emphasis>.</listitem>
<listitem>Go to http://cname:port/policy_manager/
<figure id="sparqloauthendpoint4" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlOAuth4.png"/>
</figure>
</listitem>
<listitem>Click the "FOAF+ACLs" link</listitem>
<listitem>Log in as user dba
<figure id="sparqloauthendpoint5" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlFOAFSSL1.png"/>
</figure>
</listitem>
<listitem>The FOAF+SSL ACLs management form will be displayed.
<figure id="sparqloauthendpoint6" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlFOAFSSL2.png"/>
</figure>
</listitem>
<listitem>Enter a Web ID, for example:
<programlisting><![CDATA[
http://demo.openlinksw.com/dataspace/person/demo#this
]]></programlisting>
<para>You can also click the "Browse" button and select a user from the displayed list.
A Web ID will be generated automatically for the selected user.</para></listitem>
<listitem>Select a "SPARQL Role", e.g. "SPONGE".
<figure id="sparqloauthendpoint7" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlFOAFSSL3.png"/>
</figure>
</listitem>
<listitem>Click the "Register" button to create a new FOAF+SSL ACL.
<figure id="sparqloauthendpoint7" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlFOAFSSL4.png"/>
</figure>
</listitem>
<listitem>Go to the SPARQL+SSL endpoint https://cname:port/sparql-ssl</listitem>
<listitem>Select the user's certificate
<figure id="sparqloauthendpoint7" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlFOAFSSL5.png"/>
</figure>
</listitem>
<listitem>The SPARQL Query UI is displayed next:
<figure id="sparqloauthendpoint9" float="1">
<title>FOAFSSL UI</title>
<graphic fileref="ui/SparqlFOAFSSL6.png"/>
</figure>
</listitem>
</orderedlist>
<tip><title>See Also:</title>
<para><link linkend="secureodbcx509foafsll">FOAF+SSL ODBC Login</link></para>
</tip>
</sect4>
<sect4 id="sparqloauthendpointfoafsslsparql"><title>Creating and Using a SPARQL-SSL based Endpoint</title>
<para>The following section describes the basic steps for setting up an SSL protected and WebID
based SPARQL Endpoint (SPARQL-SSL). The guide also covers the use of Virtuoso PL functions and
the Virtuoso Conductor for SPARQL endpoint creation and configuration. It also covers the use
of cURL for exercising the newly generated SPARQL-SSL endpoint.
</para>
<orderedlist>
<listitem><link linkend="vfoafsslst509issuer">Setup the CA issuer and https listener</link></listitem>
<listitem>Define the /sparql-ssl endpoint on an HTTPS based listener (HTTPS service endpoint), for example using Virtuoso PL:
<programlisting><![CDATA[
DB.DBA.VHOST_DEFINE (
lhost=>'127.0.0.1:443',
vhost=>'localhost',
lpath=>'/sparql-ssl',
ppath=>'/!sparql/',
is_dav=>1,
auth_fn=>'DB.DBA.FOAF_SSL_AUTH',
vsp_user=>'dba',
ses_vars=>0,
auth_opts=>vector ( 'https_cert',
'db:https_key_localhost',
'https_key',
'db:https_key_localhost',
'https_verify',
3,
'https_cv_depth',
10 ),
opts=>vector ('noinherit', 1),
is_default_host=>0
);
]]></programlisting>
</listitem>
<listitem><link linkend="sparqloauthendpointfoafssl">Setup the SPARQL-SSL endpoint and define
ACLs</link> using the Virtuoso Conductor</listitem>
<listitem>Export your private key and its associated WebID based X.509 certificate from your
Firefox browser or System's Key Manager into PEM (PKCS12) file
<orderedlist>
<listitem>If using Firefox use the menu path: Advanced -> View Certificates, then click
Backup for your certificate with name "mykey". </listitem>
<listitem>The file "mykey.p12" will be created. To disable password protection so that you
can use this file in non-interactive mode (e.g. with cURL and other HTTP clients) execute:
<programlisting><![CDATA[
openssl pkcs12 -in mykey.p12 -out mykey.pem -nodes
]]></programlisting>
</listitem>
</orderedlist>
</listitem>
<listitem>Test the SPARQL-SSL endpoint with cURL: (listening on default HTTPS 443 port):
<itemizedlist mark="bullet">
<listitem>Note: In this example we use the "-k / --insecure" option with cURL since we are going
to be using self-signed X.509 certificates signed by self-signed root CA.</listitem>
</itemizedlist>
<programlisting><![CDATA[
curl -k -E mykey.pem "https://localhost/sparql-ssl?query=select+*+where+\{+%3Fx+%3Fy+%3Fz+.+\}+limit+10&format=text%2Fn3"
@prefix res: <http://www.w3.org/2005/sparql-results#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
_:_ a res:ResultSet .
_:_ res:resultVariable "x" , "y" , "z" .
@prefix ns0: <https://localhost/tutorial/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:hosting ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:xml ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:repl ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:rdfview ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:services ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:wap ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:bpeldemo ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:web ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:web2 ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:xmlxslt ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
]]></programlisting>
</listitem>
<listitem>Import your key it via Conductor UI:
<orderedlist>
<listitem>Go to Conductor -> System Admin->User Accounts
<figure id="foafsslsparql1" float="1">
<title>Import key it via Conductor UI</title>
<graphic fileref="ui/fsp1.png"/>
</figure>
</listitem>
<listitem>Click "Edit" for your user
<figure id="foafsslsparql2" float="1">
<title>Import key it via Conductor UI</title>
<graphic fileref="ui/fsp2.png"/>
</figure>
</listitem>
<listitem>Change "User type" to: SQL/ODBC and WebDAV
<figure id="foafsslsparql3" float="1">
<title>Import key it via Conductor UI</title>
<graphic fileref="ui/fsp3.png"/>
</figure>
</listitem>
<listitem>Enter your ODS user WebID:
<programlisting><![CDATA[
http://cname:port/dataspace/person/username#this
]]></programlisting>
<figure id="foafsslsparql4" float="1">
<title>Import key it via Conductor UI</title>
<graphic fileref="ui/fsp4.png"/>
</figure>
</listitem>
<listitem>Click "Save"</listitem>
<listitem>Click again "Edit" for your user</listitem>
<listitem>In "PKCS12 file:" click the Browse" button and select your key.</listitem>
<listitem>Enter a local Key Name, for e.g., "cli_key"</listitem>
<listitem>Enter key password
<figure id="foafsslsparql5" float="1">
<title>Import key it via Conductor UI</title>
<graphic fileref="ui/fsp5.png"/>
</figure>
</listitem>
<listitem>Click "Import Key"</listitem>
<listitem>As result the key will be stored with name for ex. cli_key
<figure id="foafsslsparql6" float="1">
<title>Import key it via Conductor UI</title>
<graphic fileref="ui/fsp6.png"/>
</figure>
</listitem>
<listitem>Click "Save"</listitem>
</orderedlist>
</listitem>
<listitem>Test the SPARQL-SSL endpoint with http_client (listening on default HTTPS 443 port):
<orderedlist>
<listitem>Log in at Virtuos ISQL with your user credentials:
<programlisting><![CDATA[
C:\>isql localhost:1111 johndoe****
Connected to OpenLink Virtuoso
Driver: 06.01.3127 OpenLink Virtuoso ODBC Driver
OpenLink Interactive SQL (Virtuoso), version 0.9849b.
Type HELP; for help and EXIT; to exit.
SQL>
]]></programlisting>
</listitem>
<listitem>Execute:
<programlisting><![CDATA[
SQL>select http_client ('https://localhost/sparql-ssl?query=select+*+where+{+%3Fx+%3Fy+%3Fz+.+}+limit+10&format=text%2Fn3', cert_file=>'d
b:cli_key', insecure=>1);
callret
VARCHAR
_______________________________________________________________________________
@prefix res: <http://www.w3.org/2005/sparql-results#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
_:_ a res:ResultSet .
_:_ res:resultVariable "x" , "y" , "z" .
@prefix ns0: <https://localhost/tutorial/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:hosting ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:xml ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:repl ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:rdfview ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:services ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:wap ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:bpeldemo ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
res:binding [ res:variable "x" ; res:value ns0:web ] ;
res:binding [ res:variable "y" ; res:value rdf:type ] ;
res:binding [ res:variable "z" ; res:value "Tutorial" ] ] .
_:_ res:solution [
1 Rows. -- 281 msec.
]]></programlisting>
</listitem>
</orderedlist>
</listitem>
</orderedlist>
<tip><title>See Also:</title>
<para><ulink url="http://demo.openlinksw.com/tutorial/rdf/fs_s_1/fs_s_1.vsp">Demo Example</ulink> Using HTTP client to perform FOAF+SSL connection.</para>
</tip>
</sect4>
</sect3>
<sect3 id="rdfsupportedrequestmethodsofprotocol"><title>Request Methods</title>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Methods List</title>
<tgroup align="char" charoff="50" char="." cols="3">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>Method</entry>
<entry>Supported?</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry>GET</entry>
<entry>Yes</entry>
<entry>Short queries are sent in GET mode</entry>
</row>
<row>
<entry>POST</entry>
<entry>Yes</entry>
<entry>Queries longer than 1900 bytes are POST-ed.</entry>
</row>
<row>
<entry>DELETE</entry>
<entry>No</entry>
<entry></entry>
</row>
<row>
<entry>PUT</entry>
<entry>No</entry>
<entry></entry>
</row>
</tbody>
</tgroup>
</table>
</sect3>
<sect3 id="rdfsparqlclientfunctions"><title>Functions</title>
<para>The SPARQL client can be invoked by three similar functions:</para>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Functions List</title>
<tgroup align="char" charoff="50" char="." cols="3">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>Function</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry>DB.DBA.SPARQL_REXEC</entry>
<entry>Behaves like DBA.SPARQL_EVAL, but executes the query on the specified server. The procedure does not return anything. Instead, it creates a result set. </entry>
</row>
<row>
<entry>DB.DBA.SPARQL_REXEC_TO_ARRAY</entry>
<entry>Behaves like DBA.SPARQL_EXEC_TO_ARRAY (), but executes the query on the specified server. The function return a vector of rows, where every row is represented by a vector of field values.</entry>
</row>
<row>
<entry>DB.DBA.SPARQL_REXEC_WITH_META</entry>
<entry>Has no local 'SPARQL_EVAL' analog. It produces an array of result rows together with an array of result set metadata in the same format as produced by the exec () function.
This function can be used when the result should be passed later to exec_result_names () and exec_result () built-in functions.
To process a local query in similar style, an application can use the SQL built-in function exec () - a SPARQL query (with the 'SPARQL' keyword in front) can be passed to exec () instead of a plain SQL SELECT statement.</entry>
</row>
</tbody>
</tgroup>
</table>
<programlisting>
create procedure DB.DBA.SPARQL_REXEC (
in service varchar, in query varchar, in dflt_graph varchar, in named_graphs any,
in req_hdr any, in maxrows integer, in bnode_dict any );
</programlisting>
<programlisting>
create function DB.DBA.SPARQL_REXEC_TO_ARRAY (
in service varchar, in query varchar, in dflt_graph varchar, in named_graphs any,
in req_hdr any, in maxrows integer, in bnode_dict any )
returns any;
</programlisting>
<programlisting>
create procedure DB.DBA.SPARQL_REXEC_WITH_META (
in service varchar, in query varchar, in dflt_graph varchar, in named_graphs any,
in req_hdr any, in maxrows integer, in bnode_dict any,
out metadata any, -- metadata like exec () returns.
out resultset any) -- results as 'long valmode' values.
</programlisting>
</sect3>
<sect3 id="rdfsparqlendpointexamples"><title>Examples</title>
<para>Virtuoso's SPARQL demo offers a live demonstration of Virtuoso's implementation of the
<ulink url="http://www.w3.org/TR/rdf-dawg-uc/">DAWG's SPARQL test-suite</ulink>,
a collection of SPARQL query language use cases that enable interactive and simplified testing of a triple store implementation.
If you have installed the SPARQL Demo VAD locally, it can be found at a URL similar to 'http://example.com:8080/sparql_demo/', the exact form will depend on your local configuration. Alternatively, a live
version of the documentation is available at <ulink url="http://demo.openlinksw.com/sparql_demo">Virtuoso Demo Server</ulink>.
</para>
<sect4 id="rdfsparqlendpointexamples1"><title>Example SPARQL query issued via curl</title>
<programlisting><![CDATA[
curl -F "query=SELECT DISTINCT ?p FROM <http://demo.openlinksw.com/DAV/home/demo/rdf_sink/> WHERE {?s ?p ?o}" http://demo.openlinksw.com/sparql
]]></programlisting>
<para>The result should be:</para>
<programlisting><![CDATA[
<?xml version="1.0" ?>
<sparql xmlns="http://www.w3.org/2005/sparql-results#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">
<head>
<variable name="p"/>
</head>
<results distinct="false" ordered="true">
<result>
<binding name="p"><uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/nick</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/name</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/homepage</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/knows</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/workplaceHomepage</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/mbox</uri></binding>
</result>
</results>
</sparql>
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlendpointexamples2"><title>Other Examples of SPARQL query issued via curl</title>
<para><emphasis>Further example SPARQL queries:</emphasis></para>
<programlisting><![CDATA[
curl -F "query=SELECT DISTINCT ?Concept FROM <http://dbpedia.org> WHERE {?s a ?Concept} LIMIT 10" http://dbpedia.org/sparql
]]></programlisting>
<programlisting><![CDATA[
curl -F "query=SELECT DISTINCT ?Concept FROM <http://myopenlink.net/dataspace/person/kidehen> WHERE {?s a ?Concept} LIMIT 10" http://demo.openlinksw.com/sparql
]]></programlisting>
<programlisting><![CDATA[
curl -F "query=SELECT DISTINCT ?Concept FROM <http://data.openlinksw.com/oplweb/product_family/virtuoso> WHERE {?s a ?Concept} LIMIT 10" http://demo.openlinksw.com/sparql
]]></programlisting>
<programlisting><![CDATA[
curl -F "query=SELECT DISTINCT ?Concept FROM <http://openlinksw.com/dataspace/organization/openlink> WHERE {?s a ?Concept} LIMIT 10" http://demo.openlinksw.com/sparql
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlendpointexamples3"><title>Example with curl and SPARQL-SSL endpoint</title>
<programlisting><![CDATA[
$ curl -H "Accept: text/rdf+n3" --cert test.pem -k https://demo.openlinksw.com/dataspace/person/demo
Enter PEM pass phrase: *****
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/demo%27s%20AddressBook/1046#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
ns1:this rdf:type foaf:Person .
@prefix ns3: <http://www.pipian.com/rdf/tami/juliette.n3#> .
ns3:juliette rdf:type foaf:Document .
@prefix ns4: <https://demo.openlinksw.com/dataspace/person/> .
ns4:demo rdf:type foaf:PersonalProfileDocument .
@prefix ns5: <https://demo.openlinksw.com/dataspace/person/demo#> .
@prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> .
ns5:based_near rdf:type geo:Point .
@prefix ns7: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/demo%27s%20AddressBook/1042#> .
ns7:this rdf:type foaf:Person .
ns5:this rdf:type foaf:Person .
@prefix ns8: <https://demo.openlinksw.com/dataspace/person/demo/online_account/> .
@prefix sioc: <http://rdfs.org/sioc/ns#> .
ns8:demo rdf:type sioc:User .
@prefix ns10: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/myAddressBook/1001#> .
ns10:this rdf:type foaf:Person .
@prefix ns11: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/demo%27s%20AddressBook/1045#> .
ns11:this rdf:type foaf:Person .
@prefix ns12: <https://demo.openlinksw.com/dataspace/demo#> .
ns12:this rdf:type sioc:User .
ns5:org rdf:type foaf:Organization .
@prefix ns13: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/demo%27s%20AddressBook/1048#> .
ns13:this rdf:type foaf:Person .
@prefix ns14: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/myAddressBook/1001#this#> .
ns14:org rdf:type foaf:Organization .
@prefix ns15: <https://demo.openlinksw.com/dataspace/person/imitko#> .
ns15:this rdf:type foaf:Person .
@prefix ns16: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/myAddressBook/1049#> .
ns16:this rdf:type foaf:Person .
@prefix ns17: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/myAddressBook/1000#> .
ns17:this rdf:type foaf:Person .
ns8:MySpace rdf:type sioc:User .
@prefix ns18: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/demo%27s%20AddressBook/1044#> .
ns18:this rdf:type foaf:Person .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
ns4:demo dc:title "demo demo's FOAF file" .
ns14:org dc:title "OpenLink" .
ns5:org dc:title "OpenLink" .
ns18:this foaf:name "Kingsley Idehen" .
ns13:this foaf:name "Juliette" .
ns17:this foaf:name "Kingsley Idehen" .
ns5:this foaf:name "demo demo" .
ns15:this foaf:name "Mitko Iliev" .
ns10:this foaf:name "test test12" .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ns5:this rdfs:seeAlso ns4:demo .
ns15:this rdfs:seeAlso ns4:imitko .
ns4:demo foaf:maker ns5:this .
ns15:this foaf:nick "imitko" .
ns7:this foaf:nick "Orri Erling" .
ns13:this foaf:nick "Juliette" .
ns10:this foaf:nick "test1" .
ns5:this foaf:nick "demo" .
ns18:this foaf:nick "Kingsley" .
ns17:this foaf:nick "Kingsley" .
ns16:this foaf:nick "test2" .
ns1:this foaf:nick "TEST" .
ns11:this foaf:nick "TEST" .
ns5:this foaf:holdsAccount ns8:demo ,
ns8:MySpace ,
ns12:this .
@prefix ns21: <http://myopenlink.net/dataspace/person/imitko#> .
ns5:this foaf:knows ns21:this ,
ns17:this ,
ns16:this ,
ns3:juliette ,
ns10:this ,
ns7:this .
@prefix ns22: <http://myopenlink.net/dataspace/person/kidehen#> .
ns5:this foaf:knows ns22:this ,
ns18:this ,
ns11:this ,
ns1:this .
@prefix ns23: <http://bblfish.net/people/henry/card#me\u0020> .
ns5:this foaf:knows ns23: ,
ns13:this ,
ns15:this ;
foaf:firstName "demo" ;
foaf:family_name "demo" ;
foaf:gender "male" ;
foaf:icqChatID "125968" ;
foaf:msnChatID "45demo78" ;
foaf:aimChatID "demo1234" ;
foaf:yahooChatID "demo678" ;
foaf:based_near ns5:based_near .
@prefix ns24: <http://www.openlinksw.com> .
ns5:this foaf:workplaceHomepage ns24: .
ns5:org foaf:homepage ns24: .
ns5:this foaf:homepage ns24: .
ns14:org foaf:homepage ns24: .
ns4:demo foaf:primaryTopic ns5:this .
ns5:based_near geo:lat "47.333332" ;
geo:long "13.333333" .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <https://demo.openlinksw.com/dataspace/demo#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
ns1:this rdf:type foaf:OnlineAccount .
@prefix ns3: <https://demo.openlinksw.com/dataspace/person/demo/online_account/> .
ns3:MySpace rdf:type foaf:OnlineAccount .
ns3:demo rdf:type foaf:OnlineAccount .
@prefix ns4: <https://demo.openlinksw.com/dataspace/person/demo#> .
ns4:this foaf:holdsAccount ns3:MySpace ,
ns1:this ,
ns3:demo .
@prefix vcard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
ns4:this vcard:ADR ns4:addr .
ns4:addr vcard:Country "United States" ;
vcard:Locality "New York" ;
vcard:Region "Nebraska" .
@prefix ns6: <http://myspace.com> .
ns3:MySpace foaf:accountServiceHomepage ns6: .
@prefix ns7: <skype:demo?> .
ns3:demo foaf:accountServiceHomepage ns7:chat ;
foaf:accountName "demo" .
ns3:MySpace foaf:accountName "MySpace" .
@prefix ns8: <http://vocab.org/bio/0.1/> .
ns4:this ns8:olb "this is short resume of user Demo." .
@prefix ns9: <https://demo.openlinksw.com/dataspace/> .
ns4:this foaf:openid ns9:demo ;
ns8:keywords "demo, openlinksw, virtuoso, weblog, rdf" .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ns1: <https://demo.openlinksw.com/dataspace/demo/subscriptions/> .
@prefix ns2: <https://demo.openlinksw.com/dataspace/person/demo#> .
ns1:DemoFeeds foaf:maker ns2:this .
@prefix ns3: <https://demo.openlinksw.com/dataspace/demo/community/> .
ns3:demoCommunity foaf:maker ns2:this .
@prefix ns4: <https://demo.openlinksw.com/dataspace/demo/eCRM/demo%27s%20eCRM> .
ns4: foaf:maker ns2:this .
@prefix ns5: <https://demo.openlinksw.com/dataspace/demo/calendar/> .
ns5:mycalendar foaf:maker ns2:this .
@prefix ns6: <https://demo.openlinksw.com/dataspace/demo/photos/> .
ns6:MyGallery foaf:maker ns2:this .
@prefix ns7: <https://demo.openlinksw.com/dataspace/demo/briefcase/> .
ns7:mybriefcase foaf:maker ns2:this .
@prefix ns8: <https://demo.openlinksw.com/dataspace/demo/wiki/> .
ns8:ESBWiki foaf:maker ns2:this .
@prefix ns9: <https://demo.openlinksw.com/dataspace/demo/bookmark/> .
ns9:mybookmarks foaf:maker ns2:this .
@prefix ns10: <https://demo.openlinksw.com/dataspace/demo/weblog/> .
ns10:myblog foaf:maker ns2:this .
@prefix ns11: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/demo%27s%20AddressBook> .
ns11: foaf:maker ns2:this .
@prefix ns12: <https://demo.openlinksw.com/dataspace/demo/community/demo%27s%20Community> .
ns12: foaf:maker ns2:this .
ns8:mywiki foaf:maker ns2:this .
@prefix ns13: <https://demo.openlinksw.com/dataspace/demo/eCRM/demo%20demo%27s%20eCRM> .
ns13: foaf:maker ns2:this .
@prefix ns14: <https://demo.openlinksw.com/dataspace/demo/polls/> .
ns14:mypolls foaf:maker ns2:this .
@prefix ns15: <https://demo.openlinksw.com/dataspace/demo/socialnetwork/> .
ns15:myAddressBook foaf:maker ns2:this .
ns3:SP2 foaf:maker ns2:this .
ns2:this foaf:made ns11: ,
ns4: ,
ns3:demoCommunity ,
ns12: ,
ns15:myAddressBook ,
ns10:myblog ,
ns9:mybookmarks ,
ns7:mybriefcase ,
ns5:mycalendar ,
ns14:mypolls ,
ns8:mywiki ,
ns1:DemoFeeds ,
ns8:ESBWiki ,
ns6:MyGallery ,
ns3:SP2 ,
ns13: .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ns9:mybookmarks rdfs:label "demo demo's Bookmarks" .
ns15:myAddressBook rdfs:label "demo demo's AddressBook" .
ns4: rdfs:label "demo demo's eCRM" .
ns12: rdfs:label "demo's Community" .
ns14:mypolls rdfs:label "demo demo's Polls" .
ns13: rdfs:label "demo demo's eCRM Description" .
ns8:mywiki rdfs:label "demo demo's Wiki" .
ns7:mybriefcase rdfs:label "demo demo's Briefcase" .
ns1:DemoFeeds rdfs:label "demo demo's Feeds" .
ns10:myblog rdfs:label "demo's Weblog" .
ns5:mycalendar rdfs:label "demo demo's Calendar" .
ns11: rdfs:label "demo demo's AddressBook" .
ns6:MyGallery rdfs:label "demo demo's Gallery" .
ns8:ESBWiki rdfs:label "demo demo's Wiki" .
ns3:demoCommunity rdfs:label "demo demo's Community" .
ns3:SP2 rdfs:label "demo demo's Community" .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <https://demo.openlinksw.com/dataspace/person/demo#> .
@prefix ns2: <http://www.w3.org/ns/auth/rsa#> .
ns1:cert rdf:type ns2:RSAPublicKey .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix ns4: <https://demo.openlinksw.com/dataspace/person/demo/projects#ods%20project> .
ns4: dc:title "ods project" .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
ns4: foaf:maker ns1:this .
ns1:this foaf:made ns4: .
@prefix ns6: <http://www.w3.org/ns/auth/cert#> .
ns1:cert ns6:identity ns1:this ;
ns2:modulus ns1:cert_mod .
ns1:cert_mod ns6:hex "b8edefa13092d05e85257d6be0aca54218091278583f1d18759c4bced0007948fa6e920018abc3c30b8885d303ec2e679f3a7c15036d38452ddd9ebfcbb41
e1bd08dca66b7737b744fd9e441ebefa425311363711714cd0fe3b334a79ce50be9eb3443193bcbf2f1486481e775382f1a1792a2a8438543ca6f478c3b13c5db2a7f9a12a9a5aed5ec498
6be0169a1859d027170812a28914d158fb76a5933f11777a06c8db64d10f7c02900c4bb4bbf2d24c0e34c6ca135fdb5e05241bc029196ceef13a2006f07d1800f17762c0cfe05b3dac3042
09e1b7a3973122e850e96fcd0396544f82f0b11a46f0d868ba0f3d8efd957e7ef224871905a06c3c5d85ac9" .
ns1:cert ns2:public_exponent ns1:cert_exp .
ns1:cert_exp ns6:decimal "65537" .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <https://demo.openlinksw.com/dataspace/person/demo#> .
@prefix ns2: <http://vocab.org/bio/0.1/> .
ns1:event rdf:type ns2:Birth .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix ns4: <mailto:demo@openlinksw.com> .
ns1:this foaf:mbox ns4: ;
foaf:birthday "01-01" .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
ns1:event dc:date "1968-01-01" .
ns1:this ns2:event ns1:event .
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlendpointexamples4"><title>Example with curl and SPARQL-OAuth endpoint</title>
<para>Note: this is just an example as token had expired already. You can go to <link linkend="sparqloauthendpoint">this</link> section to see how to interact with our Virtuoso UI.</para>
<programlisting><![CDATA[
$ curl "http://demo.openlinksw.com/oauth/sparql.vsp?debug=on&default-graph-uri=&format=text%2Fhtml&oauth_consumer_key=27f105a327f5f23163e0636f78901
8dacdd70bb5&oauth_nonce=a14d43339fcb2638&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1242106643&oauth_token=42e2af4d9264ef42521c1010aff99f60a8
ee95a2&oauth_version=1.0&query=select%20distinct%20%3FURI%20%3FObjectType%20where%20%7B%3FURI%20a%20%3FObjectType%7D%20limit%2050&oauth_signature=C
w9yJ2saU1vgHuFxWcughai5cZY%3D"
<table class="sparql" border="1">
<tr>
<th>URI</th>
<th>ObjectType</th>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-nonblank</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-nonblank-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarchar</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarchar-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarbinary</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarbinary-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-uri</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-uri-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-uri</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-uri-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-doubleprecision</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-doubleprecision-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-date</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-date-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-datetime</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-datetime-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#multipart-uri</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#multipart-uri-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#multipart-uri-fn-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#multipart-literal-fn-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-uri-fn</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-uri-fn-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-uri-fn</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-uri-fn-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-literal-fn</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-literal-fn-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-literal-fn</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-integer-literal-fn-nullable</td>
<td>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</td>
</tr>
<tr>
<td>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</td>
<td>http://www.w3.org/1999/02/22-rdf-syntax-ns#Property</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-nullable-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-nonblank-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-iid-nonblank-nullable-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#default-nullable-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-nullable-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarchar-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarchar-nullable-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarbinary-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-longvarbinary-nullable-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
<tr>
<td>http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-uri-SuperFormats</td>
<td>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</td>
</tr>
</table>
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlendpointexamples5"><title>Example with CONSTRUCT</title>
<para>Go to the sparql endpoint UI: i.e. go to http://host:port/sparql</para>
<para>For the Default Graph URI enter: http://www.w3.org/2001/sw/DataAccess/proto-tests/data/construct/simple-data.rdf</para>
<para>Select "Retrieve remote RDF data for all missing source graphs".</para>
<para>For the query text enter:</para>
<programlisting>
SELECT * WHERE {?s ?p ?o}
</programlisting>
<para>Click the "Run Query" button.</para>
<para>The query results, shown below, are cached locally (sponged). The remote RDF data is saved in the local RDF quad store as graph http://www.w3.org/2001/sw/DataAccess/proto-tests/data/construct/simple-data.rdf</para>
<programlisting>
s p o
http://www.example/jose/foaf.rdf#jose http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/nick Jo
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/name Jose Jimen~ez
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/knows http://www.example/jose/foaf.rdf#juan
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/homepage http://www.example/jose/
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/workplaceHomepage http://www.corp.example/
http://www.example/jose/foaf.rdf#kendall http://xmlns.com/foaf/0.1/knows http://www.example/jose/foaf.rdf#edd
http://www.example/jose/foaf.rdf#julia http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.example/jose/foaf.rdf#julia http://xmlns.com/foaf/0.1/mbox mailto:julia@mail.example
http://www.example/jose/foaf.rdf#juan http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.example/jose/foaf.rdf#juan http://xmlns.com/foaf/0.1/mbox mailto:juan@mail.example
</programlisting>
<para>Now let's take the CONSTRUCT query:</para>
<programlisting><![CDATA[
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX myfoaf: <http://www.example/jose/foaf.rdf#>
CONSTRUCT
{ myfoaf:jose foaf:depiction <http://www.example/jose/jose.jpg>.
myfoaf:jose foaf:schoolHomepage <http://www.edu.example/>.
?s ?p ?o.
}
FROM <http://www.w3.org/2001/sw/DataAccess/proto-tests/data/construct/simple-data.rdf>
WHERE
{
?s ?p ?o. myfoaf:jose foaf:nick "Jo".
FILTER ( ! (?s = myfoaf:kendall && ?p = foaf:knows && ?o = myfoaf:edd )
&& ! ( ?s = myfoaf:julia && ?p = foaf:mbox && ?o = <mailto:julia@mail.example> )
&& ! ( ?s = myfoaf:julia && ?p = rdf:type && ?o = foaf:Person))
}
]]></programlisting>
<para>From an HTTP client, issue the GET command with the above query added as a URL-encoded parameter value:</para>
<programlisting><![CDATA[
GET -e -s http://host:port/sparql/?query=PREFIX+rdf%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23%3E%0D%0APREFIX+foaf%3A+%3Chttp%3A%2F%2Fxmlns.com%2Ffoaf%2F0.1%2F%3E%0D%0APREFIX+myfoaf%3A+%3Chttp%3A%2F%2Fwww.example%2Fjose%2Ffoaf.rdf%23%3E%0D%0A%0D%0ACONSTRUCT+%7B+myfoaf%3Ajose+foaf%3Adepiction+%3Chttp%3A%2F%2Fwww.example%2Fjose%2Fjose.jpg%3E.%0D%0A++++++++++++myfoaf%3Ajose+foaf%3AschoolHomepage+%3Chttp%3A%2F%2Fwww.edu.example%2F%3E.%0D%0A++++++++++++%3Fs+%3Fp+%3Fo.%7D%0D%0AFROM+%3Chttp%3A%2F%2Fwww.w3.org%2F2001%2Fsw%2FDataAccess%2Fproto-tests%2Fdata%2Fconstruct%2Fsimple-data.rdf%3E%0D%0AWHERE+%7B+%3Fs+%3Fp+%3Fo.+myfoaf%3Ajose+foaf%3Anick+%22Jo%22.%0D%0A+++++++FILTER+%28+%21+%28%3Fs+%3D+myfoaf%3Akendall+%26%26+%3Fp+%3D+foaf%3Aknows+%26%26+%3Fo+%3D+myfoaf%3Aedd+%29%0D%0A++++++++++++++%26%26+%21+%28+%3Fs+%3D+myfoaf%3Ajulia+%26%26+%3Fp+%3D+foaf%3Ambox+%26%26+%3Fo+%3D+%3Cmailto%3Ajulia%40mail.example%3E+%29%0D%0A++++++++++%26%26+%21+%28+%3Fs+%3D+myfoaf%3Ajulia+%26%26+%3Fp+%3D+rdf%3Atype+%26%26+%3Fo+%3D+foaf%3APerson%29%29%0D%0A%7D%0D%0A&format=application%2Frdf%2Bxml
]]></programlisting>
<para>The request response will be similar to:</para>
<programlisting><![CDATA[
200 OK
Connection: close
Date: Fri, 28 Dec 2007 10:06:14 GMT
Accept-Ranges: bytes
Server: Virtuoso/05.00.3023 (Win32) i686-generic-win-32 VDB
Content-Length: 2073
Content-Type: application/rdf+xml; charset=UTF-8
Client-Date: Fri, 28 Dec 2007 10:06:14 GMT
Client-Peer: 83.176.40.177:port
Client-Response-Num: 1
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#juan"><ns0pred:mbox xmlns:ns0pred="http://xmlns.com/foaf/0.1/" rdf:resource="mailto:juan@mail.example"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:schoolHomepage xmlns:ns0pred="http://xmlns.com/foaf/0.1/" rdf:resource="http://www.edu.example/"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:type xmlns:ns0pred="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="http://xmlns.com/foaf/0.1/Person"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:homepage xmlns:ns0pred="http://xmlns.com/foaf/0.1/" rdf:resource="http://www.example/jose/"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#juan"><ns0pred:type xmlns:ns0pred="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="http://xmlns.com/foaf/0.1/Person"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:workplaceHomepage xmlns:ns0pred="http://xmlns.com/foaf/0.1/" rdf:resource="http://www.corp.example/"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:nick xmlns:ns0pred="http://xmlns.com/foaf/0.1/">Jo</ns0pred:nick></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:depiction xmlns:ns0pred="http://xmlns.com/foaf/0.1/" rdf:resource="http://www.example/jose/jose.jpg"/></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:name xmlns:ns0pred="http://xmlns.com/foaf/0.1/">Jose Jime?+ez</ns0pred:name></rdf:Description>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#jose"><ns0pred:knows xmlns:ns0pred="http://xmlns.com/foaf/0.1/" rdf:resource="http://www.example/jose/foaf.rdf#juan"/></rdf:Description>
</rdf:RDF>
Done
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlendpointexamples6"><title>Example with extraction part of literal as variable</title>
<para>The following example shows how to extract a part of a literal as a variable for
use in a numeric comparison using SPARQL</para>
<para>Suppose there are the following triples inserted:</para>
<programlisting><![CDATA[
SQL>SPARQL INSERT INTO GRAPH <http://mygraph.com> { <:a>
<:p>
"123 abc" };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 30 msec.
SQL>SPARQL INSERT INTO GRAPH <http://mygraph.com> { <:a>
<:p>
"234 abc" };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 0 msec.
]]></programlisting>
<para>In order to extract the numeric part, and then do a numeric (<.>,=), you can use
atoi (), atol or atof in the filter:</para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://mygraph.com>
WHERE
{
?s ?p ?o . filter (bif:atoi (?o) > 130)
};
s p o
VARCHAR VARCHAR VARCHAR
___________________________________
:a :p 234 abc
1 Rows. -- 10 msec.
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlendpointexamples7"><title>Example how to define rule</title>
See details <link linkend="rdfsparqlruleexamples">here</link> how to define rule context that is
initialized from the contents of a given graph.
</sect4>
</sect3>
<sect3 id="rdfsparqlendpointimplnotes"><title>Implementation Notes</title>
<para>This service has been implemented using <ulink url="http://docs.openlinksw.com/virtuoso">Virtuoso Server</ulink>.</para>
</sect3>
<sect3 id="rdftables"><title>Virtuoso 'Semantic Bank' End Point</title>
<para>
<emphasis>What is Piggy Bank?</emphasis>
</para>
<para>
Piggy Bank is an extension to the Firefox Web browser that turns it into a Semantic Web browser, letting you make use of existing information on the Web in more useful and flexible ways not offered by the original Web sites.
</para>
<para></para>
<para>
<emphasis>What is Semantic Bank?</emphasis>
</para>
<para>
Semantic Bank is the server companion of Piggy Bank that lets you persist, share and publish data collected by individuals, groups or communities. Here is a screen shot of one in action:
</para>
<para>
<emphasis>What can I do with this?</emphasis>
</para>
<para>
A Semantic Bank allows you to:
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>
Persist your information remotely on a server - This is useful, for example, if you want to share data between two of your computers or to avoid losing it due to mistakes or failure.
</listitem>
<listitem>
Share information with other people - The ability to tag resources creates a powerful serendipitous categorization (as proven by things like del.icio.us or Flickr).
</listitem>
<listitem>
Lets you publish your information - Both in the "pure" RDF form (for those who know how to make use of it) or to regular web pages, with the usual Longwell faceted browsing view of it
</listitem>
</itemizedlist>
<para>
<emphasis>How can I help?</emphasis>
</para>
<para>
Semantic Bank is Open Source software and built around the spirit of open participation and collaboration.
</para>
<para>
There are several ways you can help:
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Install a Semantic Bank and let us know about it, so that we can update the list of available Semantic Banks.</listitem>
<listitem>Subscribe to our mailing lists to show your interest and give us feedback</listitem>
<listitem>Report problems and ask for new features through our issue tracking system.</listitem>
<listitem>Send us patches or fixes to the code</listitem>
</itemizedlist>
<para>
<emphasis>Licensing and Legal Issues</emphasis>
</para>
<para>
Semantic Bank is open source software and is licensed under the BSD license.
</para>
<para>
<emphasis>Note</emphasis>, however, that this software ships with libraries that are not released under the same license; that we interpret their licensing terms to be compatible with ours and that we are redistributing them unmodified. For more information on the licensing terms of the libraries Semantic Bank depends on, please refer to the source code.
</para>
<para>
<emphasis>Download location:</emphasis>
</para>
<para>
<ulink url="http://simile.mit.edu/dist/semantic-bank/">"http://simile.mit.edu/dist/semantic-bank/</ulink>
</para>
<para>
<emphasis>The Virtuoso Semantic Bank End Point</emphasis>
</para>
<para>
Before you can publish, you must register with one or more Semantic Banks:
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Invoke the menu command Tools > Piggy Bank > My Semantic Bank Accounts ...</listitem>
<listitem>Click Add... in the Semantic Bank Accounts dialog box.</listitem>
<listitem>In the popup dialog box, type in the URL to the Virtuoso Semantic Bank you want to register with. Example: http://server_name:server_port/bank</listitem>
<listitem>Enter the account of a valid Virtuoso DAV user. (Note: currently we do not use encryption during authentication; do not use your precious password here.)</listitem>
<listitem>Click OK, wait for the account to be registered, and then dismiss the Semantic Bank Accounts dialog box.</listitem>
<listitem>To publish an item, just click the corresponding Publish button (much like how you save the item). To publish all the items being viewed, click the Publish All button.</listitem>
</itemizedlist>
<para>
<emphasis>What is the graph name used by Virtuoso for the triples from PiggyBank?</emphasis>
</para>
<para>
http://simile.org/piggybank/<piggybank-generated-name>
</para>
<para>
The piggybank-generated-name is a Virtuoso DAV user ID.
</para>
</sect3>
<sect3 id="rdfsparqlexnpointnorthwindexample"><title>Making RDF Views Dereferenceable - Northwind Example</title>
<para>Consider an application that makes some relational data available for SPARQL requests, as described in the <link linkend="rdfviewnorthwindexample1">first part of the Northwind RDF View example</link>. This may be sufficient for some clients but the IRIs of the described subjects are not dereferenceable.
This means that external SPARQL processors cannot retrieve that data using the Virtuoso Sponger or the like. It also means that if some external resources refer to the IRI of
some Northwind subject and a user browses that resource then he cannot look at the application's data by clicking on the subject link.</para>
<para>To make RDF access complete, applications can do the following:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Create a virtual directory</listitem>
<listitem>Instruct the server how to prepare RDF resources on demand</listitem>
<listitem>Configure rendering of RDF resources for non-RDF clients (including Web search engines)</listitem>
<listitem>Make the used ontology available</listitem>
<listitem>Provide an index or sitemap page to help users who try to browse published data but do not know the proper URLs</listitem>
</itemizedlist>
<para>The following sequence of operations demonstrates how to implement the listed features without writing any special web pages.
All requests (except the application-specific index/sitemap) will be handled by existing web service endpoints.</para>
<para>As a precaution, we erase any URL rewriting rule lists created by this example that may be in the database following a previous run of the script.</para>
<programlisting><![CDATA[
DB.DBA.URLREWRITE_DROP_RULELIST ('demo_nw_rule_list1', 1)
;
]]></programlisting>
<para>Do the same for individual rewrite rules:</para>
<programlisting><![CDATA[
DB.DBA.URLREWRITE_DROP_RULE ('demo_nw_rule1', 1)
;
DB.DBA.URLREWRITE_DROP_RULE ('demo_nw_rule2', 1)
;
DB.DBA.URLREWRITE_DROP_RULE ('demo_nw_rule3', 1)
;
DB.DBA.URLREWRITE_DROP_RULE ('demo_nw_rule4', 1)
;
]]></programlisting>
<para>As a sanity check we ensure that there are no other similarly named rules:</para>
<programlisting><![CDATA[
SQL>SELECT signal ('WEIRD', sprintf ('Rewrite rule "%s" found', URR_RULE))
FROM DB.DBA.URL_REWRITE_RULE WHERE URR_RULE like 'demo_nw%'
;
]]></programlisting>
<para>Next we create URI rewrite rules based on regular expressions by calling <link linkend="fn_urlrewrite_create_regex_rule"><function>DB.DBA.URLREWRITE_CREATE_REGEX_RULE</function></link>, so the same path will be redirected to different places depending on the MIME types the client can accept.</para>
<para>
For a given input path, that is a URI identifying a particular Linked Data entity, the rewrite rule below generates an N3 or RDF/XML representation of the entity using a CONSTRUCT
query. (Note: In the regular expression identifying the Accept: MIME types this rule applies to, i.e. in rdf.n3 and rdf.xml, each period (.) replaces a literal character
because some SPARQL web clients published before the relevant W3C recommendations produce slightly incorrect "Accept:" strings.)
</para>
<programlisting><![CDATA[
SQL>DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'demo_nw_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/Northwind%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
]]></programlisting>
<note><para>The request URL for the SPARQL web service looks terrible because it is URL-encoded; the sprintf format string for it is even worse! The easiest way of composing
encoded strings of this sort is to use the Conductor UI for configuring the rewrite rules. Alternatively open the SPARQL endpoint page (assuming it supports a UI for entering queries, if no query string is specified), type in the desired CONSTRUCT or DESCRIBE statement into the web form (using some sample URI), execute it, cut the URL of the page with results
from the address line of the browser window, paste it into the script and then replace the host name with
<emphasis>^{URIQADefaultHost}^</emphasis>, every percent with double percent, the parts of the sample IRI to be substituted with <emphasis>%U</emphasis>; finally adjust the vector of replacement parameters so that its length is equal to the number of <emphasis>%U</emphasis> or other format specifiers in the template.</para></note>
<para>The next rule redirects to the RDF browser service to display a description of the subject URI and let the user explore related subjects.</para>
<programlisting><![CDATA[
SQL>DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'demo_nw_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/rdfbrowser/index.html?uri=http%%3A//^{URIQADefaultHost}^%U%%23this',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
]]></programlisting>
<para>This next rule removes any trailing slash from the input path. Note that <emphasis>\x24</emphasis> is the hex character code for the
end-of-line pattern <emphasis>$</emphasis>. It is written escaped because the dollar sign indicates the beginning of macro in ISQL.</para>
<programlisting><![CDATA[
SQL>DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'demo_nw_rule3',
1,
'(/[^#]*)/\x24',
vector('path'),
1,
'%s',
vector('path'),
null,
null,
0,
null
);
]]></programlisting>
<para>To configure the server to furnish the ontology underpinning the example Northwind RDF view, the procedure LOAD_NW_ONTOLOGY_FROM_DAV, listed
below, takes the ontology described in file /DAV/VAD/demo/sql/nw.owl and loads it into graph http://demo.openlinksw.com/schemas/NorthwindOntology/1.0/
in the local quad store. A rewrite rule is then created to query this graph when the input path identifies entities from this ontology.
</para>
<programlisting><![CDATA[
SQL>create procedure DB.DBA.LOAD_NW_ONTOLOGY_FROM_DAV()
{
declare content1, urihost varchar;
SELECT cast (RES_CONTENT as varchar) INTO content1 from WS.WS.SYS_DAV_RES WHERE RES_FULL_PATH = '/DAV/VAD/demo/sql/nw.owl';
DB.DBA.RDF_LOAD_RDFXML (content1, 'http://demo.openlinksw.com/schemas/northwind#', 'http://demo.openlinksw.com/schemas/NorthwindOntology/1.0/');
urihost := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
if (urihost = 'demo.openlinksw.com')
{
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/northwind');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/northwind', ppath=>'/DAV/VAD/demo/sql/nw.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/northwind#');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/northwind#', ppath=>'/DAV/VAD/demo/sql/nw.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
}
};
DB.DBA.LOAD_NW_ONTOLOGY_FROM_DAV();
drop procedure DB.DBA.LOAD_NW_ONTOLOGY_FROM_DAV;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'demo_nw_rule4',
1,
'/schemas/northwind#(.*)',
vector('path'),
1,
'/sparql?query=DESCRIBE%20%3Chttp%3A//demo.openlinksw.com/schemas/northwind%23%U%3E%20FROM%20%3Chttp%3A//demo.openlinksw.com/schemas/NorthwindOntology/1.0/%3E',
vector('path'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
]]></programlisting>
<para>Next we define virtual directory <emphasis>/Northwind</emphasis> and associate with this a rulelist containing the URL rewriting rules defined
above. Requests matching the rewriting rules should then be properly redirected to produce the requested data. Attempts to access the virtual directory
root will execute the application's default VSP page, namely <emphasis>sfront.vspx</emphasis>.</para>
<programlisting><![CDATA[
SQL>DB.DBA.URLREWRITE_CREATE_RULELIST (
'demo_nw_rule_list1',
1,
vector (
'demo_nw_rule1',
'demo_nw_rule2',
'demo_nw_rule3',
'demo_nw_rule4'
));
VHOST_REMOVE (lpath=>'/Northwind');
DB.DBA.VHOST_DEFINE (lpath=>'/Northwind', ppath=>'/DAV/home/demo/', vsp_user=>'dba', is_dav=>1, def_page=>'sfront.vspx',
is_brws=>0, opts=>vector ('url_rewrite', 'demo_nw_rule_list1'));
]]></programlisting>
<para>Finally, to register the namespace prefix <emphasis>northwind</emphasis> as persistent we execute:</para>
<programlisting><![CDATA[
SQL>DB.DBA.XML_SET_NS_DECL ('northwind', 'http://demo.openlinksw.com/schemas/northwind#', 2);
]]></programlisting>
</sect3>
<sect3 id="rdfproxyservice"><title>Sponger Proxy URI Service</title>
<para>
In certain cases, such as Ajax applications, it's prohibited to issue HTTP requests to a server other than the original server.
In other cases it is necessary to transform the content of a target to an RDF format. To this end Virtuoso Server provides a Sponger Proxy URI Service.
This service takes as an argument a target URL and may return the target's content "as is" or the Sponger may try to transform the content and return
an RDF representation of the target. When transforming to RDF, the RDF format (RDF/XML, N3, TURTLE etc) of the output can be forced by a URL parameter
or by content negotiation.
</para>
<para>
When the rdf_mappers package is installed, Virtuoso reserves the path '/about/[id|html|data|rdf]/http/' for the RDF
proxy service. In the current implementation, Virtuoso defines virtual directories for HTTP requests that
come to the port specified as 'ServerPort' in the '[HTTPServer]' section of Virtuoso configuration file
and refer to the above path string. So, if the Virtuoso installation on host example.com listens for HTTP
requests on port 8080, client applications should use the 'service endpoint' string equal to
'http://example.com:8080/about/[id|html|data|rdf]/http/'.
</para>
<para>
If the rdf_mappers VAD package is not installed, then the path '/proxy/rdf/' is used for the Sponger Proxy URI Service.
</para>
<para>
The old pattern for the Sponger Proxy URI Service, '/proxy/', is now deprecated.
</para>
<para>
<emphasis>Note:</emphasis> If you do not have the rdf_mappers package installed, in order for the Sponger Proxy URI Service to work correctly,
you must grant the SPARQL_UPDATE role to user SPARQL and grant execute permission on procedure RDF_SPONGE_UP.
</para>
<para>
To enable SPARQL_UPDATE using the Conductor UI:
</para>
<itemizedlist>
<listitem>Go to the Virtuoso Administration Conductor i.e. http://host:port/conductor</listitem>
<listitem>Login as dba user</listitem>
<listitem>Go to System Admin->User Accounts->Roles</listitem>
<figure id="rl1" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/cn1.png"/>
</figure>
<listitem>Click the link "Edit" for "SPARQL_UPDATE</listitem>
<listitem>Select from the list of available user/groups "SPARQL" and click the ">>" button so to add it to the right-positioned list.</listitem>
<figure id="rl2" float="1">
<title>Conductor UI</title>
<graphic fileref="ui/cn2.png"/>
</figure>
<listitem>Click the button "Update".</listitem>
</itemizedlist>
<para>
To grant execute permission on RDF_SPONGE_UP:
</para>
<programlisting><![CDATA[
grant execute on DB.DBA.RDF_SPONGE_UP to "SPARQL";
]]></programlisting>
<para>
When invoked with a URL of the form http://host:port/proxy?..., the Sponger Proxy URI Service accepts the following query string parameters:
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem><emphasis>force</emphasis> - if 'rdf' is specified, the Sponger will try to extract RDF data from the target and return it</listitem>
<listitem><emphasis>header</emphasis> - HTTP headers to be sent to the target</listitem>
<listitem><emphasis>output-format</emphasis> - if 'force=rdf' is given, designates the desired output MIME type of the RDF data. The default is 'rdf+xml'. Other supported MIME types are 'n3', 'turtle' or 'ttl'.</listitem>
</itemizedlist>
<para>
When RDF data is requested and 'output-format' is not specified, the result will be serialized with a MIME type determined by the request 'Accept' headers i.e. the proxy service will do content negotiation.
</para>
<para>Example: RDF file with URL: http://www.w3.org/People/Berners-Lee/card</para>
<programlisting><![CDATA[
-- Access the url in order to view the result in HTML format:
http://host:port/about/html/http/www.w3.org/People/Berners-Lee/card
-- Access the url in order to view the result in RDF:
http://host:port/about/rdf/http://www.w3.org/People/Berners-Lee/card
-- or use the following proxy invocation style:
http://host:port/proxy/rdf/http://www.w3.org/People/Berners-Lee/card
-- or this one:
http://host:port/proxy?url=http://www.w3.org/People/Berners-Lee/card&force=rdf
]]></programlisting>
<para>Note: It is not permitted, when using the style http://host:port/proxy/rdf, to pass URL query string parameters to the proxy. </para>
<para>Now go to the SPARQL endpoint, i.e. http://host:port/sparql</para>
<para>For the 'Default Graph URI' enter the URL of the RDF file: http://www.w3.org/People/Berners-Lee/card</para>
<para>For 'Query' enter:</para>
<programlisting><![CDATA[
SELECT *
WHERE
{
?s ?p ?o
}
]]></programlisting>
<para>Query result:</para>
<programlisting><![CDATA[
s p o
http://www.w3.org/People/Berners-Lee/card http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/PersonalProfileDocument
http://www.w3.org/People/Berners-Lee/card http://purl.org/dc/elements/1.1/title Tim Berners-Lee's FOAF file
http://www.w3.org/People/Berners-Lee/card http://creativecommons.org/ns#license http://creativecommons.org/licenses/by-nc/3.0/
http://www.w3.org/People/Berners-Lee/card http://xmlns.com/foaf/0.1/maker http://www.w3.org/People/Berners-Lee/card#i
etc ...
]]></programlisting>
</sect3>
<sect3 id="sparqliniservice"><title>SPARQL INI service</title>
<para>
The [SPARQL] section of the virtuoso.ini configuration file sets parameters and limits for the SPARQL query web service.
The values contained in the [SPARQL] section can be exposed in RDF form via the URL pattern http://cname/sparql?ini
</para>
<para>Example: http://demo.openlinksw.com/sparql?ini</para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:MaxQueryCostEstimationTime xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">1000</ns0pred:MaxQueryCostEstimationTime></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:ExternalXsltSource xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">1</ns0pred:ExternalXsltSource></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:DefaultQuery xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">SELECT ?Subject ?Concept WHERE {?Subject a ?Concept}</ns0pred:DefaultQuery></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:ResultSetMaxRows xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">100000</ns0pred:ResultSetMaxRows></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:MaxQueryExecutionTime xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">30</ns0pred:MaxQueryExecutionTime></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:ExternalQuerySource xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">1</ns0pred:ExternalQuerySource></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:DefaultGraph xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">http://demo.openlinksw.com/dataspace/person/demo</ns0pred:DefaultGraph></rdf:Description>
<rdf:Description rdf:about="http://www.openlinksw.com/schemas/virtini#SPARQL"><ns0pred:PingService xmlns:ns0pred="http://www.openlinksw.com/schemas/virtini#">http://rpc.pingthesemanticweb.com/</ns0pred:PingService></rdf:Description>
</rdf:RDF>
]]></programlisting>
</sect3>
<sect3 id="sparqlexcel"><title>SPARQL Endpoint with Excel MIME Type Output Option</title>
<para>The SPARQL endpoint offers an Excel MIME type output option.</para>
<para>From http://cname:host/sparql, select "Spreadsheet" for the "Display Results As:" option and click the "Run Query" button.</para>
<figure id="sparqlexcel1" float="1">
<title>SPARQL Endpoint with Excel MIME type output</title>
<graphic fileref="ui/Excel1.png"/>
</figure>
<para>The resulting query string contains a format parameter value of <emphasis>"application/vnd.ms-excel"</emphasis>. For example,
<ulink url="http://demo.openlinksw.com/sparql?default-graph-uri=http%3A%2F%2Fdemo.openlinksw.com%2Fdataspace%2Fperson%2Fdemo&should-sponge=&query=select+*%0D%0Awhere+%7B%3Fs+%3Fp+%3Fo%7D%0D%0Alimit+10&format=application%2Fvnd.ms-excel&debug=on">A URL such as this one</ulink> will be generated, and can be opened directly with Excel.</para>
<figure id="sparqlexcel2" float="1">
<title>SPARQL Endpoint with Excel MIME type output</title>
<graphic fileref="ui/Excel2.png"/>
</figure>
</sect3>
<sect3 id="sparqljson"><title>SPARQL Endpoint with RDF+JSON Output: SPARQL UI Example</title>
<para>The SPARQL endpoint also offers a RDF+JSON output option.</para>
<para>From http://cname:host/sparql select "JSON" for "Display Results As:" and click the "Run Query" button.</para>
<figure id="sparqljson1" float="1">
<title>SPARQL Endpoint with RDF+JSON output</title>
<graphic fileref="ui/JSON1.png"/>
</figure>
<para>As result URL containing as parameter the format <emphasis>application/sparql-results+json</emphasis> will be generated and the content should look like:</para>
<figure id="sparqljson2" float="1">
<title>SPARQL Endpoint with JSON+RDF</title>
<graphic fileref="ui/JSON2.png"/>
</figure>
</sect3>
<sect3 id="sparqljsonp"><title>SPARQL Endpoint with JSON/P Output Option: Curl Example</title>
<para>The SPARQL endpoint also offers a JSON/P output option.</para>
<para>The SPARQL endpoint accepts a 'callback' URL parameter and in this case
when parameter 'format' is 'json', then it will produce JSON/P output.</para>
<programlisting><![CDATA[
$ curl "http://lod.openlinksw.com/sparql?query=select+*+where+\{+%3Fx+a+%3Fz+.+\}+limit+10&format=json&debug=on&callback=func"
func(
{ "head": { "link": [], "vars": ["x", "z"] },
"results": { "distinct": false, "ordered": true, "bindings": [
{ "x": { "type": "bnode", "value": "nodeID://b196899188" } , "z": { "type": "uri", "value": "http://www.w3.org/2000/10/swap
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2005/04/sparqlette/#profile" } , "z": { "type": "uri", "value":
services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/#b-profile" } , "z": { "type": "uri",
aml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/#a-profile" } , "z": { "type": "uri",
aml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/index.rdf#a-profile" } , "z": { "type":
://www.daml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/index.rdf#b-profile" } , "z": { "type":
://www.daml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2006/06/blogmatrix/#profile" } , "z": { "type": "uri", "value":
services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/#b-profile" } , "z": { "type": "uri",
aml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/#a-profile" } , "z": { "type": "uri",
aml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }},
{ "x": { "type": "uri", "value": "http://www.wasab.dk/morten/2003/12/nearestAirport/#b-profile" } , "z": { "type": "uri",
aml.org/services/owl-s/1.1/Service.owl#ServiceProfile" }} ] } })
]]></programlisting>
</sect3>
</sect2>
<sect2 id="sparqldebug"><title>Troubleshooting SPARQL Queries</title>
<para>A short SPARQL query can be compiled into a long SQL statement,
especially if data comes from many quad map patterns. A moderately sized
application with 50 tables and 10 columns per table may create
thousands of quad map patterns for subjects spanning hundreds of different
types. An attempt to "select everything" from RDF view of
that complexity may easily create 5000 lines of SQL code. Thus it is
to be expected that some queries will be rejected even if the same
queries would work fine if the RDF data were held as physical quads in default storage, rather than synthesized through an RDF view.
</para>
<para>In addition, the SQL compiler catches typos efficiently, signalling an error if a table or column
name is unknown, efficiently catching typos. SPARQL uses IRIs that are
long and sometimes unreadable, but there is no "closed
world" schema of the data so a typo in an IRI is not an error; it
is simply some other IRI. So a typo in an IRI or in a namespace prefix
causes missing bindings of some triple patterns of the query and an
incomplete result, but usually no errors are reported. A typo in graph
or predicate IRI may cause the SPARQL compiler to generate code that
accesses default (quad) storage instead of a relational source or generate
empty code that accesses nothing.</para>
<para>The SQL compiler does not signal casting errors when it runs the
statement generated from SPARQL, because the generated SQL code
contains <emphasis>option (QUIETCAST)</emphasis>. This means that
mismatches between expected and actual datatypes of values stay
invisible and may cause rounding errors (e.g. integer division instead
of floating-point) and even empty joins (due to join conditions that
silently return NULL instead of returning a comparison error).</para>
<para>In other words, SPARQL queries are so laconic that there is no
room for details that let the compiler distinguish between intent
and a bug. This masks query complexity, misuse of names and
type mismatches. One may make debugging easier by making queries
longer.</para>
<para>Two very helpful debugging tools are automatic void variable
recognition and plain old code inspection. "Automatic" means
"cheap" so the very first step of debugging is to ensure
that every triple pattern of the query may in principle return
something. This helps in finding typos when the query gets data from
RDF views. It also helps when a query tries to join two disjoint
sorts of subjects. If the <emphasis>define sql:signal-void-variables
1</emphasis> directive is placed in the preamble of the SPARQL query,
the compiler will signal an error if it finds any triple pattern that cannot
bind variables or any variable that is proved to be always
unbound. This is especially useful when data are supposed to come from an
<emphasis>option (exclusive)</emphasis> or <emphasis>option (soft
exclusive)</emphasis> quad map. Without one of these options, the SPARQL
compiler will usually bind variables using "physical quads";
the table of physical quads may contain any rows that match any given
triple pattern; thus many errors will remain undiscovered. If the name
of a quad map pattern is known then it is possible to force the SPARQL
compiler to use only that quad map for the whole query or a
part of the query. This is possible by using the following syntax:</para>
<programlisting><![CDATA[
QUAD MAP quad-map-name { group-pattern }
]]></programlisting>
<para>If some triple pattern inside <emphasis>group-pattern</emphasis> cannot be bound using <emphasis>quad-map-name</emphasis> or one of its descendants then <emphasis>define sql:signal-void-variables 1</emphasis> will force the compiler to signal the error.</para>
<note><para>Although it is technically possible to use <emphasis>QUAD
MAP</emphasis> to improve the performance of a query that tries to
access redundant RDF Views, it is much better to achieve the same
effect by providing a more restrictive query or by changing/extending
the RDF View. If an application relies on this trick then interoperable third-party SPARQL
clients may experience problems because they cannot use Virtuoso-specific
extensions.</para></note>
<para>
If the automated query checking gives nothing, function <function>sparql_to_sql_text</function> can be used in order to get the SQL text generated from the given query.
Its only argument is the text of the SPARQL query to compile (without any leading SPARQL keyword or semicolon at the end). The returned value is the SQL text. The output may be long but it is the most authoritative source of diagnostic data.
</para>
<para>
When called from ISQL or an ODBC client, the return value of <function>sparql_to_sql_text</function> may be transferred as a BLOB so ISQL requires the "set blobs on" instruction to avoid data truncation. Even better, the SQL text can be saved to a file:
</para>
<programlisting><![CDATA[
string_to_file ('debug.sql', sparql_to_sql_text ('SELECT * WHERE { graph ?g { ?s a ?type }}'), -2);
]]></programlisting>
<para>(The -2 is to overwrite the previous version of the file, as this function may be called many times).</para>
<note><para>
When passing the query text to sparql_to_sql_text, if the query contains single quotes, each embedded single quote must be doubled up.
Use double quotes in SPARQL queries to avoid this inconvenience.
</para>
</note>
<para>As an example, let's find out why the query</para>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX northwind: <http://demo.openlinksw.com/schemas/northwind#>
SELECT DISTINCT ?emp
FROM <http://myhost.example.com/Northwind>
WHERE {
?order1 northwind:has_salesrep ?emp ; northwind:shipCountry ?country1 .
?order2 northwind:has_salesrep ?emp ; northwind:shipCountry ?country2 .
filter (?country1 != ?country2) }
]]></programlisting>
<para>is much slower than a similar SQL statement. The call of <function>sparql_to_sql_text</function> returns the equivalent SQL statement:</para>
<programlisting><![CDATA[
SELECT DISTINCT sprintf_iri ( 'http://myhost.example.com/Northwind/Employee/%U%U%d#this' ,
/*retval[*/ "s-6-1-t0"."b067b7d~FirstName~0" /* emp */ /*]retval*/ ,
/*retval[*/ "s-6-1-t0"."b067b7d~FirstName~1" /*]retval*/ ,
/*retval[*/ "s-6-1-t0"."b067b7d~FirstName~2" /*]retval*/ ) AS /*tmpl*/ "emp"
FROM (SELECT "s-6-1-t0-int~orders"."OrderID" AS /*tmpl*/ "20ffecc~OrderID",
"s-6-1-t0-int~employees"."FirstName" AS /*as-name-N*/ "b067b7d~FirstName~0",
"s-6-1-t0-int~employees"."LastName" AS /*as-name-N*/ "b067b7d~FirstName~1",
"s-6-1-t0-int~employees"."EmployeeID" AS /*as-name-N*/ "b067b7d~FirstName~2"
FROM Demo.demo.Employees AS "s-6-1-t0-int~employees", Demo.demo.Orders AS "s-6-1-t0-int~orders"
WHERE /* inter-alias join cond */
"s-6-1-t0-int~orders".EmployeeID = "s-6-1-t0-int~employees".EmployeeID) AS "s-6-1-t0",
(SELECT "s-6-1-t1-int~orders"."OrderID" AS /*tmpl*/ "20ffecc~OrderID",
"s-6-1-t1-int~orders"."ShipCountry" AS /*tmpl*/ "e45a7f~ShipCountry"
FROM Demo.demo.Orders AS "s-6-1-t1-int~orders") AS "s-6-1-t1",
(SELECT "s-6-1-t2-int~orders"."OrderID" AS /*tmpl*/ "20ffecc~OrderID",
"s-6-1-t2-int~employees"."FirstName" AS /*as-name-N*/ "b067b7d~FirstName~0",
"s-6-1-t2-int~employees"."LastName" AS /*as-name-N*/ "b067b7d~FirstName~1",
"s-6-1-t2-int~employees"."EmployeeID" AS /*as-name-N*/ "b067b7d~FirstName~2"
FROM Demo.demo.Employees AS "s-6-1-t2-int~employees", Demo.demo.Orders AS "s-6-1-t2-int~orders"
WHERE /* inter-alias join cond */
"s-6-1-t2-int~orders".EmployeeID = "s-6-1-t2-int~employees".EmployeeID) AS "s-6-1-t2",
(SELECT "s-6-1-t3-int~orders"."OrderID" AS /*tmpl*/ "20ffecc~OrderID",
"s-6-1-t3-int~orders"."ShipCountry" AS /*tmpl*/ "e45a7f~ShipCountry"
FROM Demo.demo.Orders AS "s-6-1-t3-int~orders") AS "s-6-1-t3"
WHERE /* two fields belong to same equiv */
/*retval[*/ "s-6-1-t0"."20ffecc~OrderID" /* order1 */ /*]retval*/ =
/*retval[*/ "s-6-1-t1"."20ffecc~OrderID" /* order1 */ /*]retval*/
AND /* two fields belong to same equiv */
sprintf_iri ( 'http://myhost.example.com/Northwind/Employee/%U%U%d#this' ,
/*retval[*/ "s-6-1-t0"."b067b7d~FirstName~0" /* emp */ /*]retval*/ ,
/*retval[*/ "s-6-1-t0"."b067b7d~FirstName~1" /*]retval*/ ,
/*retval[*/ "s-6-1-t0"."b067b7d~FirstName~2" /*]retval*/ ) =
sprintf_iri ( 'http://myhost.example.com/Northwind/Employee/%U%U%d#this' ,
/*retval[*/ "s-6-1-t2"."b067b7d~FirstName~0" /* emp */ /*]retval*/ ,
/*retval[*/ "s-6-1-t2"."b067b7d~FirstName~1" /*]retval*/ ,
/*retval[*/ "s-6-1-t2"."b067b7d~FirstName~2" /*]retval*/ )
AND /* two fields belong to same equiv */
/*retval[*/ "s-6-1-t2"."20ffecc~OrderID" /* order2 */ /*]retval*/ =
/*retval[*/ "s-6-1-t3"."20ffecc~OrderID" /* order2 */ /*]retval*/
AND /* filter */
( /*retval[*/ "s-6-1-t1"."e45a7f~ShipCountry" /* country1 */ /*]retval*/ <>
/*retval[*/ "s-6-1-t3"."e45a7f~ShipCountry" /* country2 */ /*]retval*/ )
OPTION (QUIETCAST)
]]></programlisting>
<para>The query is next to unreadable but some comments split it into meaningful expressions. Every triple (or list of similar triples) becomes a subquery that returns fields needed to build the values of bound variables. The fields are printed wrapped by comments like
<emphasis>/*retval[*/ expression /* original variable name */
/*]retval*/</emphasis>. Names like<emphasis>"s-6-1-t0"</emphasis>
contain the source line number where a group pattern begins (6) and the serial
number of the triple (0). Comment <emphasis>/* inter-alias join cond
*/</emphasis> means that the expression which follows is the condition as
written in the declaration of the quad map pattern. Comment
<emphasis>/* filter */</emphasis> precedes expressions for FILTER
expressions in the source SPARQL. The word "equiv" means
"equivalence class", i.e. a group of occurrences of variables
in the source query such that all occurrences are bound to the same
value. E.g. when a name repeats in many triples of a group, all its
occurrences form an equivalence class. In some cases the compiler can
prove that two variables are always equal even if the names differ - these
variables are also placed into an "equiv".</para>
<para>Looking at this query, you may notice equalities like
<emphasis>sprintf_iri (...) = sprintf_iri (...)</emphasis>. That is
sub-optimal because it indicates that no index will be used to optimize the join
and that there will be one function call per row. When the variable
<emphasis>?emp</emphasis> appears in two different triples, it means
that the value of the variable is the same in both triples. The query
compares IRIs instead of comparing the arguments of <link
linkend="fn_sprintf_iri"><function>sprintf_iri</function></link>
because the format string is not proven to be a bijection. Indeed it
cannot be a bijection for <emphasis>arbitrary</emphasis> strings, but the database must reflect the
real world. If it is assumed that the real names of persons never start with a
digit, within the <emphasis>%d%U</emphasis> format fragment, the digits will always
be distinguishable from the name; so the IRI class can be declared as a
bijection even if it is not true for arbitrary strings. The script
can then include "suspicious" <emphasis>option (bijection)</emphasis> as
follows:</para>
<programlisting><![CDATA[
create iri class sample:Employee "http://example.com/Employee/%d%U#this"
(in employee_id integer not null, in employee_lastname varchar not null)
option (bijection) .
]]></programlisting>
<para>Unfortunately, attempts to use the same trick with the declaration from the Northwind example will fail:</para>
<programlisting><![CDATA[
create iri class northwind:Employee "http://^{URIQADefaultHost}^/Northwind/Employee/%U%U%d#this"
(in employee_firstname varchar not null, in employee_lastname varchar not null, in employee_id integer not null)
option (bijection) .
]]></programlisting>
<para>Bijection will allow the parsing, but it will never give the proper result, because the first <emphasis>%U</emphasis> will read the whole concatenation of <emphasis>%U%U%d</emphasis>, leaving nothing before the<emphasis>#this</emphasis> for the second <emphasis>%U</emphasis> (this is an error) and
leaving nothing for the <emphasis>%d</emphasis> (that is an explicit parse error, becauses the integer field cannot be empty).</para>.
<para>The string parser will process the string from left to right so it will be unable to parse the string.
The compiler might sometimes report an error if it can prove that the format string is not appropriate for bijection.</para>
<para>The correct way of improving the Northwind example is to enable reliable bijection by adding strong delimiters:</para>
<programlisting><![CDATA[
create iri class northwind:Employee "http://^{URIQADefaultHost}^/Northwind/Employee/%U/%U/%d#this"
(in employee_firstname varchar not null, in employee_lastname varchar not null, in employee_id integer not null)
option (bijection) .
]]></programlisting>
<para>After running the updated script, the query contains three comparisons of fields that were arguments of <function>sprintf_iri</function> in the previous version.</para>
<para><emphasis>Example for casting string as IRI type</emphasis></para>
<programlisting><![CDATA[
create function DB.DBA.RDF_DF_GRANTEE_ID_URI (in id integer)
{
declare isrole integer;
isrole := coalesce ((SELECT top 1 U_IS_ROLE FROM DB.DBA.SYS_USERS WHERE U_ID = id));
if (isrole is null)
return NULL;
else if (isrole)
return sprintf ('http://%s/sys/group?id=%d', registry_get ('URIQADefaultHost'), id);
else
return sprintf ('http://%s/sys/user?id=%d', registry_get ('URIQADefaultHost'), id);
}
;
grant execute on DB.DBA.RDF_DF_GRANTEE_ID_URI to SPARQL_SELECT
;
create function DB.DBA.RDF_DF_GRANTEE_ID_URI_INVERSE (in id_iri varchar)
{
declare parts any;
parts := sprintf_inverse (id_iri, sprintf ('http://%s/sys/user?id=%%d', registry_get ('URIQADefaultHost')), 1);
if (parts is not null)
{
if (exists (SELECT TOP 1 1 FROM DB.DBA.SYS_USERS WHERE U_ID = parts[0] and not U_IS_ROLE))
return parts[0];
}
parts := sprintf_inverse (id_iri, sprintf ('http://%s/sys/group?id=%%d', registry_get ('URIQADefaultHost')), 1);
if (parts is not null)
{
if (exists (SELECT TOP 1 1 FROM DB.DBA.SYS_USERS WHERE U_ID = parts[0] and U_IS_ROLE))
return parts[0];
}
return NULL;
}
;
grant execute on DB.DBA.RDF_DF_GRANTEE_ID_URI_INVERSE to SPARQL_SELECT
;
create iri class oplsioc:grantee_iri using
function DB.DBA.RDF_DF_GRANTEE_ID_URI (in id integer) returns varchar ,
function DB.DBA.RDF_DF_GRANTEE_ID_URI_INVERSE (in id_iri varchar) returns integer
option ( bijection ,
returns "http://^{URIQADefaultHost}^/sys/group?id=%d"
union "http://^{URIQADefaultHost}^/sys/user?id=%d" ) .
]]></programlisting>
</sect2>
<sect2 id="sparqlextensions"><title>Extensions</title>
<sect3 id="rdfsparqlrulefulltext"><title>Using Full Text Search in SPARQL</title>
<para>Virtuoso's triple store supports optional full text indexing of RDF object values since version 5.0.
It is possible to declare that objects of triples with a given predicate or graph get indexed.
The graphs and triples may be enumerated or a wildcard may be used.
</para>
<para>The triples for which a full text index entry exists can be found using the <emphasis>bif:contains</emphasis>
or related filters and predicates.
</para>
<para>For example, the query:
</para>
<programlisting>
SQL>SELECT *
FROM <people>
WHERE
{
?s foaf:Name ?name . ?name bif:contains "'rich*'".
}
</programlisting>
<para>would match all subjects whose <emphasis>foaf:Name</emphasis> contained a word starting with Rich.
This would match Richard, Richie etc.
</para>
<para>Note that words and phrases should be enclosed in quotes if they contain spaces or
other non-alphanumeric chars.
</para>
<para>If the <emphasis>bif:contains</emphasis> or related predicate is applied to an object that is not
a string or is not the object of an indexed triple, no match will be found.
</para>
<para>The syntax for text patterns is identical to the syntax for the SQL contains predicate.
</para>
<para>The SPARQL/SQL optimizer determines whether the text pattern will be used to drive the query or whether it
will filter results after other conditions are applied first. In contrast to <emphasis>bif:contains</emphasis>,
regexp matching never drives the query or makes use of an index, thus in practice regexps are checked after other conditions.
</para>
<sect4 id="rdfsparqlrulespecifywhatindex"><title>Specifying What to Index</title>
<para>Whether the object of a given triple is indexed in the text index depends on indexing rules. If at least one
indexing rule matches the triple, the object gets indexed if the object is a string. An indexing rule specifies
a graph and a predicate. Either may be an IRI or NULL, in which case it matches all IRI's.
</para>
<para>Rules also have a 'reason', which can be used to group rules into application-specific sets. A triple will stop
being indexed only after all rules mandating its indexing are removed. When an application requires indexing a
certain set of triples, rules are added for that purpose. These rules are tagged with the name of the application
as their reason. When an application no longer requires indexing, the rules belonging to this application can be
removed. This will not turn off indexing if another application still needs certain triples to stay indexed.
</para>
<para>Indexing is enabled/disabled for specific graph/predicate combinations with:
</para>
<programlisting>
create function DB.DBA.RDF_OBJ_FT_RULE_ADD
(in rule_g varchar, in rule_p varchar, in reason varchar) returns integer
</programlisting>
<programlisting>
create function DB.DBA.RDF_OBJ_FT_RULE_DEL
(in rule_g varchar, in rule_p varchar, in reason varchar) returns integer
</programlisting>
<para>The first function adds a rule. The first two arguments are the text representation of the IRI's for the graph
and predicate. If NULL is given then all graph's or predicates match. Specifying both as NULL means that all
string valued objects will be added to a text index.
</para>
<para>The second function reverses the effect of the first. Only a rule that has actually been added can be deleted.
Thus one cannot say that all except a certain enumerated set should be indexed.
</para>
<para>The reason argument is an arbitrary string identifying the application that needs this rule.
Two applications can add the same rule.
Removing one of them will still keep the rule in effect.
If an object is indexed by more than one rule, the index data remain free from duplicates, neither index size nor speed is affected.
</para>
<para>
If <emphasis>DB.DBA.RDF_OBJ_FT_RULE_ADD</emphasis> detects that <emphasis>DB.DBA.RDF_QUAD</emphasis> contains quads whose graphs and/or predicates match to the new rule but which have not been indexed before then these quads are indexed automatically.
However the function <emphasis>DB.DBA.RDF_OBJ_FT_RULE_DEL</emphasis> does not remove indexing data about related objects.
Thus the presence of indexing data about an object does not imply that it is necessarily used in some quad that matches to some rule.
</para>
<para>The above functions return one if the rule is added or deleted and zero if the call was redundant (the rule has been added before or there's no rule to delete).
</para>
<sect5 id="rdfsparqlrulespecifywhatindexexample"><title>Example</title>
<programlisting><![CDATA[
-- We load Tim Berners-Lee's FOAF file into a graph called 'people'.
SQL>DB.DBA.RDF_LOAD_RDFXML (http_get ('http://www.w3.org/People/Berners-Lee/card#i'), 'no', 'http://www.w3.org/people#');
Done. -- 172 msec.
-- We check how many triples we got.
SQL>SPARQL SELECT COUNT (*) FROM <http://www.w3.org/people#> WHERE {?s ?p ?o};
callret-0
INTEGER
266
No. of rows in result: 1
-- We check the GRAPH: <http://www.w3.org/people#> for objects like "Tim":
SQL>SPARQL
SELECT *
FROM <http://www.w3.org/people#>
WHERE
{
?s ?p ?o . FILTER (?o LIKE '%Tim%')
};
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/name Timothy Berners-Lee
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/nick TimBL
http://www.w3.org/People/Berners-Lee/card#i http://www.w3.org/2002/07/owl#sameAs http://www4.wiwiss.fu-berlin.de/bookmashup/persons/Tim+Berners-Lee
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://dbpedia.org/resource/Tim_Bray
http://www.w3.org/People/Berners-Lee/card#i http://www.w3.org/2000/01/rdf-schema#label Tim Berners-Lee
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/givenname Timothy
http://dbpedia.org/resource/Tim_Bray http://xmlns.com/foaf/0.1/name Tim Bray
no http://purl.org/dc/elements/1.1/title Tim Berners-Lee's FOAF file
8 Rows. -- 230 msec.
-- We specify that all string objects in the graph 'people' should be text indexed.
SQL>DB.DBA.RDF_OBJ_FT_RULE_ADD('http://www.w3.org/people#', null, 'people');
Done. -- 130 msec.
-- We update the text index.
SQL>DB.DBA.VT_INC_INDEX_DB_DBA_RDF_OBJ ();
Done. -- 140 msec.
-- See impact of the index by querying the subjects and predicates
-- of all triples in the GRAPH: <http://www.w3.org/people#>,
-- where the object is a string which contains a word beginning with "TIM".
SQL>SPARQL SELECT * FROM <http://www.w3.org/people#> WHERE { ?s ?p ?o . ?o bif:contains '"Timo*"'};
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/name Timothy Berners-Lee
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/givenname Timothy
2 Rows. -- 2 msec.
]]></programlisting>
<para>
The query below is identical with that above but uses a different syntax.
The filter syntax is more flexible in that it allows passing extra options to the <emphasis>contains</emphasis> predicate. These may be useful in the future.
</para>
<programlisting><![CDATA[
SQL>SPARQL SELECT * FROM <people> WHERE { ?s ?p ?o . FILTER (bif:contains(?o, '"Timo*"')) };
]]></programlisting>
</sect5>
<note><title>Note:</title><para>It is advisable to upgrade to the latest version of Virtuoso before adding free-text rules for the first time.
This is especially the case if large amounts of text are to be indexed. The reason is that the free-text index on RDF may be changed in future versions
and automatic upgrading of an existing index data into the new format may take much more time than indexing from scratch.</para></note>
<para>The table <emphasis>DB.DBA.RDF_OBJ_FT_RULES</emphasis> stores list of free-text index configuration rules.
</para>
<programlisting><![CDATA[
create table DB.DBA.RDF_OBJ_FT_RULES (
ROFR_G varchar not null, -- specific graph IRI or NULL for "all graphs"
ROFR_P varchar not null, -- specific predicate IRI or NULL for "all predicates"
ROFR_REASON varchar not null, -- identification string of a creator, preferably human-readable
primary key (ROFR_G, ROFR_P, ROFR_REASON) );
]]></programlisting>
<para>
Applications may read from this table but they should not write to it directly.
Duplications in the rules do not affect the speed of free-text index operations because the content of the table is cached in memory in a special form.
Unlike the use of configuration functions, directly writing to the table will not update the in-memory cache.
</para>
<para>
The table is convenient to search for rules added by a given application.
If a unique identification string is used during installation of an application when rules are added then it's easy to remove those rules
as part of any uninstall routine.
</para>
</sect4>
<sect4 id="rdfsparqlruletimeindexing"><title>Time of Indexing</title>
<para>The triple store's text index is in manual batch mode by default. This means that changes in triples are periodically
reflected in the text index but are not maintained in strict synchrony. This is much more efficient than keeping the
indices in constant synchrony. This setting may be altered with the <emphasis>db.dba.vt_batch_update</emphasis> stored procedure.
</para>
<para>To force synchronization of the RDF text index, use:
</para>
<programlisting>
DB.DBA.VT_INC_INDEX_DB_DBA_RDF_OBJ ();
</programlisting>
<para>To set the text index to follow the triples in real time, use:
</para>
<programlisting>
DB.DBA.VT_BATCH_UPDATE ('DB.DBA.RDF_OBJ', 'OFF', null);
</programlisting>
<para>To set the text index to be updated every 10 minutes, use:
</para>
<programlisting>
DB.DBA.VT_BATCH_UPDATE ('DB.DBA.RDF_OBJ', 'ON', 10);
</programlisting>
<para>To make the update always manual, specify NULL as the last argument above.
</para>
<para>
One problem related to free-text indexing of <emphasis>DB.DBA.RDF_QUAD</emphasis> is that some applications (e.g. those that import billions of triples) may set off triggers.
This will make free-text index data incomplete.
Calling procedure <emphasis>DB.DBA.RDF_OBJ_FT_RECOVER ()</emphasis> will insert all missing free-text index items by dropping and re-inserting every existing free-text index rule.
</para>
</sect4>
<sect4 id="rdfviewsandfreetext"><title>Free-Text Indexes on RDF Views</title>
<para>
If an <emphasis>O</emphasis> field of a quad map pattern gets its value from a database column that has a free text index then this index can be used in SPARQL for efficient text searching. As a variation of this facility, the free-text index of another table may be used.
</para>
<para>
If a statement of a quad map pattern declaration starts with a declaration of table aliases, the table alias declaration may include the name of a table column that should have a text index.
For example, consider the possibility of using a free-text index on the content of DAV resources stored in the DAV system tables of Virtuoso:
</para>
<programlisting><![CDATA[
prefix mydav: <...>
create quad storage mydav:metadata
FROM WS.WS.SYS_DAV_RES as dav_resource text literal RES_CONTENT
...
{
...
mydav:resource-iri (dav_resource.RES_FULL_PATH)
a mydav:resource ;
mydav:resource-content dav_resource.RES_CONTENT ;
mydav:resource-mime-type dav_resource.RESTYPE ;
...
}
]]></programlisting>
<para>
The clause <emphasis>text literal RES_CONTENT</emphasis> grants the SPARQL compiler permission to use a free-text index for objects that are literals composed from column <emphasis>dav_resource.RES_CONTENT</emphasis>. This clause also allows choosing between <emphasis>text literal</emphasis> (supports only the <emphasis>contains()</emphasis> predicate) and <emphasis>text xml literal</emphasis> (supports both <emphasis>contains()</emphasis> and <emphasis>xcontains()</emphasis>) text indexes.
It is important to understand that the free-text index will produce results using raw relational data.
If a literal class transformation changes the text stored in the column then these changes are ignored by free-text search.
e.g. if a transformation concatenates a word to the value of the column, but the free-text search will not find this word.
</para>
<para>
The free-text index may be used in a more sophisticated way. Consider a built-in table <emphasis>DB.DBA.RDF_QUAD</emphasis> that does not have a free-text index.
Moreover, the table does not contain the full values of all objects; the <emphasis>O</emphasis> column contains "short enough" values inlined, but long and special values are represented by links to the <emphasis>DB.DBA.RDF_OBJ</emphasis> table.
The RDF_OBJ table, however, has free-text index that can be used.
The full declaration of the built-in default mapping for default storage could be written this way:
</para>
<programlisting><![CDATA[
-- Important! Do not try to execute on live system
-- without first changing the quad storage and quad map pattern names!
SPARQL
create virtrdf:DefaultQuadMap as
graph rdfdf:default-iid-nonblank (DB.DBA.RDF_QUAD.G)
subject rdfdf:default-iid (DB.DBA.RDF_QUAD.S)
predicate rdfdf:default-iid-nonblank (DB.DBA.RDF_QUAD.P)
object rdfdf:default (DB.DBA.RDF_QUAD.O)
create quad storage virtrdf:DefaultQuadStorage
FROM DB.DBA.RDF_QUAD as physical_quad
FROM DB.DBA.RDF_OBJ as physical_obj text xml literal RO_DIGEST of (physical_quad.O)
WHERE (^{physical_quad.}^.O = ^{physical_obj.}^.RO_DIGEST)
{
create virtrdf:DefaultQuadMap as
graph rdfdf:default-iid-nonblank (physical_quad.G)
subject rdfdf:default-iid (physical_quad.S)
predicate rdfdf:default-iid-nonblank (physical_quad.P)
object rdfdf:default (physical_quad.O) .
}
;
]]></programlisting>
<para>
The reference to the free-text index is extended by clause <emphasis> of (physical_quad.O)</emphasis>.
This means that the free-text on <emphasis>DB.DBA.RDF_OBJ.RO_DIGEST</emphasis> will be used when the object value comes from <emphasis>physical_quad.O</emphasis> as if <emphasis>physical_quad.O</emphasis> were indexed itself.
If a SPARQL query invokes <emphasis>virtrdf:DefaultQuadMap</emphasis> but contains no free-text criteria then only <emphasis>DB.DBA.RDF_QUAD</emphasis> appears in the final SQL statement and no join with <emphasis>DB.DBA.RDF_OBJ</emphasis> is made.
Adding a free-text predicate will add <emphasis>DB.DBA.RDF_OBJ</emphasis> to the list of source tables and a join condition for <emphasis>DB.DBA.RDF_QUAD.O</emphasis> and <emphasis>DB.DBA.RDF_OBJ.RO_DIGEST</emphasis>; and it will add <emphasis>contains (RO_DIGEST, ...)</emphasis> predicate, rather than <emphasis>contains (O, ...)</emphasis>.
As a result, "you pay only for what you use": adding free-text index to the declaration does not add tables to the query unless the index is actually used.
</para>
<para>
Boolean functions <function>bif:contains</function> and <function>bif:xcontains</function> are used for objects that come from RDF Views as well as for regular "physical" triples.
Every function takes two arguments and returns a boolean value. The first argument is an local variable.
The argument variable should be used as an object field in the group pattern where the filter condition is placed.
Moreover, the occurrence of the variable in an object field should be placed <emphasis>before</emphasis> the filter.
If there are many occurrences of the variable in object fields then the free-text search is associated with the rightmost occurrence that is still to the left of the filter.
The triple pattern that contains the rightmost occurrence is called the "intake" of the free-text search.
When the SPARQL compiler chooses the appropriate quad map patterns that may generate data matching the intake triple pattern, it skips quad map patterns that have no declared free-text indexes, because nothing can be found by free-text search in data that have no free-text index.
Every quad map pattern that has a free-text pattern will ultimately produce an invocation of the SQL <link linkend="containspredicate">contains</link> or <link linkend="xcontainspredicate">xcontains</link> predicate, so the final result of a free-text search may be a union of free-text searches from different quad map patterns.
</para>
<para>
The described logic is important only in very complicated cases, whereas simple queries are self-evident:
</para>
<programlisting><![CDATA[
SELECT * FROM <my-dav-graph>
WHERE {
?resource a mydav:resource ;
mydav:resource-content ?text .
FILTER (bif:contains (?text, "hello and world")) }
]]></programlisting>
<para>
or, more succinctly,
</para>
<programlisting><![CDATA[
SELECT * FROM <my-dav-graph>
WHERE {
?resource a mydav:resource ;
mydav:resource-content ?text .
?text bif:contains "hello and world" . }
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlrulescoreexmp"><title>Example Using Score</title>
<programlisting><![CDATA[
SQL>
SPARQL
SELECT *
WHERE
{
?s ?p ?o .
?o bif:contains 'NEW AND YORK'
OPTION (score ?sc) .
}
ORDER BY DESC (?sc)
LIMIT 10
s p o sc
ANY ANY ANY ANY
______________________________________________________________________________________________________________________________________________________________________________
http://dbpedia.org/resource/New_York%2C_New_York_%28disambiguation%29 http://www.w3.org/2000/01/rdf-schema#comment New York, New York, New York kentini........ 88
http://dbpedia.org/resource/New_York%2C_New_York_%28disambiguation%29 http://dbpedia.org/property/abstract New York, New York, New York kentinin re.... 88
http://newyorkjobs.wordpress.com/2006/07/10/new-york-jobs-71006 http://purl.org/dc/elements/1.1/description York Marketing Jobs New York Retail Jobs.... 84
http://dbpedia.org/resource/Global_Communication http://dbpedia.org/property/contenu A - New York, New York (Headfuq Mix) B1 .... 84
http://dbpedia.org/resource/New_York_%28disambiguation%29 http://www.w3.org/2000/01/rdf-schema#comment New York a^?? New York amerikai vA~?ros .... 76
http://dbpedia.org/resource/New_York_%28disambiguation%29 http://dbpedia.org/property/abstract New York a^?? New York amerikai vA~?ros .... 76
http://dbpedia.org/resource/New_York_%28disambiguation%29 http://www.w3.org/2000/01/rdf-schema#comment New York ima lahko naslednje pomene: New ... 74
http://dbpedia.org/resource/New_York_%28disambiguation%29 http://dbpedia.org/property/abstract New York ima lahko naslednje pomene: New ... 74
http://dbpedia.org/resource/New_York_College http://www.w3.org/2000/01/rdf-schema#comment There are several colleges of New York t ... 72
http://dbpedia.org/resource/New_York_College http://dbpedia.org/property/abstract There are several colleges of New York t ... 72
No. of rows in result: 10
]]></programlisting>
</sect4>
</sect3>
<sect3 id="rdfsparul"><title>SPARUL -- an Update Language For RDF Graphs</title>
<sect4 id="rdfsparulintro"><title>Introduction</title>
<para>Starting with version 5.0, Virtuoso supports the
<ulink url="http://jena.hpl.hp.com/~afs/SPARQL-Update.html">SPARQL/Update</ulink> extension to SPARQL.
This is sufficient for most of routine data manipulation operations. If the <emphasis>SPARQL_UPDATE</emphasis>
role is granted to user <emphasis>SPARQL</emphasis> user then data manipulation statements may be
executed via the SPARQL web service endpoint as well as by data querying.
</para>
</sect4>
<sect4 id="rdfsparulfunc"><title>Manage RDF Storage</title>
<para>Two functions allow the user to alter RDF storage by inserting or deleting all
triples listed in some vector. Both functions receive the IRI of the graph that should be altered and
a vector of triples that should be added or removed. The graph IRI can be either an IRI ID or a string.
The third optional argument controls the transactional behavior - the parameter value is
passed to the <link linkend="fn_log_enable"><function>log_enable</function></link> function.
The return values of these functions are not defined and should not be used by applications.
</para>
<programlisting>
create function DB.DBA.RDF_INSERT_TRIPLES (in graph_iri any, in triples any, in log_mode integer := null)
create function DB.DBA.RDF_DELETE_TRIPLES (in graph_iri any, in triples any, in log_mode integer := null)
</programlisting>
<para>Simple operations may be faster if written as low-level SQL code instead of using SPARUL.
The use of SPARQL DELETE is unnecessary in cases where the better alternative is for the application to delete from RDF_QUAD
using simple SQL filters like:
</para>
<programlisting>
DELETE FROM DB.DBA.RDF_QUAD
WHERE G = DB.DBA.RDF_MAKE_IID_OF_QNAME (
'http://local.virt/DAV/sparql_demo/data/data-xml/source-simple2/source-data-01.rdf' );
</programlisting>
<para>On the other hand, simple filters does not work when the search criteria refer to triples
that are affected by the modification. Consider a function that deletes all triples whose subjects
are nodes of type 'http://xmlns.com/foaf/0.1/Person'. Type information is stored in triples that
will be deleted, so the simplest function is something like this:
</para>
<programlisting><![CDATA[
create procedure DELETE_PERSONAL_DATA (in foaf_graph varchar)
{
declare pdata_dict, pdata_array any;
-- Step 1: select everything that should be deleted
pdata_dict := ((
sparql construct { ?s ?p ?o }
WHERE { graph ?:foaf_graph {
?s ?p ?o . ?s rdf:type <http://xmlns.com/foaf/0.1/Person>
} }
));
-- Step 2: delete all found triples
pdata_array := dict_list_keys (pdata_dict, 1);
RDF_DELETE_TRIPLES (foaf_graph, pdata_array);
};
DELETE_PERSONAL_DATA (
'http://local.virt/DAV/sparql_demo/data/data-xml/source-simple2/source-data-01.rdf' );
]]></programlisting>
<para>From Virtuoso 5.0 onwards, applications can use SPARUL to do the same in a more convenient way:
</para>
<programlisting><![CDATA[
create procedure DELETE_PERSONAL_DATA (in foaf_graph varchar)
{
sparql delete { ?s ?p ?o }
WHERE { graph ?:foaf_graph {
?s ?p ?o . ?s rdf:type <http://xmlns.com/foaf/0.1/Person>
} }
};
]]></programlisting>
</sect4>
<sect4 id="rdfsparulexamples"><title>Examples</title>
<sect5 id="rdfsparulexamples1"><title>Example for changing the graph</title>
<para>The graph to be changed may be specified by an option preceding of query, instead
of being specified in the 'insert into graph' clause.
</para>
<programlisting><![CDATA[
SQL>SPARQL DEFINE input:default-graph-uri <http://mygraph.com>
INSERT INTO <http://mygraph.com> { <http://myopenlink.net/dataspace/Kingsley#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#User> };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 20 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples2"><title>Example for delete graph equivalents</title>
<para>The following two statements are equivalent but the latter may work faster, especially
if there are many RDF views in the system or if the graph in question contains triples from RDF views.
Note that neither of these two statements affects data coming from RDF views.
</para>
<programlisting><![CDATA[
SQL> SPARQL DELETE FROM GRAPH <http://mygraph.com> { ?s ?p ?o } FROM <http://mygraph> WHERE { ?s ?p ?o };
callret-0
VARCHAR
_______________________________________________________________________________
Delete from <http://mygraph.com>, 1 triples -- done
1 Rows. -- 10 msec.
SQL> SPARQL CLEAR GRAPH <http://mygraph.com>;
callret-0
VARCHAR
__________________________________________________________
Clear <http://mygraph.com> -- done
1 Rows. -- 10 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples3"><title>Example for deleting all triples for given subject</title>
<para>The following statement deletes all records with <http://myopenlink.net/dataspace/Kingsley#this> as the subject:</para>
<programlisting><![CDATA[
SQL>SPARQL
DELETE FROM GRAPH <http://mygraph.com> { ?s ?p ?o }
FROM <http://mygraph.com>
WHERE { ?s ?p ?o . filter ( ?s = <http://myopenlink.net/dataspace/Kingsley#this>) };
callret-0
VARCHAR
_______________________________________________________________________________
Delete from <http://mygraph.com>, 1 triples -- done
1 Rows. -- 10 msec.
]]></programlisting>
<para>Alternatively, the statement can be written in this way:</para>
<programlisting><![CDATA[
SQL>SPARQL
DELETE FROM GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Kingsley#this> ?p ?o }
FROM <http://mygraph.com>
WHERE { <http://myopenlink.net/dataspace/Kingsley#this> ?p ?o };
callret-0
VARCHAR
_______________________________________________________________________________
Delete from <http://mygraph.com>, 1 triples -- done
1 Rows. -- 10 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples4"><title>Example for INSERT statements equivalent</title>
<para>Keywords 'insert in' and 'insert into' are interchangeable in Virtuoso for backward
compatibility, but the SPARUL specification lists only 'insert into'. For example,
the statements below are equivalent:
</para>
<programlisting><![CDATA[
SQL>SPARQL INSERT INTO GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Kingsley#this>
<http://rdfs.org/sioc/ns#id>
<Kingsley> };
callret-0
VARCHAR
______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 0 msec.
SQL>SPARQL INSERT INTO GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Caroline#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 0 msec.
-- and
SQL>SPARQL INSERT IN GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Kingsley#this>
<http://rdfs.org/sioc/ns#id>
<Kingsley> };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 10 msec.
SQL>SPARQL INSERT IN GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Caroline#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> };
callret-0
VARCHAR
________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
1 Rows. -- 0 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples5"><title>Example for various expressions usage</title>
<para>It is possible to use various expressions to calculate fields of new triples. This is
very convenient, even if not a part of the original specification.
</para>
<programlisting><![CDATA[
SQL>SPARQL INSERT INTO GRAPH <http://mygraph.com> { ?s <http://rdfs.org/sioc/ns#id> `iri (bif:concat (str (?o), "Idehen"))` }
WHERE { ?s <http://rdfs.org/sioc/ns#id> ?o };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 4 triples -- done
1 Rows. -- 0 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples6"><title>Example for operator IN usage</title>
<para>The example shows how to find which predicate/object pairs the following
subjects have in common and count the occurances:</para>
<programlisting><![CDATA[
http://dbpedia.org/resource/Climate_change
http://dbpedia.org/resource/Disaster_risk_reduction
http://dbpedia.org/resource/Tanzania
http://dbpedia.org/resource/Capacity_building
http://dbpedia.org/resource/Poverty
http://dbpedia.org/resource/Construction
http://dbpedia.org/resource/Vulnerability
http://dbpedia.org/resource/Mount_Kilimanjaro
http://dbpedia.org/resource/Social_vulnerability
]]></programlisting>
<para>The following query returns the desired results:</para>
<programlisting><![CDATA[
SPARQL
SELECT ?s1 ?s2 COUNT (1)
WHERE
{
?s1 ?p ?o .
FILTER (?s1 IN (<http://dbpedia.org/resource/Climate_change>,
<http://dbpedia.org/resource/Disaster_risk_reduction>,
<http://dbpedia.org/resource/Tanzania>,
<http://dbpedia.org/resource/Capacity_building>,
<http://dbpedia.org/resource/Poverty>,
<http://dbpedia.org/resource/Construction>,
<http://dbpedia.org/resource/Vulnerability>,
<http://dbpedia.org/resource/Mount_Kilimanjaro>,
<http://dbpedia.org/resource/Social_vulnerability> ))
?s2 ?p ?o .
FILTER (?s2 IN (<http://dbpedia.org/resource/Climate_change>,
<http://dbpedia.org/resource/Disaster_risk_reduction>,
<http://dbpedia.org/resource/Tanzania>,
<http://dbpedia.org/resource/Capacity_building>,
<http://dbpedia.org/resource/Poverty>,
<http://dbpedia.org/resource/Construction>,
<http://dbpedia.org/resource/Vulnerability>,
<http://dbpedia.org/resource/Mount_Kilimanjaro>,
<http://dbpedia.org/resource/Social_vulnerability> ))
FILTER (?s1 != ?s2)
FILTER (str(?s1) < str (?s2))
}
LIMIT 20
]]></programlisting>
<para>The result of executing the query:</para>
<programlisting><![CDATA[
s1 s2 callret-2
http://dbpedia.org/resource/Climate_change http://dbpedia.org/resource/Tanzania 2
http://dbpedia.org/resource/Social_vulnerability http://dbpedia.org/resource/Vulnerability 1
http://dbpedia.org/resource/Mount_Kilimanjaro http://dbpedia.org/resource/Poverty 1
http://dbpedia.org/resource/Mount_Kilimanjaro http://dbpedia.org/resource/Tanzania 3
http://dbpedia.org/resource/Capacity_building http://dbpedia.org/resource/Disaster_risk_reduction 1
http://dbpedia.org/resource/Poverty http://dbpedia.org/resource/Tanzania 1
]]></programlisting>
<para>You can also find live demo query results <ulink url="http://dbpedia.org/sparql?default-graph-uri=http%3A%2F%2Fdbpedia.org&should-sponge=&query=SELECT+%0D%0A%3Fs1+%3Fs2+count+%281%29+where+{%0D%0A%3Fs1+%3Fp+%3Fo+.%0D%0Afilter+%28%3Fs1+in+%28%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FClimate_change%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FDisaster_risk_reduction%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FTanzania%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FCapacity_building%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FPoverty%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FConstruction%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FVulnerability%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FMount_Kilimanjaro%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FSocial_vulnerability%3E+%29%29%0D%0A%3Fs2+%3Fp+%3Fo+.%0D%0Afilter+%28%3Fs2+in+%28%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FClimate_change%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FDisaster_risk_reduction%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FTanzania%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FCapacity_building%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FPoverty%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FConstruction%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FVulnerability%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FMount_Kilimanjaro%3E%2C%0D%0A%3Chttp%3A%2F%2Fdbpedia.org%2Fresource%2FSocial_vulnerability%3E+%29%29%0D%0Afilter+%28%3Fs1+!%3D+%3Fs2%29%0D%0Afilter+%28str%28%3Fs1%29+%3C+str+%28%3Fs2%29%29%0D%0A}+limit+20&format=html&debug=on&timeout=">here</ulink></para>
<tip><title>See Also:</title>
<para><link linkend="rdfsparulexamples18">Example usage of IN operator for retrieving all triples for each entity.</link></para>
</tip>
</sect5>
<sect5 id="rdfsparulexamples7"><title>Example for Modify used as Update</title>
<para>'Modify graph' may be used as a form of 'update' operation.
</para>
<programlisting><![CDATA[
SQL>SPARQL MODIFY GRAPH <http://mygraph.com> DELETE { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?o } INSERT { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type1> ?o } WHERE { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?o };
SQL>SPARQL
DELETE FROM GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Caroline#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type1> <http://rdfs.org/sioc/ns#User> };
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples8"><title>Example for generating RDF information resource URI</title>
<para>The RDF information resource URI can be generated via a string expression.</para>
<itemizedlist mark="bullet">
<listitem>Suppose there is a sample file kidehen.n3:
<programlisting><![CDATA[
<http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#User> .
<http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this> <http://www.w3.org/2000/01/rdf-schema#label> "Kingsley" .
<http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this> <http://rdfs.org/sioc/ns#creator_of> <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300> .
]]></programlisting>
</listitem>
<listitem>Using Conductor UI go to Web Application Server and create folder, for ex. with name "n3_collection"</listitem>
<listitem>Upload the "n3_collection" folder the file kidehen.n3</listitem>
<listitem>Click properties for the folder "n3_collection" and set to be public readable in the Permissions section</listitem>
<listitem>Check "Apply changes to all subfolders and resources".</listitem>
<listitem>Finally Click "Update"</listitem>
<figure id="gnr1" float="1">
<title>Generating RDF information resource URI</title>
<graphic fileref="ui/exmp1.png"/>
</figure>
<listitem>To clear the graph execute:
<programlisting><![CDATA[
SQL>SPARQL CLEAR GRAPH <http://mygraph.com>;
callret-0
VARCHAR
_____________________________________________________________________
Clear <http://mygraph.com> -- done
1 Rows. -- 10 msec.
]]></programlisting></listitem>
<listitem>To load the kidehen.n3 file execute:
<programlisting><![CDATA[
SQL>SPARQL
load bif:concat ("http://", bif:registry_get("URIQADefaultHost"), "/DAV/n3_collection/kidehen.n3")
INTO GRAPH <http://mygraph.com>;
callret-0
VARCHAR
_______________________________________________________________________________
Load <http://localhost:8890/DAV/n3_collection/kidehen.n3> into graph <http://mygraph.com> -- done
1 Rows. -- 30 msec.
]]></programlisting>
</listitem>
<listitem>In order to check the new inserted triples execute:
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://mygraph.com>
WHERE
{
?s ?p ?o
}
;
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://rdfs.org/sioc/ns#User
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this http://rdfs.org/sioc/ns#creator_of http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this http://www.w3.org/2000/01/rdf-schema#label Kingsley
3 Rows. -- 10 msec.
]]></programlisting>
</listitem>
</itemizedlist>
</sect5>
<sect5 id="rdfsparulexamples9"><title>Example for operations over a web service endpoint</title>
<para>Several operations can be sent to a web service endpoint as a single statement and
executed in sequence.
</para>
<programlisting><![CDATA[
SQL>SPARQL
INSERT IN GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Kingsley#this>
<http://rdfs.org/sioc/ns#id>
<Kingsley> }
INSERT INTO GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Caroline#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> }
INSERT INTO GRAPH <http://mygraph.com> { ?s <http://rdfs.org/sioc/ns#id> `iri (bif:concat (str (?o), "Idehen"))` }
WHERE { ?s <http://rdfs.org/sioc/ns#id> ?o };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://mygraph.com>, 1 triples -- done
Insert into <http://mygraph.com>, 1 triples -- done
Insert into <http://mygraph.com>, 8 triples -- done
Commit -- done
1 Rows. -- 10 msec.
SQL>SPARQL
MODIFY GRAPH <http://mygraph.com>
DELETE { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?o }
INSERT { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type1> ?o }
WHERE { ?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?o };
SQL>DELETE FROM GRAPH <http://mygraph.com> { <http://myopenlink.net/dataspace/Caroline#this> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type1> <http://rdfs.org/sioc/ns#User> };
SQL>SPARQL
load bif:concat ("http://", bif:registry_get("URIQADefaultHost"), "/DAV/n3_collection/kidehen.n3") INTO GRAPH <http://mygraph.com>;
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples10"><title>Example for Dropping graph</title>
<para>When handling very large RDF data collections (e.g. 600 million triples ) loaded into Virtuoso
server as a single graph, the fastest operation to drop the graph is:</para>
<programlisting><![CDATA[
SQL>SPARQL CLEAR GRAPH <http://mygraph.com>;
callret-0
VARCHAR
______________________________________________________________________________
Clear <http://mygraph.com> -- done
1 Rows. -- 10 msec.
]]></programlisting>
<para>The operation can be speeded up by executing log_enable (0) or even log_enable (2) beforehand,
and log_enable(1) after it completes.
</para>
</sect5>
<sect5 id="rdfsparulexamples11"><title>Example for testing Graph Equality</title>
<para>The procedure below keeps simple cases of graphs with bnodes:</para>
<orderedlist>
<listitem>First it compares all triples without bnodes</listitem>
<listitem>Then it iteratively establishes equivalences between bnodes that
are directly and unambiguously connected to equivalent vertexes by identical predicates.</listitem>
</orderedlist>
<programlisting><![CDATA[
-- Fast Approximate RDF Graph Equivalence Test
-- (C) 2009 OpenLink Software
-- License: GNU General Public License (only version 2 of the license).
-- No warranty, even implied warranty
-- This compares the content of triple dictionaries \c dict1 and \c dict2,
-- returns NULL if no difference found (with bnode equivalence in mind),
-- returns description of a difference otherwise.
-- The function is experimental (note suffix _EXP), so no accurate QA is made.
-- Some version of the function may be inserted later in OpenLink Virtuoso Server under some different name.
create function DB.DBA.RDF_TRIPLE_DICTS_DIFFER_EXP (
in dict1 any, --- Triple dictionary, traditional, (vectors of S, P, O are keys, any non-nulls are values)
in dict2 any, --- Second triple dictionary, like to \c dict1
in accuracy integer, --- Accuracy, 0 if no bnodes expected, 1 if "convenient" trees with intermediate bnodes expected, 2 and more are not yet implemented
in equiv_map any := null, --- If specified then it contain mapping from IRI_IDs of bnodes of \c dict1 to equivalent IRI_IDs of bnodes of \c dict1.
-- It can be extended during the run so use dict_duplicate() before call if needed.
in equiv_rev any := null --- If specified then it is an inverted dictionary of \c equiv_map (this time \c dict2 bnodes are keys and \c dict1 bnodes are values)
)
{
declare dict_size1, dict_size2 integer;
declare old_dirt_level, dirt_level integer;
declare ctr, tailctr, sp_made_new_equiv integer;
declare array1, array2, dict2_sp, dict1_op, dict2_op, array1_op any;
dict_size1 := dict_size (dict1);
dict_size2 := dict_size (dict2);
dict2 := dict_duplicate (dict2);
if (dict_size1 <> dict_size2)
return 'Sizes differ';
if (equiv_map is null)
{
equiv_map := dict_new (dict_size1);
equiv_rev := dict_new (dict_size1);
}
old_dirt_level := dict_size1 - dict_size (equiv_map);
array1 := dict_list_keys (dict1, 0);
next_loop:
-- Step 1: removing triples with all three items matched
ctr := dict_size1-1;
while (ctr >= 0)
{
declare s_in_1, o_in_1, s_in_2, o_in_2, triple_in_2 any;
s_in_1 := array1[ctr][0];
o_in_1 := array1[ctr][2];
if (is_bnode_iri_id (s_in_1))
{
s_in_2 := dict_get (equiv_map, s_in_1, null);
if (s_in_2 is null)
goto next_full_eq_check;
}
else
s_in_2 := s_in_1;
if (is_bnode_iri_id (o_in_1))
{
o_in_2 := dict_get (equiv_map, o_in_1, null);
if (o_in_2 is null)
goto next_full_eq_check;
}
else
o_in_2 := o_in_1;
triple_in_2 := vector (s_in_2, array1[ctr][1], o_in_2);
if (dict_get (dict2, triple_in_2, null) is null)
return vector (array1[ctr], ' is in first, ', triple_in_2, ' is missing in second');
dict_remove (dict2, triple_in_2);
if (ctr < dict_size1-1)
array1[ctr] := array1[dict_size1-1];
dict_size1 := dict_size1-1;
next_full_eq_check:
ctr := ctr-1;
}
-- Step 1 end, garbage truncated:
if ((0 = dict_size1) or (0 = accuracy))
return null;
if (dict_size1 < length (array1))
array1 := subseq (array1, 0, dict_size1);
if (dict_size (dict2) <> dict_size1)
signal ('OBLOM', 'Internal error: sizes of graphs suddenly differ');
-- Step 2: establishing equivs between not-yet-coupled bnodes that are values of functional predicates of coupled subjects
sp_made_new_equiv := 0;
dict2_sp := dict_new (dict_size1);
array2 := dict_list_keys (dict2, 0);
for (ctr := dict_size1-1; ctr >= 0; ctr := ctr-1)
{
declare sp2, o2, prev_uniq_o2 any;
sp2 := vector (array2[ctr][0], array2[ctr][1]);
prev_uniq_o2 := dict_get (dict2_sp, sp2, null);
if (prev_uniq_o2 is null)
{
o2 := array2[ctr][2];
if (is_bnode_iri_id (o2))
dict_put (dict2_sp, sp2, o2);
else
dict_put (dict2_sp, sp2, #i0);
}
else if (prev_uniq_o2 <> #i0)
dict_put (dict2_sp, sp2, #i0);
}
rowvector_subj_sort (array1, 0, 1);
rowvector_subj_sort (array1, 1, 1);
rowvector_subj_sort (array2, 1, 1);
ctr := 0;
while (ctr < dict_size1)
{
declare s_in_1, o_in_1, s_in_2, o_in_2, o_in_dict2_sp, o_in_dict2_sp_in_1 any;
tailctr := ctr+1;
if (array1[ctr][1] <> array2[ctr][1])
{
if (array1[ctr][1] > array2[ctr][1])
return vector ('Cardinality of predicate ', array2[ctr][1], ' is greater in second than in first');
else
return vector ('Cardinality of predicate ', array1[ctr][1], ' is greater in first than in second');
}
while ((tailctr < dict_size1) and
(array1[tailctr][0] = array1[ctr][0]) and
(array1[tailctr][1] = array1[ctr][1]) )
tailctr := tailctr+1;
if ((tailctr - ctr) > 1)
goto next_sp_check;
o_in_1 := array1[ctr][2];
if (not is_bnode_iri_id (o_in_1))
goto next_sp_check;
o_in_2 := dict_get (equiv_map, o_in_1, null);
if (o_in_2 is not null)
goto next_sp_check;
s_in_1 := array1[ctr][0];
if (is_bnode_iri_id (s_in_1))
{
s_in_2 := dict_get (equiv_map, s_in_1, null);
if (s_in_2 is null)
goto next_sp_check;
}
else
s_in_2 := s_in_1;
o_in_dict2_sp := dict_get (dict2_sp, vector (s_in_2, array1[ctr][1]), null);
if (o_in_dict2_sp is null)
return vector (vector (s_in_1, array1[ctr][1], o_in_1), ' is unique SP in first, ', vector (s_in_2, array1[ctr][1]), ' is missing SP in second');
if (o_in_dict2_sp = #i0)
return vector (vector (s_in_1, array1[ctr][1], o_in_1), ' is unique SP in first, ', vector (s_in_2, array1[ctr][1]), ' is not unique SP-to-bnode in second');
o_in_dict2_sp_in_1 := dict_get (equiv_rev, o_in_dict2_sp, null);
if (o_in_dict2_sp_in_1 is not null)
{
if (o_in_dict2_sp_in_1 = o_in_1)
goto next_sp_check;
return vector (vector (s_in_1, array1[ctr][1], o_in_1), ' is unique SP in first, ', vector (s_in_2, array1[ctr][1], o_in_dict2_sp), ' is unique SP in second but ', o_in_dict2_sp, ' rev-equiv to ', o_in_dict2_sp_in_1);
}
dict_put (equiv_map, o_in_1, o_in_dict2_sp);
dict_put (equiv_rev, o_in_dict2_sp, o_in_1);
sp_made_new_equiv := sp_made_new_equiv + 1;
next_sp_check:
ctr := tailctr;
}
dict_list_keys (dict2_sp, 2);
-- Step 2 end
if (sp_made_new_equiv * 10 > dict_size1)
goto next_loop; -- If dictionary is noticeably extended then it's worth to remove more triples before continue.
-- Step 3: establishing equivs between not-yet-coupled bnodes that are subjects of inverse functional properties with coupled objects.
dict1_op := dict_new (dict_size1);
for (ctr := dict_size1-1; ctr >= 0; ctr := ctr-1)
{
declare op1, s1, prev_uniq_s1 any;
op1 := vector (array1[ctr][2], array1[ctr][1]);
prev_uniq_s1 := dict_get (dict1_op, op1, null);
if (prev_uniq_s1 is null)
{
s1 := array1[ctr][0];
if (is_bnode_iri_id (s1))
dict_put (dict1_op, op1, s1);
else
dict_put (dict1_op, op1, #i0);
}
else if (prev_uniq_s1 <> #i0)
dict_put (dict1_op, op1, #i0);
}
array1_op := dict_to_vector (dict1_op, 2);
dict2_op := dict_new (dict_size1);
for (ctr := dict_size1-1; ctr >= 0; ctr := ctr-1)
{
declare op2, s2, prev_uniq_s2 any;
op2 := vector (array2[ctr][2], array2[ctr][1]);
prev_uniq_s2 := dict_get (dict2_op, op2, null);
if (prev_uniq_s2 is null)
{
s2 := array2[ctr][0];
if (is_bnode_iri_id (s2))
dict_put (dict2_op, op2, s2);
else
dict_put (dict2_op, op2, #i0);
}
else if (prev_uniq_s2 <> #i0)
dict_put (dict2_op, op2, #i0);
}
ctr := length (array1_op) - 2;
while (ctr >= 0)
{
declare o_in_1, s_in_1, o_in_2, s_in_2, s_in_dict2_op, s_in_dict2_op_in_1 any;
s_in_1 := array1_op[ctr+1];
if (not is_bnode_iri_id (s_in_1))
goto next_op_check;
s_in_2 := dict_get (equiv_map, s_in_1, null);
if (s_in_2 is not null)
goto next_op_check;
o_in_1 := array1_op[ctr][0];
if (is_bnode_iri_id (o_in_1))
{
o_in_2 := dict_get (equiv_map, o_in_1, null);
if (o_in_2 is null)
goto next_op_check;
}
else
o_in_2 := o_in_1;
s_in_dict2_op := dict_get (dict2_op, vector (o_in_2, array1_op[ctr][1]), null);
if (s_in_dict2_op is null)
return vector (vector (s_in_1, array1_op[ctr][1], o_in_1), ' is unique OP in first, ', vector (o_in_2, array1_op[ctr][1]), ' is missing OP in second');
if (s_in_dict2_op = #i0)
return vector (vector (s_in_1, array1_op[ctr][1], o_in_1), ' is unique OP in first, ', vector (o_in_2, array1_op[ctr][1]), ' is not unique OP-to-bnode in second');
s_in_dict2_op_in_1 := dict_get (equiv_rev, s_in_dict2_op, null);
if (s_in_dict2_op_in_1 is not null)
{
if (s_in_dict2_op_in_1 = s_in_1)
goto next_op_check;
return vector (vector (s_in_1, array1_op[ctr][1], o_in_1), ' is unique OP in first, ', vector (s_in_dict2_op, array1[ctr][1], o_in_2), ' is unique OP in second but ', s_in_dict2_op, ' rev-equiv to ', s_in_dict2_op_in_1);
}
dict_put (equiv_map, s_in_1, s_in_dict2_op);
dict_put (equiv_rev, s_in_dict2_op, s_in_1);
next_op_check:
ctr := ctr - 2;
}
dict_list_keys (dict2_op, 2);
-- Step 3 end
dirt_level := dict_size1 - dict_size (equiv_map);
if (dirt_level >= old_dirt_level)
return vector (vector (array1[0][0], array1[0][1], array1[0][2]), ' has no matches in second with the requested accuracy');
old_dirt_level := dirt_level;
goto next_loop;
}
;
create function DB.DBA.RDF_GRAPHS_DIFFER_EXP (in g1_uri varchar, in g2_uri varchar, in accuracy integer)
{
return DB.DBA.RDF_TRIPLE_DICTS_DIFFER_EXP (
(sparql define output:valmode "LONG" construct { ?s ?p ?o } where { graph `iri(?:g1_uri)` { ?s ?p ?o }}),
(sparql define output:valmode "LONG" construct { ?s ?p ?o } where { graph `iri(?:g2_uri)` { ?s ?p ?o }}),
accuracy );
}
;
-- The rest of file contains some minimal tests.
set verbose off;
set banner off;
set types off;
create function DB.DBA.DICT_EXTEND_WITH_KEYS (in dict any, in keys any)
{
if (dict is null)
dict := dict_new (length (keys));
foreach (any k in keys) do
dict_put (dict, k, 1);
return dict;
}
;
create function DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP (in title varchar, in should_differ integer, in v1 any, in v2 any, in accuracy integer)
{
declare d1, d2, eqm, eqr, differ_status any;
d1 := DB.DBA.DICT_EXTEND_WITH_KEYS (null, v1);
d2 := DB.DBA.DICT_EXTEND_WITH_KEYS (null, v2);
eqm := dict_new (10);
eqr := dict_new (10);
dbg_obj_princ ('===== ' || title);
differ_status := DB.DBA.RDF_TRIPLE_DICTS_DIFFER_EXP (d1, d2, accuracy, eqm, eqr);
dbg_obj_princ ('Result: ', differ_status);
if (0 < dict_size (eqm))
dbg_obj_princ ('Equivalence map: ', dict_to_vector (eqm, 0));
dbg_obj_princ ('Equivalence rev: ', dict_to_vector (eqr, 0));
return sprintf ('%s: %s',
case when (case when should_differ then equ (0, isnull (differ_status)) else isnull (differ_status) end) then 'PASSED' else '***FAILED' end,
title );
}
;
create function DB.DBA.TEST_RDF_GRAPHS_DIFFER_EXP (in title varchar, in should_differ integer, in g1_uri varchar, in g2_uri varchar, in accuracy integer)
{
declare differ_status any;
differ_status := DB.DBA.RDF_GRAPHS_DIFFER_EXP (g1_uri, g2_uri, accuracy);
dbg_obj_princ ('Result: ', differ_status);
return sprintf ('%s: %s',
case when (case when should_differ then equ (0, isnull (differ_status)) else isnull (differ_status) end) then 'PASSED' else '***FAILED' end,
title );
}
;
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'Identical graphs', 0,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i200, 1) ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i200, 1) ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'Sizes differ', 1,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i200, 1) ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i200, 1),
vector (#i101, #i201, #i301) ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'Cardinality of a pred differ', 1,
vector (
vector (#i100, #i200, #ib300),
vector (#i101, #i200, #ib302),
vector (#i103, #i201, #ib304),
vector (#ib109, #i200, #ib109) ),
vector (
vector (#i100, #i200, #ib301),
vector (#i101, #i200, #ib303),
vector (#i103, #i201, #ib305),
vector (#ib109, #i201, #ib109) ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'Bnodes in O with unique SP (equiv)', 0,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib301),
vector (#i101, #i201, #ib301),
vector (#i102, #i202, #ib303),
vector (#ib303, #i204, #i306),
vector (#ib303, #i205, #ib305),
vector (#i100, #i200, 1) ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib302),
vector (#i101, #i201, #ib302),
vector (#i102, #i202, #ib304),
vector (#ib304, #i204, #i306),
vector (#ib304, #i205, #ib306),
vector (#i100, #i200, 1) ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'Bnodes in O with unique SP (diff 1)', 1,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib301),
vector (#i102, #i202, #ib303),
vector (#ib303, #i204, #i306),
vector (#ib303, #i205, #ib305),
vector (#i100, #i200, 1) ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib302),
vector (#i102, #i202, #ib304),
vector (#ib304, #i204, #i306),
vector (#ib304, #i205, #i306),
vector (#i100, #i200, 1) ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'Bnodes in O with unique SP (diff 2)', 1,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib301),
vector (#i102, #i202, #ib303),
vector (#ib303, #i204, #i306),
vector (#ib303, #i205, #ib305),
vector (#i100, #i200, 1) ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib302),
vector (#i102, #i202, #ib304),
vector (#ib304, #i204, #i306),
vector (#ib304, #i205, #ib304),
vector (#i100, #i200, 1) ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'foaf-like-mix (equiv)', 0,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib301),
vector (#i100, #i201, #ib303),
vector (#i100, #i201, #ib305),
vector (#i100, #i201, #ib307),
vector (#ib301, #i202, 'Anna'),
vector (#ib303, #i202, 'Anna'),
vector (#ib305, #i202, 'Brigit'),
vector (#ib307, #i202, 'Clara'),
vector (#ib301, #i203, 'ann@ex.com'),
vector (#ib303, #i203, 'ann@am.com'),
vector (#ib305, #i203, 'root@ple.com'),
vector (#ib307, #i203, 'root@ple.com') ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib302),
vector (#i100, #i201, #ib304),
vector (#i100, #i201, #ib306),
vector (#i100, #i201, #ib308),
vector (#ib302, #i202, 'Anna'),
vector (#ib304, #i202, 'Anna'),
vector (#ib306, #i202, 'Brigit'),
vector (#ib308, #i202, 'Clara'),
vector (#ib302, #i203, 'ann@ex.com'),
vector (#ib304, #i203, 'ann@am.com'),
vector (#ib306, #i203, 'root@ple.com'),
vector (#ib308, #i203, 'root@ple.com') ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'foaf-like-mix (swapped names)', 1,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib301),
vector (#i100, #i201, #ib303),
vector (#i100, #i201, #ib305),
vector (#i100, #i201, #ib307),
vector (#ib301, #i202, 'Anna'),
vector (#ib303, #i202, 'Anna'),
vector (#ib305, #i202, 'Brigit'),
vector (#ib307, #i202, 'Clara'),
vector (#ib301, #i203, 'ann@ex.com'),
vector (#ib303, #i203, 'ann@am.com'),
vector (#ib305, #i203, 'root@ple.com'),
vector (#ib307, #i203, 'root@ple.com') ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib302),
vector (#i100, #i201, #ib304),
vector (#i100, #i201, #ib306),
vector (#i100, #i201, #ib308),
vector (#ib302, #i202, 'Anna'),
vector (#ib304, #i202, 'Brigit'),
vector (#ib306, #i202, 'Anna'),
vector (#ib308, #i202, 'Clara'),
vector (#ib302, #i203, 'ann@ex.com'),
vector (#ib304, #i203, 'ann@am.com'),
vector (#ib306, #i203, 'root@ple.com'),
vector (#ib308, #i203, 'root@ple.com') ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'foaf-like-mix (swapped names)', 1,
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib301),
vector (#i100, #i201, #ib303),
vector (#i100, #i201, #ib305),
vector (#i100, #i201, #ib307),
vector (#ib301, #i202, 'Anna'),
vector (#ib303, #i202, 'Anna'),
vector (#ib305, #i202, 'Brigit'),
vector (#ib307, #i202, 'Clara'),
vector (#ib301, #i203, 'ann@ex.com'),
vector (#ib303, #i203, 'ann@am.com'),
vector (#ib305, #i203, 'root@ple.com'),
vector (#ib307, #i203, 'root@ple.com') ),
vector (
vector (#i100, #i200, #i300),
vector (#i100, #i201, #ib302),
vector (#i100, #i201, #ib304),
vector (#i100, #i201, #ib306),
vector (#i100, #i201, #ib308),
vector (#ib302, #i202, 'Anna'),
vector (#ib304, #i202, 'Brigit'),
vector (#ib306, #i202, 'Anna'),
vector (#ib308, #i202, 'Clara'),
vector (#ib302, #i203, 'ann@ex.com'),
vector (#ib304, #i203, 'ann@am.com'),
vector (#ib306, #i203, 'root@ple.com'),
vector (#ib308, #i203, 'root@ple.com') ),
100
);
select DB.DBA.TEST_RDF_TRIPLE_DICTS_DIFFER_EXP ( 'bnodes only (equiv that can not be proven)', 1,
vector (
vector (#ib101, #i200, #ib103),
vector (#ib103, #i201, #ib101) ),
vector (
vector (#ib102, #i200, #ib104),
vector (#ib104, #i201, #ib102) ),
100
);
sparql clear graph <http://GraphCmp/One>;
TTLP ('@prefix foaf: <http://i-dont-remember-it> .
_:me
a foaf:Person ;
foaf:knows [ foaf:nick "oerling" ; foaf:title "Mr." ; foaf:sha1 "abra" ] ;
foaf:knows [ foaf:nick "kidehen" ; foaf:title "Mr." ; foaf:sha1 "bra" ] ;
foaf:knows [ foaf:nick "aldo" ; foaf:title "Mr." ; foaf:sha1 "cada" ] .',
'', 'http://GraphCmp/One' );
sparql clear graph <http://GraphCmp/Two>;
TTLP ('@prefix foaf: <http://i-dont-remember-it> .
_:iv
foaf:knows [ foaf:title "Mr." ; foaf:sha1 "cada" ; foaf:nick "aldo" ] ;
foaf:knows [ foaf:sha1 "bra" ; foaf:title "Mr." ; foaf:nick "kidehen" ] ;
foaf:knows [ foaf:nick "oerling" ; foaf:sha1 "abra" ; foaf:title "Mr." ] ;
a foaf:Person .',
'', 'http://GraphCmp/Two' );
select DB.DBA.TEST_RDF_GRAPHS_DIFFER_EXP ( 'nonexisting graphs (equiv, of course)', 0,
'http://GraphCmp/NoSuch', 'http://GraphCmp/NoSuch',
100 );
select DB.DBA.TEST_RDF_GRAPHS_DIFFER_EXP ( 'throughout test on foafs (equiv)', 0,
'http://GraphCmp/One', 'http://GraphCmp/Two',
100 );
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples12"><title>Example for Adding triples to graph</title>
<programlisting><![CDATA[
SQL>SPARQL
INSERT INTO GRAPH <http://BookStore.com>
{ <http://www.dajobe.org/foaf.rdf#i> <http://purl.org/dc/elements/1.1/title> "SPARQL and RDF" .
<http://www.dajobe.org/foaf.rdf#i> <http://purl.org/dc/elements/1.1/date> <1999-01-01T00:00:00>.
<http://www.w3.org/People/Berners-Lee/card#i> <http://purl.org/dc/elements/1.1/title> "Design notes" .
<http://www.w3.org/People/Berners-Lee/card#i> <http://purl.org/dc/elements/1.1/date> <2001-01-01T00:00:00>.
<http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/title> "Fundamentals of Compiler Design" .
<http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/date> <2002-01-01T00:00:00>. };
callret-0
VARCHAR
_________________________________________________________________
Insert into <http://BookStore.com>, 6 triples -- done
1 Rows. -- 0 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples13"><title>Example for Updating triples from graph</title>
<para>A SPARQL/Update request that contains a triple to be deleted and a triple to be added (used here to correct a book title).
</para>
<programlisting><![CDATA[
SQL>SPARQL
MODIFY GRAPH <http://BookStore.com>
DELETE
{ <http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/title> "Fundamentals of Compiler Design" }
INSERT
{ <http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/title> "Fundamentals" };
callret-0
VARCHAR
_______________________________________________________________________________
Modify <http://BookStore.com>, delete 1 and insert 1 triples -- done
1 Rows. -- 20 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples14"><title>Example for Deleting triples from graph</title>
<para>The example below has a request to delete all records of old books (dated before year 2000)
</para>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
DELETE FROM GRAPH <http://BookStore.com> { ?book ?p ?v }
WHERE
{ GRAPH <http://BookStore.com>
{ ?book dc:date ?date
FILTER ( xsd:dateTime(?date) < xsd:dateTime("2000-01-01T00:00:00")).
?book ?p ?v.
}
};
_______________________________________________________________________________
Delete from <http://BookStore.com>, 6 triples -- done
1 Rows. -- 10 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples15"><title>Example for Copying triples from one graph to another</title>
<para>The next snippet copies records from one named graph to another based on a pattern:
</para>
<programlisting><![CDATA[
SQL>SPARQL clear graph <http://BookStore.com>;
SQL>SPARQL clear graph <http://NewBookStore.com>;
SQL>SPARQL
insert in graph <http://BookStore.com>
{
<http://www.dajobe.org/foaf.rdf#i> <http://purl.org/dc/elements/1.1/date> <1999-04-01T00:00:00> .
<http://www.w3.org/People/Berners-Lee/card#i> <http://purl.org/dc/elements/1.1/date> <1998-05-03T00:00:00> .
<http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/date> <2001-02-08T00:00:00>
};
SQL>SPARQL
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
INSERT INTO GRAPH <http://NewBookStore.com> { ?book ?p ?v }
WHERE
{ GRAPH <http://BookStore.com>
{ ?book dc:date ?date
FILTER ( xsd:dateTime(?date) > xsd:dateTime("2000-01-01T00:00:00")).
?book ?p ?v.
}
};
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://NewBookStore.com>, 6 triples -- done
1 Rows. -- 30 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples16"><title>Example for Moving triples from one graph to another</title>
<para>This example moves records from one named graph to another named graph based on a pattern:
</para>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
INSERT INTO GRAPH <http://NewBookStore.com>
{ ?book ?p ?v }
WHERE
{ GRAPH <http://BookStore.com>
{ ?book dc:date ?date .
FILTER ( xsd:dateTime(?date) > xsd:dateTime("2000-01-01T00:00:00")).
?book ?p ?v.
}
};
_______________________________________________________________________________
Insert into <http://NewBookStore.com>, 6 triples -- done
1 Rows. -- 10 msec.
SQL>SPARQL
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
DELETE FROM GRAPH <http://BookStore.com>
{ ?book ?p ?v }
WHERE
{ GRAPH <http://BookStore.com>
{ ?book dc:date ?date .
FILTER ( xsd:dateTime(?date) > xsd:dateTime("2000-01-01T00:00:00")).
?book ?p ?v.
}
};
_______________________________________________________________________________
Delete from <http://BookStore.com>, 3 triples -- done
1 Rows. -- 10 msec.
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples17"><title>Example for BBC SPARQL Collection</title>
<programlisting><![CDATA[
## All programmes related to James Bond:
PREFIX po: <http://purl.org/ontology/po/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?uri ?label
WHERE
{
?uri po:category
<http://www.bbc.co.uk/programmes/people/bmFtZS9ib25kLCBqYW1lcyAobm8gcXVhbGlmaWVyKQ#person> ;
rdfs:label ?label.
}
]]></programlisting>
<programlisting><![CDATA[
## Find all Eastenders broadcasta after 2009-01-01,
## along with the broadcast version & type
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>
PREFIX po: <http://purl.org/ontology/po/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?version_type ?broadcast_start
WHERE
{
<http://www.bbc.co.uk/programmes/b006m86d#programme> po:episode ?episode .
?episode po:version ?version .
?version a ?version_type .
?broadcast po:broadcast_of ?version .
?broadcast event:time ?time .
?time tl:start ?broadcast_start .
FILTER ( (?version_type != <http://purl.org/ontology/po/Version>)
&& (?broadcast_start > "2009-01-01T00:00:00Z"^^xsd:dateTime) )
}
]]></programlisting>
<programlisting><![CDATA[
## Find all programmes that featured both the Foo Fighters and Al Green
PREFIX po: <http://purl.org/ontology/po/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX mo: <http://purl.org/ontology/mo/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX tl: <http://purl.org/NET/c4dm/timeline.owl#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT DISTINCT ?programme ?label
WHERE
{
?event1 po:track ?track1 .
?track1 foaf:maker ?maker1 .
?maker1 owl:sameAs
<http://www.bbc.co.uk/music/artists/67f66c07-6e61-4026-ade5-7e782fad3a5d#artist> .
?event2 po:track ?track2 .
?track2 foaf:maker ?maker2 .
?maker2 owl:sameAs
<http://www.bbc.co.uk/music/artists/fb7272ba-f130-4f0a-934d-6eeea4c18c9a#artist> .
?event1 event:time ?t1 .
?event2 event:time ?t2 .
?t1 tl:timeline ?tl .
?t2 tl:timeline ?tl .
?version po:time ?t .
?t tl:timeline ?tl .
?programme po:version ?version .
?programme rdfs:label ?label .
}
]]></programlisting>
<programlisting><![CDATA[
## Get short synopsis' of EastEnders episodes
PREFIX po: <http://purl.org/ontology/po/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
SELECT ?t ?o
WHERE
{
<http://www.bbc.co.uk/programmes/b006m86d#programme> po:episode ?e .
?e a po:Episode .
?e po:short_synopsis ?o .
?e dc:title ?t
}
]]></programlisting>
<programlisting><![CDATA[
## Get short synopsis' of EastEnders episodes (with graph)
PREFIX po: <http://purl.org/ontology/po/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
SELECT ?g ?t ?o
WHERE
{
graph ?g
{
<http://www.bbc.co.uk/programmes/b006m86d#programme> po:episode ?e .
?e a po:Episode .
?e po:short_synopsis ?o .
?e dc:title ?t
}
}
]]></programlisting>
<programlisting><![CDATA[
## Get reviews where John Paul Jones' has been involved
PREFIX mo: <http://purl.org/ontology/mo/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX rev: <http://purl.org/stuff/rev#>
PREFIX po: <http://purl.org/ontology/po/>
SELECT DISTINCT ?r_name, ?rev
WHERE
{
{
<http://www.bbc.co.uk/music/artists/4490113a-3880-4f5b-a39b-105bfceaed04#artist> foaf:made ?r1 .
?r1 a mo:Record .
?r1 dc:title ?r_name .
?r1 rev:hasReview ?rev
}
UNION
{
<http://www.bbc.co.uk/music/artists/4490113a-3880-4f5b-a39b-105bfceaed04#artist> mo:member_of ?b1 .
?b1 foaf:made ?r1 .
?r1 a mo:Record .
?r1 dc:title ?r_name .
?r1 rev:hasReview ?rev
}
}
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples18"><title>Example usage of IN operator for retrieving all triples for each entity</title>
<para>To retrieve all triples for each entity for a given list of entities uris, one might use the following syntax:</para>
<programlisting><![CDATA[
SELECT ?p ?o
WHERE
{
?s ?p ?o .
FILTER ( ?s IN (<someGraph#entity1>, <someGraph#entity2>, ...<someGraph#entityN> ) )
}
]]></programlisting>
<para>So to demonstrate this feature, execute the following query:
</para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT DISTINCT ?p ?o
WHERE
{
?s ?p ?o .
FILTER ( ?s IN (<http://dbpedia.org/resource/Climate_change>, <http://dbpedia.org/resource/Social_vulnerability> ) )
}
LIMIT 100
p o
ANY ANY
_______________________________________________________________________________
http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://s.zemanta.com/ns#Target
http://s.zemanta.com/ns#title Climate change
http://s.zemanta.com/ns#targetType http://s.zemanta.com/targets#rdf
3 Rows. -- 10 msec.
]]></programlisting>
<tip><title>See Also:</title>
<para><link linkend="rdfsparulexamples6">Example usage of IN operator.</link></para>
</tip>
</sect5>
<sect5 id="rdfsparulexamples19"><title>Example for extending SPARQL via SQL for Full Text search: Variant I</title>
<para>To find all albums looked up by album name, one might use the following syntax:</para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT ?s ?o ?an ( bif:search_excerpt ( bif:vector ( 'In', 'Your' ) , ?o ) )
WHERE
{
?s rdf:type mo:Record .
?s foaf:maker ?a .
?a foaf:name ?an .
?s dc:title ?o .
FILTER ( bif:contains ( ?o, '"in your"' ) )
}
LIMIT 10;
http://musicbrainz.org/music/record/30f13688-b9ca-4fa5-9430-f918e2df6fc4 China in Your Hand Fusion China <b>in</b> <b>Your</b> Hand.
http://musicbrainz.org/music/record/421ad738-2582-4512-b41e-0bc541433fbc China in Your Hand T'Pau China <b>in</b> <b>Your</b> Hand.
http://musicbrainz.org/music/record/01acff2a-8316-4d4b-af93-97289e164379 China in Your Hand T'Pau China <b>in</b> <b>Your</b> Hand.
http://musicbrainz.org/music/record/4fe99b06-ac73-40dd-8be7-bdaefb014981 China in Your Hand T'Pau China <b>in</b> <b>Your</b> Hand.
http://musicbrainz.org/music/record/ac1cb011-6040-4515-baf2-59551a9884ac In Your Hands Stella One Eleven <b>In</b> <b>Your</b> Hands.
http://dbtune.org/magnatune/album/mercy-inbedinst In Your Bed - instrumental mix Mercy Machine <b>In</b> <b>Your</b> Bed mix.
http://musicbrainz.org/music/record/a09ae12e-3694-4f68-bf25-f6ff4f790962 A Word in Your Ear Alfie A Word <b>in</b> <b>Your</b> Ear.
http://dbtune.org/magnatune/album/mercy-inbedremix In Your Bed - the remixes Mercy Machine <b>In</b> <b>Your</b> Bed the remixes.
http://musicbrainz.org/music/record/176b6626-2a25-42a7-8f1d-df98bec092b4 Smoke Gets in Your Eyes The Platters Smoke Gets <b>in</b> <b>Your</b> Eyes.
http://musicbrainz.org/music/record/e617d90e-4f86-425c-ab97-efdf4a8a452b Smoke Gets in Your Eyes The Platters Smoke Gets <b>in</b> <b>Your</b> Eyes.
]]></programlisting>
<para>Note that the query will not show anything when there are triples like:</para>
<programlisting><![CDATA[
<x> <y> "In"
<z> <q> "Your"
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples20"><title>Example for extending SPARQL via SQL for Full Text search: Variant II</title>
<para>To get movies from DBpedia, where the query can contain terms from the title,
one might use the following syntax:</para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT ?s ?an ?dn ?o( bif:search_excerpt ( bif:vector ( 'Broken', 'Flowers' ) , ?o ) )
WHERE
{
?s rdf:type dbpedia-owl:Film .
?s dbpprop:name ?o .
FILTER ( bif:contains ( ?o, '"broken flowers"' ) )
OPTIONAL { ?s dbpprop:starring ?starring .}
OPTIONAL { ?s dbpprop:director ?director . }
OPTIONAL { ?starring dbpprop:name ?an . }
OPTIONAL { ?director dbpprop:name ?dn . }
};
http://dbpedia.org/resource/Broken_Flowers Tilda Swinton Jim Jarmusch Broken Flowers <b>Broken</b> <b>Flowers</b>.
http://dbpedia.org/resource/Broken_Flowers Swinton, Tilda Jim Jarmusch Broken Flowers <b>Broken</b> <b>Flowers</b>.
....
http://dbpedia.org/resource/Broken_Flowers Bill Murray Jim Jarmusch Music from Broken Flowers Music from <b>Broken</b> <b>Flowers</b>.
....
]]></programlisting>
<para>Note that the query will not show anything when there are triples like:</para>
<programlisting><![CDATA[
<x> <y> "Broken"
<z> <q> "Flowers"
]]></programlisting>
</sect5>
<sect5 id="rdfsparulexamples21"><title>Example for date manipulation of xsd types within SPARQL</title>
<para>This example shows usage of dateTime column truncation to date only
and performs a group by on this column:
</para>
<programlisting><![CDATA[
-- prepare the data by inserting triples in a graph:
SQL>SPARQL
INSERT INTO GRAPH <http://BookStore.com>
{
<http://www.dajobe.org/foaf.rdf#i> <http://purl.org/dc/elements/1.1/title> "SPARQL and RDF" .
<http://www.dajobe.org/foaf.rdf#i> <http://purl.org/dc/elements/1.1/date> <1999-01-01T00:00:00>.
<http://www.w3.org/People/Berners-Lee/card#i> <http://purl.org/dc/elements/1.1/title> "Design notes" .
<http://www.w3.org/People/Berners-Lee/card#i> <http://purl.org/dc/elements/1.1/date> <2001-01-01T00:00:00>.
<http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/title> "Fundamentals of Compiler Design" .
<http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/date> <2002-01-01T00:00:00>.
<http://www.ivan-herman.net/foaf.rdf#me> <http://purl.org/dc/elements/1.1/title> "RDF Store" .
<http://www.ivan-herman.net/foaf.rdf#me> <http://purl.org/dc/elements/1.1/date> <2001-03-05T00:00:00>.
<http://bblfish.net/people/henry/card#me> <http://purl.org/dc/elements/1.1/title> "Design RDF notes" .
<http://bblfish.net/people/henry/card#me> <http://purl.org/dc/elements/1.1/date> <2001-01-01T00:00:00>.
<http://hometown.aol.com/chbussler/foaf/chbussler.foaf#me> <http://purl.org/dc/elements/1.1/title> "RDF Fundamentals" .
<http://hometown.aol.com/chbussler/foaf/chbussler.foaf#me> <http://purl.org/dc/elements/1.1/date> <2002-01-01T00:00:00>.
};
_______________________________________________________
Insert into <http://BookStore.com>, 12 triples -- done
-- Find Count of Group by Dates
SQL>SPARQL
SELECT (xsd:date(bif:subseq(str(?a_dt), 0, 10))), count(*)
FROM <http://BookStore.com>
WHERE
{
?s <http://purl.org/dc/elements/1.1/date> ?a_dt
}
GROUP BY (xsd:date(bif:subseq(str(?a_dt), 0, 10)));
callret-0 callret-1
VARCHAR VARCHAR
__________________________________________________
1999-01-01 1
2001-01-01 2
2002-01-01 2
2001-03-05 1
4 Rows. -- 15 msec.
SQL>
]]></programlisting>
</sect5>
</sect4>
</sect3>
<sect3 id="sparqlbi"><title>Business Intelligence Extensions for SPARQL</title>
<para>
Virtuoso extends SPARQL with expressions in results, subqueries, aggregates and grouping.
These extensions allow a straightforward translation of arbitrary SQL queries to SPARQL.
This extension is called "SPARQL BI", because the primary objective is to match needs of Business Intelligence.
The extended features apply equally to querying physical quads or relational tables mapped through RDF views.
</para>
<note><para>In this section, many examples use the TPC-H namespace. You may test them on your local demo database.
They use data from the TPC-H dataset that is mapped into a graph with an IRI of the form
http://example.com/tpch. When testing, you should replace the fake host name "example.com" with the host name of your own installation
verbatim, that is as specified in the "DefaultHost" parameter in the [URIQA] section of the Virtuoso configuration file.</para></note>
<sect4 id="rdfsparqlaggregate"><title>Aggregates in SPARQL</title>
<para>Virtuoso extends SPARQL with SQL like aggregate and "group by" functionality. This functionality is
also available by embedding SPARQL text inside SQL, but the SPARQL extension syntax has the benefit
of also working over the SPARQL protocol and of looking more SPARQL-like.
</para>
<para>The supported aggregates are <emphasis>COUNT</emphasis>, <emphasis>MIN</emphasis>,
<emphasis>MAX</emphasis>, <emphasis>AVG</emphasis> and <emphasis>SUM</emphasis>. These can take an
optional <emphasis>DISTINCT</emphasis> keyword. These are permitted only in the selection part of a
select query. If a selection list consists of a mix of variables and aggregates, the non-aggregate
selected items are considered to be grouping columns and a <emphasis>GROUP BY</emphasis> over them is implicitly added
at the end of the generated SQL query. Virtuoso also supports explicit syntax for
<emphasis>GROUP BY</emphasis>, <emphasis>ORDER BY</emphasis>, <emphasis>LIMIT</emphasis> and <emphasis>OFFSET</emphasis>.
There is no explicit syntax for <emphasis>HAVING</emphasis> in Virtuoso SPARQL.
</para>
<para>If a selection consists of aggregates exclusively, the result set has one row with the values
of the aggregates. If there are aggregates and variables in the selection, the result set has as many
rows as there are distinct combinations of the variables; the aggregates are then calculated over each
such distinct combination, as if there were a SQL GROUP BY over all non-aggregates.
The implicit grouping pays attention to all subexpressions in the return list; say, if a result column expression is <code>(?x * max (?y))</code> then
<code>?y</code> is aggregated and <code>?x</code> is not so it is grouped by ?x.
This also means that if a result column expression is <code>(bif:year (?shipdate))</code> then a group is made for each distinct <code>?shipdate</code>,
i.e. up to 366 groups for each distinct year.
If you need one group per year, write explicit <code>GROUP BY (bif:year (?shipdate))</code>.
</para>
<para>With the count aggregate the argument may be either <emphasis>*</emphasis>, meaning counting all rows, or a variable
name, meaning counting all the rows where this variable is bound. If there is no implicit <emphasis>GROUP BY</emphasis>,
there can be an optional <emphasis>DISTINCT</emphasis> keyword before the variable that is the argument of an aggregate.
</para>
<para>There is a special syntax for counting distinct combinations of selected variables. This is:</para>
<programlisting><![CDATA[
SELECT COUNT DISTINCT ?v1 ... ?vn
FROM ....
]]></programlisting>
<para>User-defined aggregate functions are not supported in current version of the SPARQL compiler.</para>
<sect5 id="rdfsparqlaggregatepathexpressions"><title>Path Expressions</title>
<para>Virtuoso has support for paths consisting of dereferencing properties in SPARQL. Virtuoso allows
simple paths in expressions and has a separate feature for transitivity:</para>
<itemizedlist mark="bullet">
<listitem>S+>P: for "one or many values of P of S"</listitem>
<listitem>S*>P: for "zero or many values of P of S", so *> may form a LEFT OUTER JOIN whereas +> forms an INNER JOIN.</listitem>
<listitem>S|>P: is reserved for potential "single value of P of S or an error if there are many values"</listitem>
</itemizedlist>
<para>If this property is set (for example by an RDF View) then +> should be used.</para>
<para><emphasis>Simple Example</emphasis></para>
<programlisting><![CDATA[
SELECT ?f+>foaf:name ?f|>foaf:mbox WHERE { ?x foaf:name "Alice" . ?x foaf:knows ?f . FILTER (?f+>foaf:name = "John") }
]]></programlisting>
<para>means:</para>
<programlisting><![CDATA[
SELECT ?fname ?mbox
WHERE
{
?x foaf:knows ?f .
?x foaf:knows ?f .
OPTIONAL {?f foaf:mbox ?mbox} .
?f foaf:name ?fname .
?x foaf:name "Alice" .
?x foaf:knows ?f2 .
?f2 foaf:name "John" .
}
]]></programlisting>
<para><emphasis>Other Examples</emphasis></para>
<programlisting><![CDATA[
SPARQL
DEFINE sql:signal-void-variables 1
PREFIX tpcd: <http://www.openlinksw.com/schemas/tpcd#>
PREFIX oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
PREFIX sioc: <http://rdfs.org/sioc/ns#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT
?l+>tpcd:returnflag,
?l+>tpcd:linestatus,
sum(?l+>tpcd:linequantity) as ?sum_qty,
sum(?l+>tpcd:lineextendedprice) as ?sum_base_price,
sum(?l+>tpcd:lineextendedprice*(1 - ?l+>tpcd:linediscount)) as ?sum_disc_price,
sum(?l+>tpcd:lineextendedprice*(1 - ?l+>tpcd:linediscount)*(1+?l+>tpcd:linetax)) as ?sum_charge,
avg(?l+>tpcd:linequantity) as ?avg_qty,
avg(?l+>tpcd:lineextendedprice) as ?avg_price,
avg(?l+>tpcd:linediscount) as ?avg_disc,
count(1) as ?count_order
FROM <http://example.com/tpcd>
WHERE {
?l a tpcd:lineitem .
FILTER (?l+>tpcd:shipdate <= bif:dateadd ("day", -90, '1998-12-01'^^xsd:date)) }
ORDER BY ?l+>tpcd:returnflag ?l+>tpcd:linestatus
]]></programlisting>
<programlisting><![CDATA[
SPARQL
DEFINE sql:signal-void-variables 1
PREFIX tpcd: <http://www.openlinksw.com/schemas/tpcd#>
SELECT
?supp+>tpcd:acctbal,
?supp+>tpcd:name,
?supp+>tpcd:has_nation+>tpcd:name as ?nation_name,
?part+>tpcd:partkey,
?part+>tpcd:mfgr,
?supp+>tpcd:address,
?supp+>tpcd:phone,
?supp+>tpcd:comment
FROM <http://example.com/tpcd>
WHERE {
?ps a tpcd:partsupp; tpcd:has_supplier ?supp; tpcd:has_part ?part .
?supp+>tpcd:has_nation+>tpcd:has_region tpcd:name 'EUROPE' .
?part tpcd:size 15 .
?ps tpcd:supplycost ?minsc .
{ SELECT ?part min(?ps+>tpcd:supplycost) as ?minsc
WHERE {
?ps a tpcd:partsupp; tpcd:has_part ?part; tpcd:has_supplier ?ms .
?ms+>tpcd:has_nation+>tpcd:has_region tpcd:name 'EUROPE' .
} }
FILTER (?part+>tpcd:type like '%BRASS') }
ORDER BY
desc (?supp+>tpcd:acctbal)
?supp+>tpcd:has_nation+>tpcd:name
?supp+>tpcd:name
?part+>tpcd:partkey
]]></programlisting>
</sect5>
<sect5 id="rdfsparqlaggregateexamples"><title>Examples</title>
<sect6 id="rdfsparqlaggregateexamples1"><title>Example for count of physical triples in http://mygraph.com</title>
<programlisting><![CDATA[
SPARQL
SELECT COUNT (*)
FROM <http://mygraph.com>
WHERE {?s ?p ?o}
]]></programlisting>
<para><emphasis>Example for count of O's for each distinct P</emphasis></para>
<programlisting><![CDATA[
SPARQL define input:inference "http://mygraph.com"
SELECT ?p COUNT (?o)
FROM <http://mygraph.com>
WHERE {?s ?p ?o}
]]></programlisting>
</sect6>
<sect6 id="rdfsparqlaggregateexamples2"><title>Example for count of triples, including inferred triples and the count of
distinct O values</title>
<programlisting><![CDATA[
SPARQL define input:inference "http://mygraph.com"
SELECT COUNT (?p) COUNT (?o) COUNT (DISTINCT ?o)
FROM <http://mygraph.com>
WHERE {?s ?p ?o}
]]></programlisting>
</sect6>
<sect6 id="rdfsparqlaggregateexamples3"><title>Example for get number of distinct bindings of ?s ?p ?o</title>
<programlisting><![CDATA[
SPARQL define input:inference "http://mygraph.com"
SELECT count distinct ?s ?p ?o
FROM <http://mygraph.com>
WHERE {?s ?p ?o}
]]></programlisting>
</sect6>
<sect6 id="rdfsparqlaggregateexamples4"><title>Example for get counts and total prices of ordered items, grouped by item status</title>
<programlisting><![CDATA[
SPARQL
prefix tpch: <http://www.openlinksw.com/schemas/tpch#>
SELECT ?status count(*) sum(?extendedprice)
FROM <http://localhost.localdomain:8310/tpch>
WHERE {
?l a tpch:lineitem ;
tpch:lineextendedprice ?extendedprice ;
tpch:linestatus ?status .
}
]]></programlisting>
</sect6>
<sect6 id="rdfsparqlaggregateexamples5"><title>Example for get counts and total prices of ordered items, grouped by item status</title>
<para><emphasis>Example: A dataset of people, some duplicated</emphasis></para>
<para>Suppose there is a dataset with many people, some of them sharing the same name. To list them we would, ideally, execute the query:
</para>
<programlisting><![CDATA[
SPARQL
SELECT DISTINCT
(?name) ?person ?mail
WHERE {
?person rdf:type foaf:Person .
?person foaf:name ?name .
?person foaf:mbox_sha1sum ?mail
}
]]></programlisting>
<para>Unfortunately, the facility to apply DISTINCT to a part of the result set row (i.e. to ?name) does not currently exist.
(Although the above form is permitted, it's interpreted as being identical to 'SELECT DISTINCT ?name, ?person, ?mail WHERE ...')
If there's demand for such a feature then we may introduce an aggregate called, say, SPECIMEN, that will return the very first of the aggregated values. e.g.:
</para>
<programlisting><![CDATA[
SPARQL
SELECT ?name (specimen(?person)) (specimen(?mail))
WHERE
{
?person rdf:type foaf:Person .
?person foaf:name ?name .
?person foaf:mbox_sha1sum ?mail
}
]]></programlisting>
<para>As a workaround to this limitation, the MIN aggregate can be used, provided duplicates are few and there's no requirement
that ?person should correspond to ?mail
(i.e. the result should contain some person node and some mail node but they don't have to be connected by foaf:mbox_sha1sum):
</para>
<programlisting><![CDATA[
SPARQL
SELECT ?name (min(?person)) (min(?mail))
WHERE
{
?person rdf:type foaf:Person .
?person foaf:name ?name .
?person foaf:mbox_sha1sum ?mail
}
]]></programlisting>
<para>Otherwise, a complicated query is needed:</para>
<programlisting><![CDATA[
SPARQL
SELECT
?name
((SELECT (min (?person3))
WHERE {
?person3 rdf:type foaf:Person .
?person3 foaf:name ?name .
?person3 foaf:mbox_sha1sum ?mail } )) as ?person
?mail
WHERE {
{ SELECT distinct ?name
WHERE {
?person1 rdf:type foaf:Person .
?person1 foaf:name ?name .
?person1 foaf:mbox_sha1sum ?mail1 } }
{ SELECT ?name (min(?mail2)) as ?mail
WHERE {
?person2 rdf:type foaf:Person .
?person2 foaf:name ?name .
?person2 foaf:mbox_sha1sum ?mail2 } }
}
]]></programlisting>
</sect6>
<sect6 id="rdfsparqlaggregateexamples6"><title>Example quering dbpedia</title>
<para>The following example demonstrate how to query dbpedia. Suppose there is local onotlogy,
which has a datatype property hasLocation with a string containing city names. The query below finds
which of those cities are in dbpedia:</para>
<programlisting><![CDATA[
SPARQL
PREFIX dbpprop: <http://dbpedia.org/property/>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX vocab:<http://myexample.com/localOntology.rdf>
PREFIX dbpedia: <http://dbpedia.org/>
PREFIX dbpres: <http://dbpedia.org/resource/>
SELECT ?city
WHERE
{
?sub :location ?city .
FILTER(bif:exists(( ASK { ?subdb a dbo:City . ?subdb dbpprop:officialName ?city })))
}
]]></programlisting>
</sect6>
<sect6 id="rdfsparqlaggregateexamples7"><title>Example for MAX with HACING and GROOP BY</title>
<programlisting><![CDATA[
## Example "Find which town or city in
## the UK has the largest proportion of students.
PREFIX dbpedia-owl: <http://dbpedia.org/ontology/>
PREFIX dbpedia-owl-uni: <http://dbpedia.org/ontology/University/>
PREFIX dbpedia-owl-inst: <http://dbpedia.org/ontology/EducationalInstitution/>
SELECT ?town COUNT(?uni)
?pgrad ?ugrad
MAX(?population)
( ((?pgrad+?ugrad)/ MAX(?population))*100 ) AS ?percentage
WHERE
{
?uni dbpedia-owl-inst:country dbpedia:United_Kingdom ;
dbpedia-owl-uni:postgrad ?pgrad ;
dbpedia-owl-uni:undergrad ?ugrad ;
dbpedia-owl-inst:city ?town .
OPTIONAL
{
?town dbpedia-owl:populationTotal ?population .
FILTER (?population > 0 )
}
}
GROUP BY ?town ?pgrad ?ugrad
HAVING ( ( ( (?pgrad+?ugrad)/ MAX(?population) )*100 ) > 0 )
ORDER BY DESC 6
]]></programlisting>
</sect6>
</sect5>
<sect5 id="rdfsparqlaggregatenote"><title>Note on Aggregates and Inference</title>
<para>Inferencing is added to a SPARQL query only for those variables whose value is actually used. Thus,
</para>
<programlisting><![CDATA[
SELECT COUNT (*)
FROM <http://mygraph.com>
WHERE {?s ?p ?o}
]]></programlisting>
<para>will not return inferred values since s, p, and o are not actually used. In contrast,
</para>
<programlisting><![CDATA[
SPARQL
SELECT COUNT (?s) COUNT (?p) COUNT (?o)
FROM <http://mygraph.com>
WHERE {?s ?p ?o}
]]></programlisting>
<para>will also return all the inferred triples.
</para>
<para>
Note: This difference in behaviour may lead to confusion and will, therefore, likely be altered in the future.
</para>
</sect5>
</sect4>
<sect4 id="rdfsparqlarrowop"><title>Pointer Operator (<emphasis>+></emphasis> and <emphasis>*></emphasis>)</title>
<para>
When expressions occur in result sets, many variables are often introduced only for the purpose of passing a value from a triple pattern to the result expression.
This is inconvenient because many triple patterns are trivial. The presence of large numbers of variable names masks "interesting" variables that are used in more than once in pattern and which establish logical relationships between different parts of the query.
As a solution we introduce pointer operators.</para>
<para>
The <emphasis>+></emphasis> (pointer) operator allows referring to a property value without naming it as a variable and explicitly writing a triple pattern. We can shorten the example above to:</para>
<programlisting><![CDATA[SPARQL
prefix tpch: <http://www.openlinksw.com/schemas/tpch#>
SELECT ?l+>tpch:linestatus count(*) sum(?l+>tpch:lineextendedprice)
FROM <http://localhost.localdomain:8310/tpch>
WHERE { ?l a tpch:lineitem }]]></programlisting>
<para>
The <emphasis>?subject+>propertyname</emphasis> notation is equivalent to having a triple pattern <emphasis>?subject propertyname ?aux_var</emphasis> binding an auxiliary variable to the mentioned property of the subject, within the group pattern enclosing the reference.
For a SELECT, the enclosing group pattern is considered to be the top level pattern of the where clause or, in the event of a union, the top level of each term of the union.
Each distinct pointer adds exactly one triple pattern to the enclosing group pattern. Multiple uses of <emphasis>+></emphasis> with the same arguments do not each add a triple pattern.
(Having multiple copies of an identical pattern might lead to changes in cardinality if multiple input graphs were being considered.
If a lineitem had multiple discounts or extended prices, then we would get the cartesian product of both.)
</para>
<para>
If a property referenced via <emphasis>+></emphasis> is absent, the variable on the left side of the operator is not bound in the enclosing group pattern because it should be bound in all triple patterns where it appears as a field, including implicitly added patterns.
</para>
<para>
The <emphasis>?subject*>propertyname</emphasis> notation is introduced in order to access optional property values. It adds an OPTIONAL group <emphasis>OPTIONAL { ?subject propertyname ?aux_var }</emphasis>, not a plain triple pattern, so the binding of ?subject is not changed even if the object variable is not bound. If the property is set for all subjects in question then the results of <emphasis>*></emphasis> and <emphasis>+></emphasis> are the same. All other things being equal, the <emphasis>+></emphasis> operator produces better SQL code than <emphasis>*></emphasis> so use <emphasis>*></emphasis> only when it is really needed.</para>
</sect4>
<sect4 id="rdfsparqlnesting"><title>Subqueries in SPARQL</title>
<para>
Pure SPARQL does not allow binding a value that is not retrieved through a triple pattern.
We lift this restriction by allowing expressions in the result set and providing names for result columns.
We also allow a SPARQL SELECT statement to appear in another SPARQL statement in any place where a group pattern may appear.
The names of the result columns form the names of the variables bound, using values from the returned rows.
This resembles derived tables in SQL.</para>
<para>
For instance, the following statement finds the prices of the 1000 order lines with the biggest discounts:</para>
<programlisting><![CDATA[SPARQL
define sql:signal-void-variables 1
prefix tpch: <http://www.openlinksw.com/schemas/tpch#>
SELECT ?line ?discount (?extendedprice * (1 - ?discount)) as ?finalprice
FROM <http://localhost.localdomain:8310/tpch>
WHERE
{
?line a tpch:lineitem ;
tpch:lineextendedprice ?extendedprice ;
tpch:linediscount ?discount .
}
ORDER BY DESC (?extendedprice * ?discount)
LIMIT 1000]]></programlisting>
<para>
After ensuring that this query works correctly, we can use it to answer more complex questions.
Imagine that we want to find out how big the customers are who have received the biggest discounts.</para>
<programlisting><![CDATA[SPARQL
define sql:signal-void-variables 1
prefix tpch: <http://www.openlinksw.com/schemas/tpch#>
SELECT ?cust sum(?extendedprice2 * (1 - ?discount2)) max (?bigdiscount)
FROM <http://localhost.localdomain:8310/tpch>
WHERE
{
{
SELECT ?line (?extendedprice * ?discount) as ?bigdiscount
WHERE {
?line a tpch:lineitem ;
tpch:lineextendedprice ?extendedprice ;
tpch:linediscount ?discount . }
ORDER BY DESC (?extendedprice * ?discount)
LIMIT 1000
}
?line tpch:has_order ?order .
?order tpch:has_customer ?cust .
?cust tpch:customer_of ?order2 .
?order2 tpch:order_of ?line2 .
?line2 tpch:lineextendedprice ?extendedprice2 ;
tpch:linediscount ?discount2 .
}
ORDER BY (SUM(?extendedprice2 * (1 - ?discount2)) / MAX (?bigdiscount))]]></programlisting>
<para>
The inner select finds the 1000 biggest (in absolute value) discounts and their order lines. For each line we find orders of it, and the customer. For each customer found, we find all the orders he made and all the lines of each of the orders (variable ?line2).</para>
<para>
Note that the inner select does not contain FROM clauses. It is not required because the inner select inherits the access permissions of all the outer queries. It is also important to note that the internal variable bindings of the subquery are not visible in the outer query; only the result set variables are bound. Similarly, variables bound in the outer query are not accessible to the subquery.</para>
<para>
Note also the declaration <emphasis>define sql:signal-void-variables 1</emphasis> that forces the SPARQL compiler to signal errors if some variables cannot be bound due to misspelt names or attempts to make joins across disjoint domains. These diagnostics are especially important when the query is long.</para>
</sect4>
<sect4 id="rdfsparqlbackq"><title>Expressions in Triple Patterns</title>
<para>In addition to expressions in filters and result sets, Virtuoso allows the use of expressions in triples of a
CONSTRUCT pattern or WHERE pattern - an expression can be used instead of a constant or a variable name for a subject, predicate or object.
When used in this context, the expression is surrounded by backquotes.</para>
<para><emphasis>Example: With a WHERE Clause:</emphasis></para>
<para>The following example returns all the distinct 'fragment' parts of all subjects in all graphs that have some predicate whose value is equal to 2+2.</para>
<programlisting><![CDATA[
SQL>SPARQL SELECT distinct (bif:subseq (?s, bif:strchr (?s, '#')))
WHERE {
graph ?g {
?s ?p `2+2` .
FILTER (! bif:isnull (bif:strchr (?s, '#') ) )
} };
callret
VARCHAR
----------
#four
]]></programlisting>
<para>Inside a WHERE part, every expression in a triple pattern is replaced with new variable and a filter expression is added to the enclosing group. The new filter is an equality of the new variable and the expression. Hence the sample above is identical to:</para>
<programlisting><![CDATA[
SPARQL
SELECT distinct (bif:subseq (?s, bif:strchr (?s, '#')))
WHERE {
graph ?g {
?s ?p ?newvariable .
FILTER (! bif:isnull (bif:strchr (?s, '#') ) )
FILTER (?newvariable = (2+2)) .
} }
]]></programlisting>
<para><emphasis>Example: With CONSTRUCT</emphasis></para>
<programlisting><![CDATA[
CONSTRUCT {
<http://bio2rdf.org/interpro:IPR000181>
<http://bio2rdf.org/ns/bio2rdf#hasLinkCount>
`(SELECT (count(?s)) as ?countS
WHERE { ?s ?p <http://bio2rdf.org/interpro:IPR000181> })` }
WHERE { ?s1 ?p1 ?o1 } limit 1
]]></programlisting>
<para>The result should be:</para>
<programlisting><![CDATA[
<http://bio2rdf.org/interpro:IPR000181> <http://bio2rdf.org/ns/bio2rdf#hasLinkCount> "0"^^<http://www.w3.org/2001/XMLSchema#integer> .
]]></programlisting>
<para><emphasis>Example: Inserting into a graph using an expression</emphasis></para>
<programlisting><![CDATA[
SQL>SPARQL insert into graph <http://MyNewGraph.com/> {
<http://bio2rdf.org/interpro:IPR000181>
<http://bio2rdf.org/ns/bio2rdf#hasLinkCount>
`(SELECT (count(?s)) as ?countS
WHERE { ?s ?p <http://bio2rdf.org/interpro:IPR000181> })` }
WHERE { ?s1 ?p1 ?o1 } limit 1 ;
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://MyNewGraph.com/>, 1 triples -- done
1 Rows. -- 30 msec.
]]></programlisting>
</sect4>
</sect3>
</sect2>
<sect2 id="rdfsparqlinline"><title>SPARQL Inline in SQL</title>
<para>Virtuoso extends the SQL 92 syntax with SPARQL queries and subqueries. Instead of writing a SQL SELECT query or subquery, one can write the SPARQL keyword and a SPARQL query after the keyword.</para>
<programlisting>
SQL>SPARQL SELECT DISTINCT ?p WHERE { graph ?g { ?s ?p ?o } };
p
varchar
----------
http://example.org/ns#b
http://example.org/ns#d
http://xmlns.com/foaf/0.1/name
http://xmlns.com/foaf/0.1/mbox
...
SQL>SELECT distinct subseq ("p", strchr ("p", '#')) as fragment
FROM (SPARQL SELECT DISTINCT ?p WHERE { graph ?g { ?s ?p ?o } } ) as all_predicates
WHERE "p" like '%#%';
fragment
varchar
----------
#query
#data
#name
#comment
...
</programlisting>
<para>Note that names of variables returned from SPARQL are always case-sensitive and no case mode rules apply to them.
Depending on the CaseMode parameter in the Virtuoso configuration file, double quotes should be used if necessary to refer to them in surrounding SQL code.
</para>
<para>
It is possible to pass parameters to a SPARQL query via a Virtuoso-specific syntax extension.
<emphasis>??</emphasis> or <emphasis>$?</emphasis> indicates a positional parameter similar to <emphasis>?</emphasis> in plain SQL. <emphasis>??</emphasis> can be used in graph patterns or anywhere in place of a SPARQL variable.
The value of a parameter should be passed in SQL form, i.e. this should be a number or a untyped string.
An IRI ID can be passed in all cases where an absolute IRI can, except the obvious case of when the variable is an argument of a function that requires string.
If the parameter is used in the 'graph', 'subject' or 'object' position of the SPARQL pattern, the string parameter is converted into an IRI automatically. In other cases an IRI string is indistinguishable from a string literal, so it is necessary to call the built-in SPARQL function <emphasis>iri()</emphasis> , e.g. <emphasis>iri (??)</emphasis>.
Using this notation, any dynamic SQL client (whether ODBC, JDBC or some other) can execute parameterized SPARQL queries, binding parameters just as with dynamic SQL.
</para>
<programlisting><![CDATA[
SQL> create function param_passing_demo ()
{
declare stat, msg varchar;
declare mdata, rset any;
exec ('SPARQL SELECT ?s WHERE { graph ?g { ?s ?? ?? }}',
stat, msg,
vector ( /* Vector of two parameters */
'http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#int1',
4 ),
10, /* Max no of rows */
mdata, /* Variable to get metadata */
rset ); /* Variable to get result-set */
if (length (rset) = 0)
signal ('23000',
'No data found, try demo database with installed Virtuoso tutorials');
return rset[0][0];
}
SQL> SELECT param_passing_demo ();
callret
VARCHAR
_______________________________________________________________________________
http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#four
1 Rows. -- 00000 msec.
]]></programlisting>
<para>An inline SPARQL query can refer to SQL variables that are in scope in the SQL query or stored procedure containing it.
Virtuoso extends the SPARQL syntax with a special notation to this effect. A reference to SQL variable X can be written as <emphasis>?:X</emphasis> or <emphasis>$:X</emphasis>.
A reference to column <emphasis>C</emphasis> of a table or a sub-select with alias <emphasis>T</emphasis> can be written as <emphasis>?:T.C</emphasis> or <emphasis>$:T.C</emphasis>.
Both notations can be used in any place where a variable name is allowed, except the 'AS' clause described below.
</para>
<para>A column of a result set of a SPARQL SELECT can be used in SQL code inside a for statement just like any column from a SQL select.
</para>
<para>SQL rules about double-quoted names are applicable to variables that are passed to a SPARQL query or selected from one.
If a variable name contains unusual characters or should not be normalized according to SQL conventions then the
name should use double quotes for escaping. e.g., the notation <emphasis>?:"OrderLine"</emphasis> will always refer to variable or column
titled <emphasis>OrderLine</emphasis> whereas <emphasis>?:OrderLine</emphasis> can be converted to <emphasis>ORDERLINE</emphasis> or <emphasis>orderline</emphasis>.
</para>
<para>It is safer to avoid using variable names that conflict with column names of RDF system tables, esp. <emphasis>G</emphasis>, <emphasis>S</emphasis>, <emphasis>P</emphasis> and <emphasis>O</emphasis>.
These names are not reserved now but they may cause subtle bugs when an incorrect SPARQL subquery is compiled into SQL code that refers to identically named table columns.
Some of these names may be rejected as syntax errors by future Virtuoso versions.
</para>
<programlisting><![CDATA[
SQL> create procedure sql_vars_demo ()
{
#pragma prefix sort0: <http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#>
declare RES varchar;
declare obj integer;
result_names (RES);
obj := 4;
for (SPARQL SELECT ?subj WHERE { graph ?g { ?subj sort0:int1 ?:obj } } ) do
result ("subj");
}
SQL> sql_vars_demo ();
RES
VARCHAR
_______________________________________________________________________________
http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#four
1 Rows. -- 00000 msec.
]]></programlisting>
<para>The example also demonstrates the Virtuoso/PL pragma line for procedure-wide declarations of namespace prefixes.
This makes the code more readable and eliminates duplicate declarations of namespace prefixes when the procedure
contains many SPARQL fragments that refer to a common set of namespaces.
</para>
<para>A SPARQL ASK query can be used as an argument of the SQL EXISTS predicate.
</para>
<programlisting><![CDATA[
create function sparql_ask_demo () returns varchar
{
if (exists (sparql ask where { graph ?g { ?s ?p 4}}))
return 'YES';
else
return 'NO';
}
SQL> SELECT sparql_ask_demo ();
_______________________________________________________________________________
YES
]]>
</programlisting>
<sect3 id="rdfcontrollingsparqloutputtypes"><title>Controlling SPARQL Output Data Types</title>
<para>The compilation of a SPARQL query may depend on an environment that is usually provided by the SPARQL protocol and which includes the default graph URI. Environment settings that come from the SPARQL protocol may override settings in the text of a SPARQL query. To let an application configure the environment for a query, SPARQL's syntax has been extended with the 'define' clause:</para>
<programlisting>
define parameter-qname parameter-value
</programlisting>
<para>Examples of supported parameters are <emphasis>output:valmode</emphasis> and <emphasis>output:format</emphasis></para>
<para>
<emphasis>output:valmode</emphasis> specifies which data types (i.e. representation) should be used for values in the result set. The default is "SQLVAL",
meaning that a query returns result set values in SQL format and behaves as a typical SQL select - IRIs and string literals
are returned as strings, making the output compatible with ODBC and the standard SQL routines. To compose triple vectors in Virtuoso PL code, an
application may need data in long format. A valmode of "LONG" means that IRIs are returned as IRI_IDs and string literals may be returned as special "RDF boxes"
even if they are actually plain strings. This may cause problems if these new datatypes are not known to the data recipient or if IRIs come from RDF
Views (in which case IRI_IDs are created on the fly and 'pollute' the database), but it can result in fewer data conversions and thus better speed if used
properly. "AUTO" disables all types of conversion for the result set, so the latter can comprise a mix of values across "SQLVAL" and "LONG" value modes, as well as
some internal representations. It is better to avoid using this mode in user applications because the output may change from version to version.
</para>
<para>If the query contains a</para>
<programlisting>
define output:valmode 'LONG'
</programlisting>
<para>clause then all returned values are in long format. e.g., the following query returns IRI_ID's instead of IRI strings.</para>
<programlisting>
SQL>SPARQL define output:valmode 'LONG' SELECT distinct ?p WHERE { graph ?g { ?s ?p ?o } };
p
----------
#i1000001
#i1000003
#i1000005
#i1000006
...
</programlisting>
<para><emphasis>output:format</emphasis> instructs the SPARQL compiler that the result of the query should be serialized into an RDF document -
that document will be returned as a single column of a single row result set.
<emphasis>output:format</emphasis> is especially useful if a SPARQL CONSTRUCT or SPARQL DESCRIBE query is executed directly via an ODBC or JDBC database connection
and the client cannot receive the resulting dictionary of triples (there's no way to transfer such an object via ODBC).
Using this option, the client can receive the document that contains the whole result set of a SELECT or the dictionary of triples of a CONSTRUCT/DESCRIBE, and parse it locally.
</para>
<para>
Supported values for <emphasis>output:format</emphasis> are <emphasis>RDF/XML</emphasis> and <emphasis>TURTLE</emphasis> (or <emphasis>TTL</emphasis>).
If both <emphasis>output:valmode</emphasis> and <emphasis>output:format</emphasis> are specified, <emphasis>output:format</emphasis> has higher priority,
raising an error if <emphasis>output:valmode</emphasis> is set to a value other than <emphasis>LONG</emphasis>.
</para>
<para>
When a SPARQL query is compiled, the compiler checks whether the result set is to be sent to a remote ODBC/JDBC client or used in some other way.
The compiler will automatically set <emphasis>output:format</emphasis> to <emphasis>TURTLE</emphasis> if compiling for execution by an SQL client.
</para>
<para>
The example below demonstrates how different values of <emphasis>output:format</emphasis> affect the result of SPARQL SELECT.
Note 10 rows and 4 columns in the first result, and single LONG VARCHAR in the others.
When using the ISQL client, use the 'set blobs on;' directive if fetching long texts to avoid receiving a 'data truncated' warning.
</para>
<programlisting><![CDATA[
SQL> SPARQL SELECT * WHERE {graph ?g { ?s ?p ?o }} limit 10;
g s p o
VARCHAR VARCHAR VARCHAR VARCHAR
______________________________________________________________________
http://local.virt/DAV/bound/manifest.rdf nodeID://1000000000 http://example.com/test#query http://local.virt/DAV/bound/bound1.rq
. . .
http://local.virt/DAV/examples/manifest.rdf nodeID://1000000019 http://example.com/test#query http://local.virt/DAV/examples/ex11.2.3.1_1.rq
10 Rows. -- 00000 msec.
SQL> SPARQL define output:format "TTL" SELECT * WHERE {graph ?g { ?s ?p ?o }} limit 10;
callret-0
LONG VARCHAR
_______________________________________________________________________________
@prefix :rdf <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix :rs <http://www.w3.org/2005/sparql-results#> .
@prefix :xsd <http://www.w3.org/2001/XMLSchema#> .
[ rdf:type rs:results ;
rs:result [
rs:binding [ rs:name "g" ; rs:value <http://local.virt/DAV/bound/manifest.rdf> ] ;
rs:binding [ rs:name "s" ; rs:value _:nodeID1000000000 ] ;
rs:binding [ rs:name "p" ; rs:value <http://example.com/test#query> ] ;
rs:binding [ rs:name "o" ; rs:value <http://local.virt/DAV/bound/bound1.rq> ] ;
] ;
. . .
rs:result [
rs:binding [ rs:name "g" ; rs:value <http://local.virt/DAV/examples/manifest.rdf> ] ;
rs:binding [ rs:name "s" ; rs:value _:nodeID1000000019 ] ;
rs:binding [ rs:name "p" ; rs:value <http://example.com/test#query> ] ;
rs:binding [ rs:name "o" ; rs:value <http://local.virt/DAV/examples/ex11.2.3.1_1.rq> ] ;
] ;
] .
1 Rows. -- 00000 msec.
SQL> SPARQL define output:format "RDF/XML" SELECT * WHERE {graph ?g { ?s ?p ?o }} LIMIT 10;
callret-0
LONG VARCHAR
_______________________________________________________________________________
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rs="http://www.w3.org/2005/sparql-results#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#" >
<rs:results rdf:nodeID="rset">
<rs:result rdf:nodeID="sol206">
<rs:binding rdf:nodeID="sol206-0" rs:name="g"><rs:value rdf:resource="http://local.virt/DAV/bound/manifest.rdf"/></rs:binding>
<rs:binding rdf:nodeID="sol206-1" rs:name="s"><rs:value rdf:nodeID="1000000000"/></rs:binding>
<rs:binding rdf:nodeID="sol206-2" rs:name="p"><rs:value rdf:resource="http://example.com/test#query"/></rs:binding>
<rs:binding rdf:nodeID="sol206-3" rs:name="o"><rs:value rdf:resource="http://local.virt/DAV/bound/bound1.rq"/></rs:binding>
</rs:result>
. . .
<rs:result rdf:nodeID="sol5737">
<rs:binding rdf:nodeID="sol5737-0" rs:name="g"><rs:value rdf:resource="http://local.virt/DAV/examples/manifest.rdf"/></rs:binding>
<rs:binding rdf:nodeID="sol5737-1" rs:name="s"><rs:value rdf:nodeID="1000000019"/></rs:binding>
<rs:binding rdf:nodeID="sol5737-2" rs:name="p"><rs:value rdf:resource="http://example.com/test#query"/></rs:binding>
<rs:binding rdf:nodeID="sol5737-3" rs:name="o"><rs:value rdf:resource="http://local.virt/DAV/examples/ex11.2.3.1_1.rq"/></rs:binding>
</rs:result>
</rs:results>
</rdf:RDF>
1 Rows. -- 00000 msec.
]]></programlisting>
<para>SPARQL CONSTRUCT and SPARQL DESCRIBE results are serialized as one would expect:</para>
<programlisting><![CDATA[
SQL> SPARQL
define output:format "TTL"
CONSTRUCT { ?s ?p "004" }
WHERE
{
graph ?g { ?s ?p 4 }
};
callret-0
LONG VARCHAR
_______________________________________________________________________________
<http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#four> <http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#int1> "004" .
_:b1000000913 <http://www.w3.org/2001/sw/DataAccess/tests/result-set#index> "004" .
1 Rows. -- 00000 msec.
SQL> SPARQL
define output:format "RDF/XML"
CONSTRUCT { ?s ?p "004" }
WHERE
{
graph ?g { ?s ?p 4 }
};
callret-0
LONG VARCHAR
_______________________________________________________________________________
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description about="http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#four"><ns0pred:int1 xmlns:ns0pred="http://www.w3.org/2001/sw/DataAccess/tests/data/Sorting/sort-0#">004</ns0pred:int1></rdf:Description>
<rdf:Description rdf:nodeID="b1000000913"><ns0pred:index xmlns:ns0pred="http://www.w3.org/2001/sw/DataAccess/tests/result-set#">004</ns0pred:index></rdf:Description>
</rdf:RDF>
1 Rows. -- 00000 msec.
]]></programlisting>
<para>SPARQL ASK returns a non-empty result set if a match is found for the graph pattern, an empty result set otherwise. If <emphasis>output:format</emphasis> is specified then the query makes a 'boolean result' document instead:</para>
<programlisting><![CDATA[
SQL> SPARQL ASK WHERE {graph ?g { ?s ?p 4 }};
__ask_retval
INTEGER
_______________________________________________________________________________
1
1 Rows. -- 00000 msec.
SQL> SPARQL ASK WHERE {graph ?g { ?s ?p "no such" }};
__ask_retval
INTEGER
_______________________________________________________________________________
0 Rows. -- 00000 msec.
SQL> SPARQL define output:format "TTL" ASK WHERE {graph ?g { ?s ?p 4 }};
callret
VARCHAR
_______________________________________________________________________________
@prefix :rdf <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix :rs <http://www.w3.org/2005/sparql-results#> .
[ rdf:type rs:results ; rs:boolean TRUE ]
1 Rows. -- 00000 msec.
SQL> SPARQL define output:format "RDF/XML" ASK WHERE {graph ?g { ?s ?p 4 }};
callret
VARCHAR
_______________________________________________________________________________
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rs="http://www.w3.org/2005/sparql-results#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#" >
<rs:results rdf:nodeID="rset">
<rs:boolean rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">1</rs:boolean></results></rdf:RDF>
1 Rows. -- 00000 msec.
]]></programlisting>
</sect3>
</sect2>
<sect2 id="rdfapi">
<title>API Functions</title>
<para>
SPARQL can be used inline wherever SQL can be used.
The only API functions that one needs to know are the ones for loading RDF data into the store.
Dynamic SQL client applications can issue SPARQL queries against Virtuoso through the regular SQL client API, ODBC, JDBC or any other supported API, simply by prefixing the SPARQL query with the SPARQL keyword. Parameters work just as with dynamic SQL.
Stored procedures can have SPARQL expressions inline and can declare cursors over SPARQL result sets.
</para>
<para>
Value conversions between SQL and SPARQL are most often automatic and
invisible. In some cases one needs to be aware of the different
SPARQL value representations (valmodes). SPARQL offers declarations
for specifying whether returned graphs are to be serialized as XML
or Turtle, or whether these will be hash tables of
triples. See <link linkend="fn_dict_new"><function>dict_new()</function></link> and related functions for a description of the hash table SQL data type.
The use of dict's is convenient for further programmatic processing of graphs.
</para>
<para>RDF-related procedures use Virtuoso/PL vectors
and dictionaries to represent RDF triples and sets of triples.</para>
<para><emphasis>Valmode</emphasis> means the "format of values returned by an
expression", i.e. 'short', 'long' or 'SQL value'.</para>
<para><emphasis>Triple vector</emphasis> is a vector (array) of S, P and O, where all values are in
'long' formats, i.e. IRI_ID's for IRI values, numbers or datetimes for corresponding XMLSchema types, special "RDF box" objects if O is neither string nor IRI.</para>
<para><emphasis>Dictionary of triples</emphasis> or <emphasis>Hash table of triples</emphasis> is an
dictionary object made by the SQL function <emphasis>dict_new ()</emphasis> whose keys are
triple vectors and values are not specified; this is a good storage
format for an unordered set of distinct triples.</para>
<para><emphasis>Dictionary of blank node names</emphasis> is a dictionary used for tricky
processing of a number of TURTLE or RDF /XML descriptions of subgraphs
that come from a common graph. Imagine a situation where different
descriptions actually refer to the same blank nodes of the original graph
and, moreover, the application that generates these descriptions always
generates the same blank node id string for the same node. A reader of
descriptions can correctly join described subgraphs into one big
subgraph by filling in a dictionary that contains blank node id strings
as keys and IRI_ID's assigned to those strings as dependent data.
The sharing of the same node dictionary by all readers of an application will ensure that no blank node is duplicated.</para>
<sect3 id="rdfapidataimport"><title>Data Import</title>
<sect4 id="rdfapidataimportttlp"><title>Using TTLP</title>
<para>DB.DBA.TTLP() parses TTL (TURTLE or N3 resource) and places its triples into DB.DBA.RDF_QUAD.</para>
<programlisting>
create procedure DB.DBA.TTLP (
in strg any, -- text of the resource
in base varchar, -- base IRI to resolve relative IRIs to absolute
in graph varchar, -- target graph IRI, parsed triples will appear in that graph.
in flags int) -- bitmask of flags that permit some sorts of syntax errors in resource, use 0.
</programlisting>
<para>For loading a file of any great length, it is more practical to use
the file_to_string_output function.
</para>
<para>It is important the file be accessible to the Virtuoso server. You need to have set properly set the
<emphasis>DirsAllowed</emphasis> parameter value in the section [Parameters] of the Virtuoso database INI file.
For example on Windows it could be:
</para>
<programlisting>
virtuoso.ini file:
[Parameters]
...
DirsAllowed = .\tmp
...
</programlisting>
<para>So, in the example, the file you want to import from, should be in the tmp folder or in a subfolder.
Note that this example folder is a subfolder of the Virtuoso Server working directory.
</para>
<programlisting>
SQL> DB.DBA.TTLP (file_to_string_output ('.\tmp\data.ttl'), '', 'http://my_graph', 0);
</programlisting>
</sect4>
<sect4 id="rdfapidataimportttlpmt"><title>Using TTLP_MT</title>
<para>The DB.DBA.TTLP_MT() procedure is like DB.DBA.TTLP() but loads the file on multiple threads,
using parallel I/O and multiprocessing if available. The function does not leave a transaction log.
Hence, after a successful load, one should execute the checkpoint statement to make sure that a
server restart does not wipe out the results.
</para>
<programlisting>
create procedure DB.DBA.TTLP_MT (
in strg any, -- text of the resource
in base varchar, -- base IRI to resolve relative IRIs to absolute
in graph varchar, -- target graph IRI, parsed triples will appear in that graph.
in flags int) -- flags, use 0
</programlisting>
</sect4>
<sect4 id="rdfapidataimportttlpmt"><title>Using RDF_LOAD_RDFXML_MT</title>
<para>For loading large resources when transactional integrity is not important (loading of a single resource may take more than one transaction)
you can use also the <emphasis>DB.DBA.RDF_LOAD_RDFXML_MT()</emphasis> procedure:</para>
<programlisting>
create procedure DB.DBA.RDF_LOAD_RDFXML_MT (
in strg varchar, -- text of the resource
in base varchar, -- base IRI to resolve relative IRIs to absolute
in graph varchar) -- target graph IRI, parsed triples will appear in that graph.
</programlisting>
<para>The following example demonstrates importing data from the RDF resource with URI: http://www.w3.org/People/Berners-Lee/card</para>
<programlisting><![CDATA[
SQL>create procedure MY_LOAD_FILE (in full_uri varchar, in in_resultset integer := 0)
{
declare REPORT varchar;
declare graph_uri, dattext varchar;
declare app_env any;
app_env := null;
whenever sqlstate '*' goto err_rep;
if (not in_resultset)
result_names (REPORT);
dattext := cast (XML_URI_GET_AND_CACHE (full_uri) as varchar);
MY_SPARQL_REPORT (sprintf ('Downloading %s: %d bytes',
full_uri, length (dattext) ) );
graph_uri := full_uri;
DELETE FROM RDF_QUAD WHERE G = DB.DBA.RDF_MAKE_IID_OF_QNAME (graph_uri);
DB.DBA.RDF_LOAD_RDFXML_MT (dattext, full_uri, graph_uri);
return graph_uri;
err_rep:
result (sprintf ('%s: %s', __SQL_STATE, __SQL_MESSAGE));
return graph_uri;
}
;
Done. -- 0 msec.
SQL>create procedure MY_SPARQL_REPORT(in strg varchar)
{
if (__tag(strg) <> 182)
strg := cast (strg as varchar) || sprintf (' -- not a string, tag=%d', __tag(strg));
strg := replace (strg, 'SPARQL_DAV_DATA_URI()', '\044{SPARQL_DAV_DATA_URI()}');
strg := replace (strg, 'SPARQL_DAV_DATA_PATH()', '\044{SPARQL_DAV_DATA_PATH()}');
strg := replace (strg, 'SPARQL_FILE_DATA_ROOT()', '\044{SPARQL_FILE_DATA_ROOT()}');
result (strg);
}
;
Done. -- 0 msec.
SQL> MY_LOAD_FILE('http://www.w3.org/People/Berners-Lee/card');
REPORT
VARCHAR
_______________________________________________________________________________
Downloading http://www.w3.org/People/Berners-Lee/card: 17773 bytes
1 Rows. -- 4046 msec.
SQL>SPARQL
SELECT *
FROM <http://www.w3.org/People/Berners-Lee/card>
WHERE {?s ?p ?o} ;
s p o
VARCHAR VARCHAR VARCHAR
__________________________________________________________________________________________________________
http://bblfish.net/people/henry/card#me http://xmlns.com/foaf/0.1/name Henry Story
http://www.w3.org/People/Berners-Lee/card#i http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.w3.org/People/Berners-Lee/card#i http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.w3.org/2000/10/swap/pim/contact#Male
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/nick TimBL
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/nick timbl
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/mbox mailto:timbl@w3.org
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/mbox_sha1sum 965c47c5a70db7407210cef6e4e6f5374a525c5c
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://bblfish.net/people/henry/card#me
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://hometown.aol.com/chbussler/foaf/chbussler.foaf#me
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://danbri.org/foaf#danbri
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://norman.walsh.name/knows/who#norman-walsh
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://www.aaronsw.com/about.xrdf#aaronsw
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://www.ivan-herman.net/foaf.rdf#me
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://www.w3.org/People/Berners-Lee/card#amy
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/knows http://dig.csail.mit.edu/People/RRS
..........
]]></programlisting>
</sect4>
<sect4 id="rdfapidataimportttlphash"><title>Using RDF_TTL2HASH</title>
<para>The DB.DBA.RDF_TTL2HASH() does not load TTL content, instead it returns a dictionary of triples in 'long valmode'.</para>
<programlisting>
create function DB.DBA.RDF_TTL2HASH (
in strg any,
in base varchar,
in graph varchar ) returns any
</programlisting>
<para>Parameter <emphasis>flags</emphasis> is useful when the syntax of the resource is TURTLE-like, but not correct TURTLE.
By default, use zero value.
Add 1 to let string literals contain end-of-line characters.
Add 2 to suppress error messages on blank node verbs.
Add 4 to allow variables instead of blank nodes.
Add 8 to silently skip triples with literal subjects.
</para>
</sect4>
<sect4 id="rdfapidataimportloadrdfxml"><title>Using RDF_LOAD_RDFXML</title>
<para>The DB.DBA.RDF_LOAD_RDFXML() procedure parses RDF/XML and places its triples into DB.DBA.RDF_QUAD.</para>
<programlisting>
create procedure DB.DBA.RDF_LOAD_RDFXML (
in strg any, -- text of and XML document
in base_iri varchar, -- base IRI to resolve relative IRIs
in graph_iri varchar ) -- the IRI of destination graph
</programlisting>
<para>See <link linkend="rdfsparqlrulespecifywhatindexexample">example</link></para>.
</sect4>
<sect4 id="rdfapidataimportloadrdfuri"><title>Using RDF_QUAD_URI, RDF_QUAD_URI_L and RDF_QUAD_URI_L_TYPED</title>
<para>To insert a single quad into DB.DBA.RDF_QUAD() table, use one of these procedures:</para>
<programlisting>
-- Simple insertion of a quad where the object is a node
create procedure DB.DBA.RDF_QUAD_URI (
in g_uri varchar, in s_uri varchar, in p_uri varchar,
in o_uri varchar ) -- IRI string or IRI_ID
-- Simple insertion of a quad where the object is a literal value in 'SQL valmode'
create procedure DB.DBA.RDF_QUAD_URI_L (
in g_uri varchar, in s_uri varchar, in p_uri varchar,
in o_lit any ) -- string, number or datetime, NULL is not allowed
create procedure DB.DBA.RDF_QUAD_URI_L_TYPED (
in g_uri varchar, in s_uri varchar, in p_uri varchar,
in o_lit any, -- string value of the literal
in dt any, -- datatype as IRI string or IRI_ID, can be NULL
in lang varchar ) -- language as string or NULL
</programlisting>
</sect4>
<para>Arguments g_uri, s_uri and p_uri of these three functions should be IRI strings or IRI_IDs.
All string arguments should be in UTF-8 encoding, otherwise they will be stored but are not queryable via SPARQL.</para>
</sect3>
<sect3 id="rdfapidataexport"><title>Data Export</title>
<para>These two procedures serialize a vector of triples into a session, in TURTLE or RDF/XML syntax.
In their current versions, every triple is printed in a separate top-level record (say, in an rdf:Description tag), without any pretty-printing or nesting optimization.
</para>
<programlisting>
create procedure DB.DBA.RDF_TRIPLES_TO_TTL (
inout triples any, -- vector of triples in 'long valmode'.
inout ses any ) -- an output stream in server default encoding
create procedure DB.DBA.RDF_TRIPLES_TO_RDF_XML_TEXT (
inout triples any, -- vector of triples in 'long valmode'.
in print_top_level integer, -- zero if only rdf:Description tags should be written,
-- non-zero if the rdf:RDF top-level element should also be written
inout ses any ) -- an output stream in server default encoding
</programlisting>
</sect3>
<sect3 id="rdfapidataquery"><title>Data query</title>
<programlisting>
-- Local execution of SPARQL via SPARQL protocol, produces a result set of SQL values.
create procedure DB.DBA.SPARQL_EVAL (
in query varchar, -- text of SPARQL query to execute
in dflt_graph varchar, -- default graph IRI, if not NULL then this overrides what's specified in query
in maxrows integer ) -- limit on numbers of rows that should be returned.
-- Similar to SPARQL_EVAL, but returns a vector of vectors of SQL values.
create function DB.DBA.SPARQL_EVAL_TO_ARRAY (
in query varchar, -- text of SPARQL query to execute
in dflt_graph varchar, -- default graph IRI, if not NULL then this overrides what's specified in query
in maxrows integer ) -- limit on numbers of rows that should be returned.
returns any
</programlisting>
<programlisting>
-- Remote execution of SPARQL via SPARQL protocol, produces a result set of SQL values.
create procedure DB.DBA.SPARQL_REXEC (
in service varchar, -- service URI to call via HTTP
in query varchar, -- text of SPARQL query to execute
in dflt_graph varchar, -- default graph IRI, if not NULL then this overrides what's specified in query
in named_graphs any, -- vector of named graph IRIs, if not NULL then this overrides what's specified in query
in req_hdr any, -- additional HTTP header lines that should be passed to the service; 'Host: ...' is most popular.
in maxrows integer, -- limit on numbers of rows that should be returned.
in bnode_dict any ) -- dictionary of bnode ID references.
-- Similar to SPARQL_REXEC (), but returns a vector of vectors of SQL values.
-- All arguments are the same.
create function DB.DBA.SPARQL_REXEC_TO_ARRAY (
in service varchar, in query varchar, in dflt_graph varchar, in named_graphs any,
in req_hdr any, in maxrows integer, in bnode_dict any)
returns any
-- Similar to SPARQL_REXEC (), but fills in output parameters with metadata (like exec metadata) and a vector of vector
s of 'long valmode' values.
-- First seven arguments are the same.
create procedure DB.DBA.SPARQL_REXEC_WITH_META (
in service varchar, in query varchar, in dflt_graph varchar, in named_graphs any,
in req_hdr any, in maxrows integer, in bnode_dict any,
out metadata any, -- metadata like exec () returns.
out resultset any) -- results as 'long valmode' value.
</programlisting>
<para>If the query is a CONSTRUCT or DESCRIBE then the result set consists of a single row and column, the value inside is a dictionary of triples in 'long valmode'.</para>
</sect3>
</sect2>
<sect2 id="rdfinternalfunctions"><title>Useful Internal Functions</title>
<sect3 id="rdfinternalconversion"><title>Conversion Functions for XMLSchema/RDF Data Serialization Syntax</title>
<para>These functions emulate constructor functions from XQuery Core Function Library.</para>
<programlisting>
create function DB.DBA."http://www.w3.org/2001/XMLSchema#boolean" (in strg any) returns integer
create function DB.DBA."http://www.w3.org/2001/XMLSchema#dateTime" (in strg any) returns datetime
create function DB.DBA."http://www.w3.org/2001/XMLSchema#double" (in strg varchar) returns double precision
create function DB.DBA."http://www.w3.org/2001/XMLSchema#float" (in strg varchar) returns float
create function DB.DBA."http://www.w3.org/2001/XMLSchema#integer" (in strg varchar) returns integer
</programlisting>
</sect3>
<sect3 id="rdfinternalpredicates"><title>RDF-specific Predicates</title>
<programlisting>
-- Returns 1 if string s matches pattern p, 0 otherwise
create function DB.DBA.RDF_REGEX (
in s varchar, -- source string to check
in p varchar, -- regular expression pattern string
in coll varchar := null) -- unused for now (modes are not yet implemented)
-- Returns 1 if language identifier r matches lang pattern t
create function DB.DBA.RDF_LANGMATCHES (
in r varchar, -- language identifies (string or NULL)
in t varchar) -- language pattern (exact name, first two letters or '*')
</programlisting>
</sect3>
</sect2>
<sect2 id="rdfdefaultgraph"><title>Default and Named Graphs</title>
<para>Sometimes the default graph IRI is not known when the SPARQL query is composed. It can be added at the very last moment by providing the IRI in a 'define' clause as follows:</para>
<programlisting><![CDATA[
define input:default-graph-uri <http://example.com>
]]></programlisting>
<para>Such a definition overrides the default graph URI set in query by the 'FROM ...' clause (if any).</para>
<para>The query may contain more than one <emphasis>define input:default-graph-uri</emphasis>.
The set of values of <emphasis>input:default-graph-uri</emphasis> has the highest possible priority and cannot be redefined in the rest of the text of the query by FROM clauses.</para>
<para>FROM NAMED clauses can be used multiple times in one query:</para>
<programlisting><![CDATA[
SPARQL
SELECT ?id
FROM NAMED <http://example.com/user1.ttl>
OPTION (get:soft "soft", get:method "GET")
FROM NAMED <http://example.com/user2.ttl>
OPTION (get:soft "soft", get:method "GET")
WHERE { GRAPH ?g { ?id a ?o } }
]]></programlisting>
<para>Similarly, <emphasis>define input:named-graph-uri <http://example.com></emphasis> is a replacement for a FROM NAMED clause</para>
<para>
When Virtuoso receives a SPARQL request via HTTP, the value of the default graph can be set in the protocol using a <emphasis>default-graph-uri</emphasis> HTTP parameter.
Multiple occurrences of this parameter are allowed. This HTTP parameter is converted into <emphasis>define input:default-graph-uri</emphasis>.
There's similar support for <emphasis>named-graph-uri</emphasis> HTTP parameter.
For debugging purposes, graph names set in the protocol are sent back in the reply header as <emphasis>X-SPARQL-default-graph: ...</emphasis> and <emphasis>X-SPARQL-named-graph: ...</emphasis> header lines, one line per graph.
</para>
<para>
A web service endpoint may provide different default configurations for different host names mentioned in HTTP requests.
This facility is configured via table <emphasis>DB.DBA.SYS_SPARQL_HOST</emphasis>.
</para>
<programlisting>
create table DB.DBA.SYS_SPARQL_HOST (
SH_HOST varchar not null primary key, -- host mask
SH_GRAPH_URI varchar, -- 'default default' graph uri
SH_USER_URI varchar, -- reserved for any use in applications
SH_DEFINES long varchar -- additional defines for requests
)
</programlisting>
<para>
When the SPARQL web service endpoint receives a request it checks the <emphasis>Host</emphasis> HTTP header line.
This line contains zero or more target host names, delimited by commas.
For every host name in the line, the service scans the <emphasis>DB.DBA.SYS_SPARQL_HOST</emphasis> table in search of a row containing a matching host name in <emphasis>SH_HOST</emphasis>.
The <emphasis>SH_HOST</emphasis> field acts as 'pattern' argument for the SQL string operator LIKE. If a matching row is found, the text of SPARQL request is extended.
If a default graph is not explicitly set by the HTTP parameters and <emphasis>SH_GRAPH_URI</emphasis> is not null then the default graph is set to <emphasis>SH_GRAPH_URI</emphasis>.
If <emphasis>SH_DEFINES</emphasis> is not null then it is added in front of the query; so this field is a good place for the text for any <emphasis>define</emphasis> options.
</para>
<para>
The search of <emphasis>DB.DBA.SYS_SPARQL_HOST</emphasis> stops at the first found row, other possible matches are silently ignored.
</para>
</sect2>
<sect2 id="rdfsqlfromsparql"><title>Calling SQL from SPARQL </title>
<para>A SPARQL expression can contain calls to Virtuoso/PL functions and built-in SQL functions in both the WHERE clause and in the
result set. Two namespace prefixes, <emphasis>bif</emphasis> and <emphasis>sql</emphasis> are reserved for
these purposes. When a function name starts with the <emphasis>bif:</emphasis> namespace
prefix, the rest of the name is treated as the name of a SQL BIF (Built-In
Function). When a function name starts with the <emphasis>sql:</emphasis> namespace prefix,
the rest of the name is treated as the name of a Virtuoso/PL function owned by
DBA with database qualifier DB, e.g. <emphasis>sql:example(...)</emphasis> is
converted into <emphasis>DB.DBA."example"(...)</emphasis>.</para>
<para>In both cases,
the function receives arguments in SQL format ('SQL valmode') and
also returns the result in SQL format. The SPARQL compiler will
automatically add code for format conversion into the resulting SQL
code so SQL functions can be used even if <emphasis>define output:valmode
'LONG'</emphasis> forces the use of RDF representation in the
result set.</para>
<sect3 id="rdfsqlfromsparqlex1"><title>Example with sql: namespace prefix</title>
<programlisting><![CDATA[
SQL>create procedure DB.DBA.ComposeInfo (
in pname varchar,
in pnick varchar := '',
in pbox varchar := '')
{
declare ss varchar;
ss := concat(pname, ' ', pnick, ' ', pbox);
ss := rtrim (ss, ' ');
return ss;
};
Done. -- 0 msec.
SQL>SPARQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT (sql:ComposeInfo (?name, ?nick, ?box))
FROM <http://www.w3.org/People/Berners-Lee/card>
WHERE
{
?s rdf:type foaf:Person .
optional{?s foaf:name ?name }.
optional{?s foaf:nick ?nick }.
optional{?s foaf:box ?box }.
filter (?nick like '%TimBL%') .
};
callret-0
VARCHAR
_______________________________________________________________________________
Timothy Berners-Lee TimBL
1 Rows. -- 30 msec.
]]></programlisting>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfsparqlgeospatexmp11">Example "Things around highly populated places"</link></listitem>
<listitem><link linkend="virtuosospongerfacent">Virtuoso Facets Web Service Examples</link></listitem>
<listitem><link linkend="VirtFacetUsage6">Virtuoso Facets Usage Statistics Examples</link></listitem>
</itemizedlist>
</tip>
</sect3>
<sect3 id="rdfsqlfromsparqlex1"><title>Example with sql: namespace prefix and bif:contains</title>
<programlisting><![CDATA[
SQL>SPARQL
SELECT DISTINCT ?cityUri ?cityName (sql:BEST_LANGMATCH (?cityName, 'en, en-gb;q=0.8, fr;q=0.7, *;q=0.1', '')) as ?bestCityName
WHERE
{
?cityUri ?predicate ?value.
?cityUri a <http://dbpedia.org/ontology/City>.
?value bif:contains "London".
OPTIONAL
{
?cityUri rdfs:label ?cityName
}
};
cityUri cityName bestCityName
ANY ANY ANY
______________________________________________________________________________________________________________
http://dbpedia.org/resource/Anerley Anerley Anerley
http://dbpedia.org/resource/Felixstowe Felixstowe Felixstowe
http://dbpedia.org/resource/Chesham Chesham Chesham
http://dbpedia.org/resource/Stratford%2C_London Stratford, London Stratford, London
http://dbpedia.org/resource/Ashford%2C_Surrey Ashford (Surrey) A shford (Surrey)
http://dbpedia.org/resource/Newmarket%2C_Suffolk Newmarket (Suffolk) Newmarket (Suffolk)
http://dbpedia.org/resource/North_Rhine-Westphalia Renania d'o Norte-Westfalia Renania d'o Norte-Westfalia
http://dbpedia.org/resource/West_Bromwich West Bromwich West Bromwich
....
]]></programlisting>
</sect3>
<sect3 id="rdfsqlfromsparqlex2"><title>Example with bif: namespace prefix</title>
<programlisting><![CDATA[
SQL>SPARQL
SELECT *
FROM <http://www.w3.org/people#>
WHERE { ?s ?p ?o . ?o bif:contains '"Timo*"'};
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/name Timothy Berners-Lee
http://www.w3.org/People/Berners-Lee/card#i http://xmlns.com/foaf/0.1/givenname Timothy
2 Rows. -- 2 msec.
]]></programlisting>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfpredicatessparqlexamples">Example filtering RDF objects triples by a given predicate</link></listitem>
<listitem><link linkend="rdfsparqlendpointexamples6">Example with extraction part of literal as variable</link></listitem>
<listitem><link linkend="rdfsparulexamples5">Example for various expressions usage</link></listitem>
<listitem><link linkend="rdfsparulexamples8">Example for generating RDF information resource URI</link></listitem>
</itemizedlist>
</tip>
</sect3>
</sect2>
<sect2 id="rdfsqlfromsparqldescribe"><title>SPARQL DESCRIBE</title>
<para>The SPARQL specification does not define the precise output of DESCRIBE, so different
applications may need different results for the same subject. Some
applications need quick generation of short and incomplete results
whereas others may need detailed reports composed from multiple sources.
</para>
<para>If define <emphasis>sql:describe-mode "xxx"</emphasis> is specified then the generated SQL
code will use the procedures named:
</para>
<programlisting><![CDATA[
DB.DBA.SPARQL_DESC_DICT_xxx (in subj_dict any, in consts any, in graphs
any, in storage_name any, in options any)
]]></programlisting>
<para>and
</para>
<programlisting><![CDATA[
DB.DBA.SPARQL_DESC_DICT_xxx_PHYSICAL (in subj_dict any, in consts any,
in graphs any, in storage_name any, in options any)
]]></programlisting>
<para>In a new blank database, only two such pairs of procedures are created.
Procedures <emphasis>DB.DBA.SPARQL_DESC_DICT_SPO</emphasis> and <emphasis>DB.DBA.SPARQL_DESC_DICT_SPO_PHYSICAL</emphasis>
are for <emphasis>sql:describe-mode "SPO"</emphasis>. This pair of procedures
searches for all triples where the input IRIs are used as subjects; they are faster than the default
routine which searches for all triples where the input IRIs are used as subjects or objects.
Similarly, <emphasis>DB.DBA.SPARQL_DESC_DICT_CBD</emphasis> and <emphasis>DB.DBA.SPARQL_DESC_DICT_CBD_PHYSICAL</emphasis>
are for <emphasis>sql:describe-mode "CBD"</emphasis>. CBD stands for Concise Bounded Description, Nokia-style.
</para>
<para><emphasis>Example:</emphasis></para>
<programlisting><![CDATA[
SQL>SPARQL
DEFINE sql:describe-mode "CBD"
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
DESCRIBE ?friend
WHERE
{
?s foaf:knows ?friend .
?friend foaf:nick ?nick.
filter (?s=<http://www.advogato.org/person/rmorgan/foaf.rdf#me>)
}
;
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <http://www.advogato.org/person/chrisd/foaf.rdf#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
ns1:me rdf:type foaf:Person .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
ns1:me rdfs:seeAlso <http://www.advogato.org/person/chrisd/foaf.rdf> ;
foaf:name "Chris DiBona" ;
foaf:nick "chrisd" ;
foaf:homepage <http://www.dibona.com> ;
foaf:mbox_sha1sum "e8231d19ac0d11ccbdc565485054461e5d71f0d3" .
@prefix ns4: <http://www.advogato.org/person/schoen/foaf.rdf#> .
ns1:me foaf:knows ns4:me .
@prefix ns5: <http://www.advogato.org/person/jpick/foaf.rdf#> .
ns1:me foaf:knows ns5:me .
@prefix ns6: <http://www.advogato.org/person/benson/foaf.rdf#> .
ns1:me foaf:knows ns6:me .
@prefix ns7: <http://www.advogato.org/person/conrad/foaf.rdf#> .
ns1:me foaf:knows ns7:me .
@prefix ns8: <http://www.advogato.org/person/starshine/foaf.rdf#> .
ns1:me foaf:knows ns8:me .
@prefix ns9: <http://www.advogato.org/person/chip/foaf.rdf#> .
ns1:me foaf:knows ns9:me .
@prefix ns10: <http://www.advogato.org/person/crackmonkey/foaf.rdf#> .
.....
]]></programlisting>
<para>In each pair, both procedures have the same semantics but the second one is used if and
only if the SPARQL compiler can prove that all subjects to process are
from physical storage <emphasis>(DB.DBA.RDF_QUAD)</emphasis>. Thus the second procedure
will not search for subjects in RDF Views.
</para>
<para>Each procedure should return a dictionary with triples as keys and
integer 1 as values. So the dictionary is filled by calls like:
</para>
<programlisting><![CDATA[
dict_put (resulting_dict,
vector (subj_iri_id, pred_iri_id, obj_iri_id_or_rdf_box),
1);
]]></programlisting>
<para>Procedure arguments are as follows:
</para>
<itemizedlist mark="bullet">
<listitem><emphasis>subj_dict</emphasis> - a dictionary whose keys are IRI IDs and maybe values of
other types, esp. RDF boxes. Keys are subjects to be described, so
values other than IRI IDs should usually be ignored. Values should be
ignored.</listitem>
<listitem><emphasis>consts</emphasis> - a vector of IRI IDs and values of other types. The items contained in the vector
are subjects to be described, as with the keys of subj_dict.</listitem>
<listitem><emphasis>graphs</emphasis> - a vector of IRI IDs of graphs that can be used for DESCRIBE. The
vector may contain garbage, like in the two previous cases. A NULL can be
passed instead of a vector indicating that the source graphs are not specified
in the source query.</listitem>
<listitem><emphasis>storage_name</emphasis> - the value of "define input:storage" from the original
SPARQL query, NULL if missing.</listitem>
<listitem><emphasis>options</emphasis> - reserved for future use and can be ignored.</listitem>
</itemizedlist>
<para>One should grant execute permission on both procedures to SPARQL_SELECT before referring to them in SPARQL.</para>
<para><emphasis>Example:</emphasis></para>
<programlisting><![CDATA[
SQL>set blobs on;
SQL>SPARQL
define sql:describe-mode "SPO"
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX sioct: <http://rdfs.org/sioc/types#>
DESCRIBE ?forum
FROM <http://demo.openlinksw.com/dataspace>
WHERE {
?forum rdf:type sioct:Weblog .
}
LIMIT 1;
callret-0
LONG VARCHAR
_______________________________________________________________________________
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/types#Weblog> ,
<http://atomowl.org/ontologies/atomrdf#Feed> ;
<http://rdfs.org/sioc/ns#description> "XML templates demo's Weblog" ;
<http://rdfs.org/sioc/ns#has_space> <http://demo.openlinksw.com/dataspace/bloguser/space#this> ;
<http://rdfs.org/sioc/ns#container_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/20> ,
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/21> ;
<http://rdfs.org/sioc/ns#id> "bloguser_blog" ;
<http://xmlns.com/foaf/0.1/maker> <http://demo.openlinksw.com/dataspace/person/bloguser#this> ;
<http://rdfs.org/sioc/ns#link> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> ;
<http://atomowl.org/ontologies/atomrdf#entry> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/20> ,
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/21> ;
<http://atomowl.org/ontologies/atomrdf#contains> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/21> ,
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/20> ;
<http://atomowl.org/ontologies/atomrdf#title> "bloguser_blog" ;
<http://www.w3.org/2000/01/rdf-schema#label> "XML templates demo's Weblog" ;
<http://rdfs.org/sioc/ns#scope_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog#owner> ;
<http://rdfs.org/sioc/ns#has_owner> <http://demo.openlinksw.com/dataspace/bloguser#this> ;
<http://www.w3.org/2000/01/rdf-schema#isDefinedBy> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/sioc.rdf> ;
<http://purl.org/dc/elements/1.1/identifier> "62"^^<http://www.w3.org/2001/XMLSchema#integer> ;
<http://rdfs.org/sioc/services#has_service> <http://demo.openlinksw.com/RPC2> ,
<http://demo.openlinksw.com/mt-tb> ,
<http://demo.openlinksw.com/Atom/bloguser-blog-0> ,
<http://demo.openlinksw.com/GData/bloguser-blog-0> .
<http://demo.openlinksw.com/RPC2> <http://rdfs.org/sioc/services#service_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/mt-tb> <http://rdfs.org/sioc/services#service_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog#owner> <http://rdfs.org/sioc/ns#has_scope> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/20> <http://rdfs.org/sioc/ns#has_container> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> ;
<http://atomowl.org/ontologies/atomrdf#source> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog/21> <http://rdfs.org/sioc/ns#has_container> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> ;
<http://atomowl.org/ontologies/atomrdf#source> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/dataspace/bloguser#this> <http://rdfs.org/sioc/ns#owner_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/dataspace/bloguser/space#this> <http://rdfs.org/sioc/ns#space_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/dataspace/person/bloguser#this> <http://xmlns.com/foaf/0.1/made> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/Atom/bloguser-blog-0> <http://rdfs.org/sioc/services#service_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
<http://demo.openlinksw.com/GData/bloguser-blog-0> <http://rdfs.org/sioc/services#service_of> <http://demo.openlinksw.com/dataspace/bloguser/weblog/bloguser_blog> .
1 Rows. -- 240 msec.
]]></programlisting>
</sect2>
<sect2 id="rdfsparqlimplementatiotrans"><title>Transitivity in SPARQL</title>
<para>Virtuoso SPARQL allows access to Virtuoso's SQL transitivity extension. Read the
<link linkend="transitivityinsQL">SQL section</link> for a definition of the options.</para>
<para>The SPARQL syntax is slightly different from the SQL, although the option names
and meanings are the same.</para>
<para>In SPARQL, the transitive options occur after a subquery enclosed in braces:</para>
<para>The below produces all the IRI's that are the same as <alice>.</para>
<programlisting><![CDATA[
SPARQL
SELECT ?syn
where
{
{
SELECT ?x ?syn
where
{
{ ?x owl:sameAs ?syn } union { ?syn owl:sameAs ?x }
}
}
option ( transitive, t_in (?x), t_out (?syn), t_distinct, t_min (0) )
filter (?x = <Alice>) .
}
]]></programlisting>
<para>In this case, we provide a binding for ?x in the filter outside of the
transitive subquery. The subquery therefore is made to run from in to
out. The same effect would be accomplished if we bound ?syn and
SELECT ?x, the designations of in and out are arbitrary and for
transitive steps that can be evaluated equally well in both directions
this makes no difference.
</para>
<para>The transitive subquery in the above is </para>
<programlisting><![CDATA[
{SELECT ?syn
WHERE
{
{ SELECT ?x ?syn
WHERE
{{ ?x owl:sameAs ?syn } UNION { ?syn owl:sameAs ?x}}
} OPTION (TRANSITIVE, t_in (?x), t_out (?syn), t_distinct, t_min (0) )
}
} .
]]></programlisting>
<para>Leaving out the option would just look for one step of owl:sameAs.
Making it transitive will apply the subquery to all bindings it
produces until all are visited at least once (the t_distinct modifier).
</para>
<para>If the transitive step consists of a single triple pattern, there is a shorthand:</para>
<programlisting><![CDATA[
<alice> foaf:knows ?friend option (transitive t_min (1))
]]></programlisting>
<para>will bind ?friend to all directly and indirectly found foaf:known
individuals. If t_min had been 0, Malice> would have also been in the
generated bindings.</para>
<para>The syntax is</para>
<programlisting><![CDATA[
option (transitive transitivity_option[,...])
transitivity_option ::= t_in (<variable_list>)
| t_out (<variable_list>)
| t_distinct
| t_shortest_only
| t_no_cycles
| t_cycles_only
| t_min (INTNUM)
| t_max (INTNUM)
| t_end_flag (<variable>)
| t_step (<variiable_or_step>)
| t_direction INTNUM
variable_list ::= <variable> [,...]
variable_or_step ::= <variable> | path_id' | 'step_no'
]]></programlisting>
<para>Unlike SQL, variable names are used instead of column numbers.
Otherwise all the options have the same meaning.</para>
<para>Some examples of the use of transitivity are:</para>
<sect3 id="rdfsparqlimplementatiotransexamples"><title>Collection of Transitivity Option Demo Queries for SPARQL</title>
<sect4 id="rdfsparqlimplementatiotransexamples1"><title>Example for finding out what graphs contain owl:sameAs for "New York"</title>
<para>To find out what graphs contain owl:sameAs for Dan York, we do</para>
<programlisting><![CDATA[
SELECT ?g ?x count (*) as ?count
WHERE {
{SELECT ?x ?alias ?g
WHERE {
{ GRAPH ?g {?x owl:sameAs ?alias }
}
UNION
{GRAPH ?g {?alias owl:sameAs ?x}}}}
OPTION (TRANSITIVE, t_in (?x), t_out (?alias), t_distinct, t_min (1)) .
FILTER (?x = <http://dbpedia.org/resource/New_York> ) .
}
]]></programlisting>
<para>Here we select all paths that start with the initial URI and pass
through one or more sameAs statements. Each step produces a result of
the transitive subquery. The graph where the sameAs triple was found
is returned and used as the grouping column. In this way we see how
many times each graph is used. Note that graphs are counted many
times since the graphs containing immediate sameAs statements are
counted for paths of length 1, then again as steps on paths that reach
to their aliases and so on.</para>
</sect4>
<sect4 id="rdfsparqlimplementatiotransexamples2"><title>Example for query that takes all the people known by Tim Berners-Lee, to a depth between 1 and 4 applications of the subquery</title>
<para>This query takes all the people known by kidehen, to a depth between 1
and 4 applications of the subquery. It then sorts them by the
distance and the descending count of connections of each found connection. This is
equivalent to the default connections list shown by LinkedIn.</para>
<programlisting><![CDATA[
SPARQL
SELECT ?o ?dist ((SELECT COUNT (*) WHERE {?o foaf:knows ?xx}))
WHERE
{
{
SELECT ?s ?o
WHERE
{
?s foaf:knows ?o
}
} OPTION (TRANSITIVE, t_distinct, t_in(?s), t_out(?o), t_min (1), t_max (4), t_step ('step_no') as ?dist) .
FILTER (?s= <http://www.w3.org/People/Berners-Lee/card#i>)
}
ORDER BY ?dist DESC 3
LIMIT 50
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlimplementatiotransexamples4"><title>Example for finding how two people know each other and what graphs are involved in the connection</title>
<para>To find how two people know each other and what graphs are involved in the connection, we do:</para>
<programlisting><![CDATA[
SPARQL
SELECT ?link ?g ?step ?path
WHERE
{
{
SELECT ?s ?o ?g
WHERE
{
graph ?g {?s foaf:knows ?o }
}
} OPTION (TRANSITIVE, t_distinct, t_in(?s), t_out(?o), t_no_cycles, T_shortest_only,
t_step (?s) as ?link, t_step ('path_id') as ?path, t_step ('step_no') as ?step, t_direction 3) .
FILTER (?s= <http://www.w3.org/People/Berners-Lee/card#i>
&& ?o = <http://www.advogato.org/person/mparaz/foaf.rdf#me>)
}
LIMIT 20
]]></programlisting>
<para>This query binds both the t_in and t_out variables. The ?g is left as
a free variable. Also, specifying ?s and the system defined constants
step_no and path_id as with t_step, we get for each transitive step a
row of results with the intermediate binding of ?s, the count of steps
from the initial ?s and a distinct identifier for the individual path,
since there can be many distinct paths that link the ?s and ?o
specified in the filter.</para>
<para>See the SQL transitive option section for details on the meaning of step_no and path_id.</para>
</sect4>
<sect4 id="rdfsparqlimplementatiotransexamples5"><title>Example for TBox Subsumption</title>
<para>Subsumption Demo Using Transitivity Clause</para>
<para>Yago Class Hierarchy (TBox) Subsumption</para>
<para>AlphaReceptors</para>
<programlisting><![CDATA[
SELECT ?y
FROM <http://dbpedia.org/resource/classes/yago#>
WHERE
{
{
SELECT *
WHERE
{
?x rdfs:subClassOf ?y .
}
}
OPTION (TRANSITIVE, t_distinct, t_in (?x), t_out (?y) ) .
FILTER (?x = <http://dbpedia.org/class/yago/AlphaReceptor105609111>)
}
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlimplementatiotransexamples6"><title>Example for Receptors</title>
<programlisting><![CDATA[
SELECT ?x
FROM <http://dbpedia.org/resource/classes/yago#>
WHERE
{
{
SELECT *
WHERE
{
?x rdfs:subClassOf ?y .
}
} OPTION (transitive, t_distinct, t_in (?x), t_out (?y) ) .
FILTER (?y = <http://dbpedia.org/class/yago/Receptor105608868>)
}
]]></programlisting>
</sect4>
<sect4 id="rdfsparqlimplementatiotransexamples7"><title>Inference Rule example using transitive properties from SKOS vocabulary</title>
<p>The following example demostrates the steps how to retrieve the skos ontology, add triples
for skos:broaderTransitiveinto the graph, define inference rule, and at the and
execute sparql query with inference rule and transitivity option. The queries were executed against
the LOD instance (http://lod.openlinksw.com):</p>
<orderedlist>
<listitem>Make the Context graph, assuming you don't want to load entire SKOS vocabulary into our Quad Store:
<programlisting><![CDATA[
SQL>SPARQL
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
INSERT INTO GRAPH <urn:rules.skos> { skos:broader rdfs:subPropertyOf skos:broaderTransitive .
skos:narrower rdfs:subPropertyOf skos:narrowerTransitive };
]]></programlisting>
</listitem>
<listitem>OR Load entire SKOS ontology into Quad Store via iSQL interface (commandline or HTML based Conductor):
<programlisting><![CDATA[
SQL>DB.DBA.RDF_LOAD_RDFXML (http_get ('http://www.w3.org/2009/08/skos-reference/skos-owl1-dl.rdf'), 'no', 'urn:rules.skos');
Done.
]]></programlisting>
</listitem>
<listitem>Make Context Rule:
<programlisting><![CDATA[
SQL>rdfs_rule_set ('skos-trans', 'urn:rules.skos');
Done.
]]></programlisting>
</listitem>
<listitem>Go to SPARQL endpoint, for ex. http://lod.openlinksw.com/sparql</listitem>
<listitem>Use inference rule pragma to set context rule for SPARQL query, i.e:
<programlisting><![CDATA[
SPARQL
DEFINE input:inference "skos-trans"
PREFIX p: <http://dbpedia.org/property/>
PREFIX dbpedia: <http://dbpedia.org/resource/>
PREFIX category: <http://dbpedia.org/resource/Category:>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX geo: <http://www.georss.org/georss/>
SELECT DISTINCT ?m ?n ?p ?d
WHERE
{
?m rdfs:label ?n.
?m skos:subject ?c.
?c skos:broaderTransitive category:Churches_in_Paris OPTION (TRANSITIVE) .
?m p:abstract ?d.
?m geo:point ?p
FILTER ( lang(?n) = "fr" )
FILTER ( lang(?d) = "fr" )
}
]]></programlisting>
</listitem>
<listitem>You will get 22 rows returned from the query.
Note that for comparison, if the option (transitive) is ommitted, then only 2 rows will be returned
in our example query:
<figure id="rdftr" float="1">
<title>Transitive option</title>
<graphic fileref="ui/trs1.png"/>
</figure>
</listitem>
</orderedlist>
</sect4>
<sect4 id="rdfsparqlimplementatiotransexamples8"><title>Inference Rule example using
transitive properties from SKOS vocabulary: Variant II</title>
<p>This example shows how to find entities that are subcategories of Protestant Churches, no deeper
than 3 levels within the concept scheme hierarchy, filtered by a specific subcategory. It demonstrates
use of inference rules, sub-queries, and filter to obtain entities associated with category:
Protestant_churches combined with the use of the transitivitve closure, sets to a maximum of 3 stepsdown a SKOS based concept scheme hierarchy:</p>
<orderedlist>
<listitem>Make sure the inference rule "skos-trans" is created as described in the previous <link linkend="rdfsparqlimplementatiotransexamples7">example</link></listitem>
<listitem>Go to SPARQL endpoint, for ex. http://lod.openlinksw.com/sparql</listitem>
<listitem>Use inference rule pragma to set context rule for SPARQL query, i.e:
<programlisting><![CDATA[
DEFINE input:inference "skos-trans"
PREFIX p: <http://dbpedia.org/property/>
PREFIX dbpedia: <http://dbpedia.org/resource/>
PREFIX category: <http://dbpedia.org/resource/Category:>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX geo: <http://www.georss.org/georss/>
SELECT DISTINCT ?c AS ?skos_broader
?trans AS ?skos_narrower
?dist AS ?skos_level
?m ?n ?p AS ?geo_point
WHERE
{
{
SELECT ?c ?m ?n ?p ?trans ?dist
WHERE
{
?m rdfs:label ?n.
?m skos:subject ?c.
?c skos:broaderTransitive category:Protestant_churches .
?c skos:broaderTransitive ?trans
OPTION ( TRANSITIVE, t_distinct, t_in (?c), t_out (?trans),
t_max (3), t_step ( 'step_no' ) as ?dist ) .
?m p:abstract ?d.
?m geo:point ?p
FILTER ( lang(?n) = "en" )
FILTER ( lang(?d) = "en" )
}
}
FILTER ( ?trans = <http://dbpedia.org/resource/Category:Churches_in_London> )
}
ORDER BY ASC (?dist)
]]></programlisting>
</listitem>
<listitem>You will get 22 rows returned from the query.
<figure id="rdftr" float="1">
<title>Transitive option</title>
<graphic fileref="ui/trs2.png"/>
</figure>
</listitem>
</orderedlist>
</sect4>
</sect3>
</sect2>
</sect1>
<sect1 id="rdfgraphsecurity"><title>RDF Graphs Security</title>
<sect2 id="rdfgraphsecuritygroups"><title>RDF Graph Groups</title>
<para>In some cases, the data-set of a SPARQL query is not known at compile time. It is possible to pass
IRIs of source graphs via parameters, but the method is not perfect as:</para>
<itemizedlist mark="bullet">
<listitem>not all protocols are suitable for parameter passing, and no one is an interoperable standard</listitem>
<listitem>passing list of IRIs as a parameter will usually require the use of Virtuoso-specific functions
in the text of SPARQL query, that's bad for some query builders.</listitem>
<listitem>lack of knowledge about actual graphs may damage query optimization</listitem>
</itemizedlist>
<para>It would be nice to create named lists of graphs and a clause like "SELECT from all graph names of the specified list".
<emphasis>"Graph groups"</emphasis> serve for this purpose. That is Virtuoso-specific SPARQL extension that let create a named list of IRIs such that
if name of the list is used in <emphasis>FROM</emphasis> clause like <emphasis>IRI</emphasis> of default
graph then it is equivalent to list of <emphasis>FROM</emphasis> clauses, one clause for each item of the
list.</para>
<para>Internally, descriptions of graph groups are kept in two tables:</para>
<emphasis>Table of graph groups:</emphasis>
<programlisting><![CDATA[
create table DB.DBA.RDF_GRAPH_GROUP (
RGG_IID IRI_ID not null primary key, -- IRI ID of RGG_IRI field
RGG_IRI varchar not null, -- Name of the group
RGG_MEMBER_PATTERN varchar, -- Member IRI pattern
RGG_COMMENT varchar -- Comment
)
create index RDF_GRAPH_GROUP_IRI on DB.DBA.RDF_GRAPH_GROUP (RGG_IRI)
;
]]></programlisting>
<para><emphasis>Table of contents of groups:</emphasis></para>
<programlisting><![CDATA[
create table DB.DBA.RDF_GRAPH_GROUP_MEMBER (
RGGM_GROUP_IID IRI_ID not null, -- IRI_ID of the group
RGGM_MEMBER_IID IRI_ID not null, -- IRI_ID of the group member
primary key (RGGM_GROUP_IID, RGGM_MEMBER_IID)
)
;
]]></programlisting>
<para>Fields <emphasis>RGG_MEMBER_PATTERN</emphasis> and <emphasis>RGG_COMMENT</emphasis> are not used by system internals but applications may wish to write their data there for future reference.
<emphasis>RGG_COMMENT</emphasis> is supposed to be human-readable description of the group and <emphasis>RGG_MEMBER_PATTERN</emphasis> may be useful for functions that automatically add
IRIs of a given graph to all graph groups such that the graph IRI string match <emphasis>RGG_MEMBER_PATTERN</emphasis> regexp pattern.
</para>
<para>A dictionary of all groups and their members is cached in memory for fast access.
Due to this reason, applications may read these tables and modify <emphasis>RGG_MEMBER_PATTERN</emphasis> and <emphasis>RGG_COMMENT</emphasis> if needed but not change other fields directly.
The following API procedures makes changes in a safe way:
</para>
<programlisting><![CDATA[
DB.DBA.RDF_GRAPH_GROUP_CREATE (
in group_iri varchar,
in quiet integer,
in member_pattern varchar := null,
in comment varchar := null)
]]></programlisting>
<para>That creates a new empty graph group. An error is signaled if the group exists already and quiet
parameter is zero.</para>
<programlisting><![CDATA[
DB.DBA.RDF_GRAPH_GROUP_INS (in group_iri varchar, in memb_iri varchar)
DB.DBA.RDF_GRAPH_GROUP_DEL (in group_iri varchar, in memb_iri varchar)
]]></programlisting>
<para>These two are to add or remove member to an existing group. Double insert or removal of not a member
will not signal errors, but missing group will.be signaled.</para>
<programlisting><![CDATA[
DB.DBA.RDF_GRAPH_GROUP_DROP (
in group_iri varchar,
in quiet integer)
]]></programlisting>
<para>That removes graph group. An error is signaled if the group did not exist before the call and quiet
parameter is zero.</para>
<para>Graph groups are <emphasis>"macro-expanded"</emphasis> only in FROM clauses and have no effect on
FROM NAMED or on GRAPH <IRI> {...} . Technically, it is not prohibited to use an IRI as both plain
graph IRI and graph group IRI in one storage but this is confusing and is not recommended.</para>
<para>Graph groups can not be members of other graph groups, i.e. the IRI of a graph group can appear in the
list of members of some group but it will be treated as plain graph IRI and will not cause recursive
expansion of groups.</para>
</sect2>
<sect2 id="rdfgraphsecuritynotfrom"><title>NOT FROM and NOT FROM NAMED Clauses</title>
<para>In addition to standard FROM and FROM NAMED clauses, Virtuoso extends SPARQL with NOT FROM and NOT
FROM NAMED clauses of "opposite" meaning.</para>
<programlisting><![CDATA[
SELECT ... NOT FROM <x> ... WHERE {...}
]]></programlisting>
<para>means "SELECT FROM other graphs, but not from the given one".
This is especially useful because NOT FROM supports graph groups (NOT FROM NAMED supports only plain graphs).
So if</para>
<programlisting><![CDATA[
<http://example.com/users/private>
]]></programlisting>
<para>is a graph group of all graphs with confidential data about users then</para>
<programlisting><![CDATA[
SELECT * NOT FROM <http://example.com/users/private> WHERE {...}
]]></programlisting>
<para>will be restricted only to insecure data.</para>
<para>NOT FROM overrides any FROM and NOT FROM NAMED overrides any FROM NAMED, the order of clauses in the
query text is not important.</para>
<para>The SPARQL web service endpoint configuration string may contain pragmas
<emphasis>input:default-graph-exclude</emphasis> and <emphasis>input:named-graph-exclude</emphasis> that
become equivalent to NOT FROM and NOT FROM NAMED clauses like <emphasis>input:default-graph-uri</emphasis>
and <emphasis>input:named-graph-uri</emphasis> mimics FROM and FROM NAMED.</para>
</sect2>
<sect2 id="rdfgraphsecurity"><title>Graph-Level Security</title>
<para>Virtuoso supports graph-level security for "physical" RDF storage. That is somewhat similar to table
access permissions in SQL. However, the difference between SPARQL and SQL data models results in totally
different style of security administration. In SQL, when new application is installed it comes with its own
set of tables and every query in its code explicitly specifies tables in use. Security restrictions of two
applications interfere only if applications knows each other and are supposedly designed to cooperate. It
is possible to write an application that will get list of available tables and retrieve data from any given
table but that is a special case and it usually requires DBA privileges.</para>
<para>In SPARQL, data of different applications shares one table and the query language allows to select data
of all applications at once. This feature makes SPARQL convenient for cross-application data integration. At
the same time, that become a giant security hole if any sensitive data are stored.</para>
<para>A blind copying SQL security model to SPARQL domain would result in significant loss of performance or
weak security or even both problems at the same time. That is why SPARQL model is made much more restrictive,
even if it becomes inconvenient for some administration tasks.</para>
<para>Graph-level security does not replace traditional SQL security. A user should become member of
appropriate group (SPARQL_SELECT, SPARQL_SPONGE or SPARQL_UPDATE) in order to start using its graph-level
privileges.</para>
</sect2>
<sect2 id="rdfgraphsecurityunddefperm"><title>Understanding Default Permissions</title>
<para>In relational database, default permissions are trivial. DBA is usually the only account that can
access any table for both read and write. Making some table public or private does not affect applications
that do not refer that table in the code. Tables are always created before making security restrictions on
them.</para>
<para>Chances are very low that an application will unintentionally create some table and fill in with
confidential data. There are no unauthenticated users, any client has some user ID and no one user is
"default user" so permissions of any two users are always independent.</para>
<para>SPARQL access can be anonymous and graphs can be created during routine data manipulation.
For anonymous user, only public resources are available. Thus "default permissions" on some or all graphs are
actually permissions of "nobody" user, (the numeric ID of this user can be obtained by http_nobody_uid()
function call). As a consequence, there's a strong need in "default permission" for a user, this is the only
way to specify what to do with all graphs that does not exist now it might exist in some future.
</para>
<para>An attempt to make default permissions wider than specific is always potential security hole in SPARQL,
so this is strictly prohibited.</para>
<para>Four sorts of access are specified by four bits of an integer "permission bit-mask", plain old UNIX
style:</para>
<itemizedlist mark="bullet">
<listitem>Bit 1 permits read access.</listitem>
<listitem>Bit 2 permits write access via SPARUL and it's basically useless without bit 1 set.</listitem>
<listitem>Bit 4 permits write access via "RDF sponge" methods and it's basically useless
without bits 1 and 2 set.</listitem>
<listitem>Bit 8 allows to obtain list of members of graph group; an IRI can be used as graph IRI and as
graph group IRI at the same time so bit 8 can be freely combined with any of bits 1, 2 or 4.</listitem>
</itemizedlist>
<para>Note that obtaining the list of members of a graph group does not grant any access permissions to
triples from member graphs. It is quite safe to mix secure and public graphs in one graph group.</para>
<para>When a SPARQL query should check whether a given user have permission to access a given graph then
the order of checks is as follows:</para>
<orderedlist>
<listitem>permissions of the user on the specific graph;</listitem>
<listitem>default permissions of the user on all graphs;</listitem>
<listitem>public permissions on the specific graph;</listitem>
<listitem>public permissions on all graphs</listitem>
</orderedlist>
<para>If no one above mentioned permission is set then the access is "read/write/sponge/list".</para>
<para>For "nobody" user, steps 3 and 4 become exact copies of steps 1 and 2 so they are skipped.</para>
</sect2>
<sect2 id="rdfgraphsecurityintconfsec"><title>Initial Configuration of SPARQL Security</title>
<para>It is convenient to configure the RDF storage security by adding restrictions in the order inverse
to the order of checks:</para>
<itemizedlist mark="bullet">
<listitem>Step 1: Set public permissions on all graphs to the most restricted level of any application
that will be installed. So if any single graph will be unreadable for public, then public permissions on
all graphs should be set to 0 or 8.</listitem>
<listitem>Step 2: Public permissions on "insecure" graphs should be set. So if the database contains
DBpedia or WordNet or some other data of Linking Open Data project then public permissions for that graphs
may be set to 1.</listitem>
<listitem>Step3: Configure trusted users, such as administrative DBA-like accounts, and to specify their
permissions on all graphs.</listitem>
<listitem>Step 4: Some additional right can be granted to some specific users on some specific graphs.</listitem>
</itemizedlist>
<para>Note that there's no need to permit something to DBA itself, because DBA's default permissions are
set automatically.</para>
<sect3 id="rdfgraphsecurityintconfsecuser"><title>Configuring New User</title>
<itemizedlist mark="bullet">
<listitem>Step 1: Grant SPARQL_SELECT, SPARQL_SPONGE or SPAR_UPDATE to the user.</listitem>
<listitem>Step 2: Set user's permissions on all graphs.</listitem>
<listitem>Step 3: Grant rights on some specific graphs.</listitem>
</itemizedlist>
</sect3>
<sect3 id="rdfgraphsecurityintex"><title>Example: Blogs and Resource Sharing</title>
<para>Consider a "groupware" application that let users create personal resources with access policies.</para>
<programlisting><![CDATA[
-- First, create few users, in alphabetical order.
DB.DBA.USER_CREATE ('Anna', 'Anna');
DB.DBA.USER_CREATE ('Brad', 'Brad');
DB.DBA.USER_CREATE ('Carl', 'Carl');
grant SPARQL_UPDATE to "Anna";
grant SPARQL_UPDATE to "Brad";
grant SPARQL_UPDATE to "Carl";
-- At least some data are supposed to be confidential, thus the whole storage becomes confidential.
DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('nobody', 0);
-- Moreover, no one of created users have access to all graphs (even for reading).
DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('Anna', 0);
DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('Brad', 0);
DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('Carl', 0);
-- Anna can only read her personal system data graph.
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Anna/system', 'Anna', 1);
-- Anna can read and write her private data graph.
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Anna/private', 'Anna', 3);
-- Anna and Bred are friends and can read each others notes for friends.
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Anna/friends', 'Anna', 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Anna/friends', 'Brad', 1);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Brad/friends', 'Brad', 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Brad/friends', 'Anna', 1);
-- Brad and Carl share write access to graph of his company.
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/BubbleSortingServicesInc', 'Brad', 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/BubbleSortingServicesInc', 'Carl', 3);
-- Anna writes a blog for public.
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Anna/blog', 'Anna', 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Anna/blog', 'nobody', 1);
-- DBpedia is public read and local discussion wiki is readable and writable.
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://dbpedia.org/', 'nobody', 1);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/wiki', 'nobody', 3);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/publicB', 'nobody', 3);
-- Graph groups have its own security.
DB.DBA.RDF_GRAPH_GROUP_CREATE ('http://example.com/Personal', 1);
DB.DBA.RDF_GRAPH_GROUP_INS ('http://example.com/Personal', 'http://example.com/Anna/system');
DB.DBA.RDF_GRAPH_GROUP_INS ('http://example.com/Personal', 'http://example.com/Anna/private');
DB.DBA.RDF_GRAPH_GROUP_INS ('http://example.com/Personal', 'http://example.com/Brad/system');
DB.DBA.RDF_GRAPH_GROUP_INS ('http://example.com/Personal', 'http://example.com/Brad/private');
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Personal', 'Anna', 8);
DB.DBA.RDF_GRAPH_USER_PERMS_SET ('http://example.com/Personal', 'Brad', 8);
]]></programlisting>
<para>If Anna and Brad execute same</para>
<programlisting><![CDATA[
SELECT *
FROM <http://example.com/Personal>
WHERE { ?s ?p ?o }
]]></programlisting>
<para>then results will be totally different: users will not get access to each others data.</para>
</sect3>
</sect2>
<sect2 id="rdfgraphsecurityappcallb"><title>Application Callbacks for Graph Level Security</title>
<para>In some cases, different applications should provide different security for different users. Two
SPARQL pragmas are provided for this purpose:</para>
<itemizedlist mark="bullet">
<listitem>Pragma sql:gs-app-callback is to specify Virtuoso/PL callback function that return permission bits for given graph.</listitem>
<listitem>Pragma sql:gs-app-uid is to specify application-specific user ID that is some string that is passed to the callback "as is".</listitem>
</itemizedlist>
<para>The name of callback is always DB.DBA.SPARQL_GS_APP_CALLBACK_nnn, where nnn is value of
sql:gs-app-callback.</para>
<para>The callback is called only if the application has access to the graph in question so it may restrict
the caller's account but not grant more permissions.</para>
<sect3 id="rdfgraphsecurityappcallbex"><title>Example</title>
<para>Let user of application get full access to graphs whose IRIs contain user's name in path.
In addition, let all of them permission to use all graph groups and let the "moderator" user read everything.</para>
<programlisting><![CDATA[
reconnect "dba";
create function DB.DBA.SPARQL_GS_APP_CALLBACK_TEST (in g_iid IRI_ID, in app_uid varchar) returns integer
{
declare g_uri varchar;
-- A fake IRI ID #i0 is used to mention account's default permissions for all graphs.
if (#i0 = g_iid)
{
if ('moderator' = app_uid)
return 9; -- Moderator can read and list everything.
return 8; -- Other users can list everything.
}
g_uri := id_to_iri (g_iid);
if (strstr (g_uri, '/' || app_uid || '/'))
return 15; -- User has full access to "his" graph.
return 8; -- User can list any given graph group.
}
;
SPARQL
define sql:gs-app-callback "TEST"
define sql:gs-app-uid "Anna"
SELECT ?g ?s WHERE { ?s <p> ?o }
;
]]></programlisting>
</sect3>
</sect2>
</sect1>
<sect1 id="rdfrdfviewgnr"><title>Automated Generation of RDF Views over Relational Data Sources</title>
<sect2 id="rdfrdfviewgnrintro"><title>Introduction</title>
<para>Virtuoso offers from Conductor UI an HTML based Wizard interface for dynamically generating &
publishing RDF based Linked Data from ODBC or JDBC accessible relational data sources. Basically,
a mechanism for building RDF based Linked Data views over relational data sources.
</para>
<para>The proliferation of relational databases across enterprises and behind Web sites, makes them a
vital data source for the burgeoning Linked Data Web. Thus, the process of publishing Linked Data from
these sources needs to be as unobtrusive as possible. Naturally, a balance has to be struck between
unobtrusive generation of Linked Data and traditional relational database management system (RDBMS)
virtues such as:
</para>
<itemizedlist mark="bullet">
<listitem>Scalability</listitem>
<listitem>Security</listitem>
<listitem>Analytical Expressivity of SQL</listitem>
<listitem>Separation of Data Access and Data Storage via ODBC, JDBC, ADO.NET CLIs.</listitem>
</itemizedlist>
<para>The following steps must be taken to publish RDF-based Linked Data:
</para>
<orderedlist>
<listitem>Identifying ODBC or JDBC data sources that host the data you seek to publish
(assuming the data isn't Virtuoso RDBMS hosted -- in which case, skip ahead to step #3).</listitem>
<listitem>Attach/Link TABLEs or VIEWs from the external data sources into Virtuoso via their Data Source Names (DSNs).</listitem>
<listitem>Identify the internal or external TABLEs or VIEWs that hold the data you wish to publish.</listitem>
<listitem>Configure Endpoints and Re-write Rules to disambiguate data object (resource) identity and description through HTTP-based content negotiation.</listitem>
<listitem>Expose the Data Source Ontology and associated Instance Data in Linked Data form through those Endpoints and Re-write Rules.</listitem>
</orderedlist>
<para>
These steps may be largely automated (the "One-Click" Deployment below), or performed manually ("Using the Conductor's HTML-based Wizard" further down).
</para>
</sect2>
<sect2 id="rdfrdfviewgnroneclick"><title>One Click Linked Data Generation & Deployment</title>
<para>The following steps provide a one-click guide for publishing ODBC- or JDBC-accessible RDBMS data in RDF Linked Data form, using the "Generate & Publish" Conductor feature.
</para>
<orderedlist>
<listitem>Go to http://<cname>:port/conductor</listitem>
<listitem>Log in as user dba (or another user with DBA privileges)</listitem>
<listitem>Follow menu path Database -> RDF Views
<figure id="rd1" float="1">
<title>RDF Views</title>
<graphic fileref="ui/rd1.png"/>
</figure>
</listitem>
<listitem>In the form presented, perform the following steps:
<orderedlist>
<listitem>Select the Database Name Qualifier (e.g., "Demo")
that exposes the Tables / Views for this exercise </listitem>
<listitem>Enter the Base URL to which your URL rewrite rules will be bound
(e.g. http://<cname>:8890/Demo)</listitem>
<listitem>Select specific Tables containing the data to be published (e.g. Demo.demo.Shippers and Demo.demo.Suppliers)</listitem>
<listitem>Click the "Generate & Publish" button</listitem>
</orderedlist>
<figure id="rd2" float="1">
<title>RDF Views Generate and Publish</title>
<graphic fileref="ui/rd2.png"/>
</figure>
</listitem>
<listitem>Virtuoso will perform the entire process of ontology generation, instance data generation, and
linked data deployment (re-write rules generation and application).</listitem>
<listitem>Error messages will be presented if the Wizard encounters problems. If there are no error
messages, your RDF view declarations and Linked Data publishing activities will have completed successfully.
<figure id="rd13" float="1">
<title>RDF View declarations and Linked Data publishing activities</title>
<graphic fileref="ui/rd13.png"/>
</figure>
</listitem>
<listitem>Optionally, you could also perform one of the following tasks:
<orderedlist>
<listitem>Save Data Mappings: when clicked, offers to save the generated Definitions to local file system</listitem>
<listitem>Save Ontology Mappings: when clicked, offers to save the generated Ontology to local file system</listitem>
<listitem>Click on the "Cancel" should you want to return to the initial RDF View Generation form.</listitem>
</orderedlist>
</listitem>
</orderedlist>
</sect2>
<sect2 id="rdfrdfviewgnrwizzard"><title>Manual Linked Data Generation & Deployment using the Conductor's HTML-based wizard</title>
<para>The following step-by guide will lead you through manually publishing ODBC- or JDBC-accessible RDBMS
data in RDF Linked Data form, using the Conductor's HTML-based wizard:
</para>
<orderedlist>
<listitem>Go to http://<cname>:port/conductor</listitem>
<listitem>Log in as user dba (or another user with DBA privileges)</listitem>
<listitem>Follow menu path Database -> RDF Views
<figure id="rd1" float="1">
<title>RDF Views</title>
<graphic fileref="ui/rd1.png"/>
</figure>
</listitem>
<listitem>In the form presented, perform the following steps:
<orderedlist>
<listitem>Select the Database Name Qualifier (e.g., "Demo") that exposes the Tables / Views for this
exercise</listitem>
<listitem>Enter the Base URL to which your URL rewrite rules will be bound (e.g. http://<cname>:8890/Demo)</listitem>
<listitem>Select specific Tables containing the data to be published (e.g., Demo.demo.Shippers and Demo.demo.Suppliers)</listitem>
<listitem>Click the "Generate via Wizard" button
<figure id="rd2" float="1">
<title>Generate via Wizard</title>
<graphic fileref="ui/rd2.png"/>
</figure>
</listitem>
</orderedlist>
</listitem>
<listitem>At this point, you are presented with the option to edit your column selection. Select the
"Edit" link, for example, for table Demo.demo.Shippers.
<figure id="rd3" float="1">
<title>Column Selection</title>
<graphic fileref="ui/rd3.png"/>
</figure>
</listitem>
<listitem>For images or other binary data in MIME formats to be revealed as anything other than generic "binary objects", you must map large
varbinary types to the appropriate MIME types like image/gif. To do so, select the Edit link for Binding/MIME Type of the relevant table columns.
You can:
<itemizedlist mark="bullet">
<listitem>Leave the Binding/MIME Type literal; or</listitem>
<listitem>Set to skip, such that the column will not be used in RDF generation; or </listitem>
<listitem>Select the binary object value in order for the column to be referenced as binary.</listitem>
</itemizedlist>
<figure id="rd14" float="1">
<title>Binding/MIME Types</title>
<graphic fileref="ui/rd14.png"/>
</figure>
</listitem>
<listitem>After finishing with your changes click the Save button, or cancel the changes and go back by
clicking the Cancel button.</listitem>
<listitem>Make sure you click the "Next" button.</listitem>
<listitem>At this point, the RDF View Definition form will let you Select Generation Targets options:
<orderedlist>
<listitem>Data Source Ontology Mappings</listitem>
<listitem>Instance Data View Mappings</listitem>
<listitem>VoID statistic</listitem>
</orderedlist>
<figure id="rd15" float="1">
<title>Generation Targets options</title>
<graphic fileref="ui/rd15.png"/>
</figure>
</listitem>
<listitem>Make sure you click the "Next" button.</listitem>
<listitem>Based on your selections in the prior form, the RDF View Definition Deployment Options form will be offered:
<orderedlist>
<listitem>Data Source Ontology Rules</listitem>
<listitem>Instance Data Rules
</listitem>
</orderedlist>
<figure id="rd4" float="1">
<title>Generation Targets options</title>
<graphic fileref="ui/rd4.png"/>
</figure>
</listitem>
<listitem>Select the desired option(s) and click the "Prepare to Execute" button which unveils a generated
Instance Data and/or Ontology form.
<figure id="rd5" float="1">
<title>Instance Data and/or Ontology</title>
<graphic fileref="ui/rd5.png"/>
</figure>
</listitem>
<listitem>Click the Execute button and Virtuoso will:
<orderedlist>
<listitem>Apply the generated declarations (instance data and ontology) to your Virtuoso instance</listitem>
<listitem>Publish / Deploy declarations that expose the Wizard-generated Rewrite Rules and associated endpoints.
<figure id="rd6" float="1">
<title>Publishing / Deployment declarations</title>
<graphic fileref="ui/rd6.png"/>
</figure>
</listitem>
</orderedlist>
</listitem>
<listitem>Optionally, you can also perform one of the following tasks:
<orderedlist>
<listitem>Save Data Mappings: when clicked, offers to save the generated Definitions to local file
system</listitem>
<listitem>Save Ontology Mappings: when clicked, offers to save the generated Ontology to local file
system</listitem>
<listitem>Export as WebDAV resource: exports the selected objects/items as a WebDAV resource:
<itemizedlist mark="bullet">
<listitem>Click "Browse"</listitem>
<listitem>Enter a WebDAV resource and click the "Select" button.</listitem>
</itemizedlist>
<figure id="rd7" float="1">
<title>WebDAV resource</title>
<graphic fileref="ui/rd7.png"/>
</figure>
</listitem>
</orderedlist>
<para>Note, the WebDAV resource path value will be shown in the WebDAV location field.</para>
</listitem>
<listitem>Then click the "Save Data Mappings" or "Save Ontology Mappings" button, to complete the option task of saving your generated (or edited) view declarations.
<figure id="rd8" float="1">
<title>WebDAV resource</title>
<graphic fileref="ui/rd8.png"/>
</figure>
</listitem>
<listitem>Error messages will be presented if the Wizard encounters problems. If there are no error messages, your RDF view declarations and Linked Data publishing activities will have completed successfully.
<figure id="rd9" float="1">
<title>RDF view declarations and Linked Data publishing activities Finish</title>
<graphic fileref="ui/rd9.png"/>
</figure>
</listitem>
<listitem>Click on Cancel to return to the initial RDF View Generation form.</listitem>
</orderedlist>
</sect2>
</sect1>
<sect1 id="rdfinsertmethods"><title>RDF Insert Methods in Virtuoso</title>
<sect2 id="rdfinsertmethodsapifunct"><title>Using API functions</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfapidataimportttlp">Using the DB.DBA.TTLP() function</link>
<itemizedlist mark="bullet">
<listitem>Note: use this function for loading Turtle</listitem>
</itemizedlist>
</listitem>
<listitem><link linkend="rdfapidataimportttlpmt">Using the DB.DBA.TTLP_MT() function</link>
<itemizedlist mark="bullet">
<listitem>Note: use this function for loading triples from file on multiple threads</listitem>
</itemizedlist>
</listitem>
<listitem><link linkend="rdfapidataimportttlpmt">Using the DB.DBA.RDF_LOAD_RDFXML_MT() function</link>
<itemizedlist mark="bullet">
<listitem>Note: Use this function for loading large resources when transactional integrity is not important (loading of a single resource may take more than one transaction)</listitem>
</itemizedlist>
</listitem>
<listitem><link linkend="rdfapidataimportttlphash">Using the DB.DBA.RDF_TTL2HASH() function</link>
<itemizedlist mark="bullet">
<listitem>Note: use this function to get dictionary of triples in 'long valmode'.</listitem>
</itemizedlist>
</listitem>
<listitem><link linkend="rdfapidataimportloadrdfxml">Using the DB.DBA.RDF_LOAD_RDFXML() function</link>
<itemizedlist mark="bullet">
<listitem>For loading RDF/XML, the best way is to split the data to be loaded into
multiple streams and load these in parallel using this function.</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>See <link linkend="rdfperfloading">more details</link> for loading Performance Tuning specifics.</para>
</sect2>
<sect2 id="rdfinsertmethodshttppost"><title>HTTP Post using Content-Type: application/sparql-query</title>
<para>With POST can be accomplished SPARQL Insert/Update etc.</para>
<para>The result is in the rdf_quad.</para>
<para>With GET Methods you can get the triples which are saved.</para>
<para><emphasis>Examples:</emphasis></para>
<para><emphasis>Example 1:</emphasis></para>
<para>Create a DAV collection xx for user demo with password demo.</para>
<para>Execute the following command:</para>
<programlisting><![CDATA[
curl -i -d "INSERT {<http://demo.openlinksw.com/DAV/home/demo_about.rdf>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#User>}" -u "demo:demo"
-H "Content-Type: application/sparql-query" http://localhost:8890/DAV/xx/yy
]]></programlisting>
<para>The response should be:</para>
<programlisting><![CDATA[
HTTP/1.1 201 Created
Server: Virtuoso/05.00.3023 (Win32) i686-generic-win-32 VDB
Connection: Keep-Alive
Content-Type: text/html; charset=ISO-8859-1
Date: Fri, 28 Dec 2007 12:50:12 GMT
Accept-Ranges: bytes
MS-Author-Via: SPARQL
Content-Length: 0
]]></programlisting>
<para>The result in the DAV/xx location will be a new WebDAV resource with name "yy" containing the inserted RDF:</para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<rdf:Description
rdf:about="http://demo.openlinksw.com/DAV/home/demo_about.rdf">
<ns0pred:type xmlns:ns0pred="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
rdf:resource="http://rdfs.org/sioc/ns#User"/>
</rdf:Description>
</rdf:RDF>
]]></programlisting>
<para><emphasis>Example 2:</emphasis></para>
<para>Create a DAV collection, for ex. with name "test" for user ( for ex. demo).</para>
<para>Execute the following command:</para>
<programlisting><![CDATA[
curl -i -d "INSERT IN GRAPH <http://mygraph.com>
{ <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> .
<http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this>
<http://www.w3.org/2000/01/rdf-schema#label>
<Kingsley Uyi Idehen> .
<http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this>
<http://rdfs.org/sioc/ns#creator_of>
<http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300>
} " -u "demo:demo" -H "Content-Type: application/sparql-query" http://localhost:8890/DAV/home/demo/test/myrq
]]></programlisting>
<para>As result the response will be:</para>
<programlisting><![CDATA[
HTTP/1.1 201 Created
Server: Virtuoso/05.00.3023 (Win32) i686-generic-win-32 VDB
Connection: Keep-Alive
Content-Type: text/html; charset=ISO-8859-1
Date: Thu, 20 Dec 2007 16:25:25 GMT
Accept-Ranges: bytes
MS-Author-Via: SPARQL
Content-Length: 0
]]></programlisting>
<para>Now let's check the inserted triples. Go to the sparql endpoint, i.e. http://localhost:8890/sparql and:</para>
<itemizedlist>
<listitem>Enter for Default Graph URI:
<programlisting><![CDATA[
http://mygraph.com
]]></programlisting>
</listitem>
<listitem>Enter in the Query area:
<programlisting><![CDATA[
SELECT * WHERE {?s ?p ?o}
]]></programlisting>
</listitem>
<listitem>Click the button "Run Query"</listitem>
<listitem>As result will be shown the inserted triples:
<programlisting><![CDATA[
s p o
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://rdfs.org/sioc/ns#User
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this http://www.w3.org/2000/01/rdf-schema#label Kingsley
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this http://rdfs.org/sioc/ns#creator_of http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300
]]></programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="rdfinsertmethodshttpput"><title>HTTP PUT using Content-Type: application/rdf+xml</title>
<para>The URI in a PUT request identifies the entity enclosed with the request. Therefore using HTTP PUT is a more useful and meaningful command than using POST (which is more about submitting data to a script).</para>
<para><emphasis>Example:</emphasis></para>
<para>Suppose there is myfoaf.rdf file with the following content:</para>
<programlisting><![CDATA[
<rdf:RDF xmlns="http://www.example/jose/foaf.rdf#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:log="http://www.w3.org/2000/10/swap/log#"
xmlns:myfoaf="http://www.example/jose/foaf.rdf#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<foaf:Person rdf:about="http://www.example/jose/foaf.rdf#jose">
<foaf:homepage rdf:resource="http://www.example/jose/"/>
<foaf:knows rdf:resource="http://www.example/jose/foaf.rdf#juan"/>
<foaf:name>Jose Jimen~ez</foaf:name>
<foaf:nick>Jo</foaf:nick>
<foaf:workplaceHomepage rdf:resource="http://www.corp.example/"/>
</foaf:Person>
<foaf:Person rdf:about="http://www.example/jose/foaf.rdf#juan">
<foaf:mbox rdf:resource="mailto:juan@mail.example"/>
</foaf:Person>
<foaf:Person rdf:about="http://www.example/jose/foaf.rdf#julia">
<foaf:mbox rdf:resource="mailto:julia@mail.example"/>
</foaf:Person>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#kendall">
<foaf:knows rdf:resource="http://www.example/jose/foaf.rdf#edd"/>
</rdf:Description>
</rdf:RDF>
]]></programlisting>
<para>Now let's upload the myfoaf.rdf file to destination server demo.openlinksw.com for user demo:</para>
<programlisting><![CDATA[
curl -T myfoaf.rdf http://demo.openlinksw.com/DAV/home/demo/rdf_sink/myfoaf.rdf -u demo:demo
]]></programlisting>
<para>As result the response should be:</para>
<programlisting><![CDATA[
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE>201 Created</TITLE>
</HEAD>
<BODY>
<H1>Created</H1>
Resource /DAV/home/demo/rdf_sink/ myfoaf.rdf has been created.
</BODY>
</HTML>
]]></programlisting>
<para>Then you can execute:</para>
<programlisting><![CDATA[
curl -F "query=SELECT DISTINCT ?p FROM <http://demo.openlinksw.com/DAV/home/demo/rdf_sink/> WHERE {?s ?p ?o}" http://demo.openlinksw.com/sparql
]]></programlisting>
<para>The result should be:</para>
<programlisting><![CDATA[
<?xml version="1.0" ?>
<sparql xmlns="http://www.w3.org/2005/sparql-results#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.w3.org/2001/sw/DataAccess/rf1/result2.xsd">
<head>
<variable name="p"/>
</head>
<results distinct="false" ordered="true">
<result>
<binding name="p"><uri>http://www.w3.org/1999/02/22-rdf-syntax-ns#type</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/nick</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/name</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/homepage</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/knows</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/workplaceHomepage</uri></binding>
</result>
<result>
<binding name="p"><uri>http://xmlns.com/foaf/0.1/mbox</uri></binding>
</result>
</results>
</sparql>
]]></programlisting>
<para>Other examples with curl:</para>
<programlisting><![CDATA[
curl -F "query=SELECT distinct ?Concept FROM <http://dbpedia.org> WHERE {?s a ?Concept} limit 10" http://dbpedia.org/sparql
]]></programlisting>
<programlisting><![CDATA[
curl -F "query=SELECT distinct ?Concept FROM <http://myopenlink.net/dataspace/person/kidehen> WHERE {?s a ?Concept} limit 10" http://demo.openlinksw.com/sparql
]]></programlisting>
<programlisting><![CDATA[
curl -F "query=SELECT distinct ?Concept FROM <http://data.openlinksw.com/oplweb/product_family/virtuoso> WHERE {?s a ?Concept} limit 10" http://demo.openlinksw.com/sparql
]]></programlisting>
<programlisting><![CDATA[
curl -F "query=SELECT distinct ?Concept FROM <http://openlinksw.com/dataspace/organization/openlink> WHERE {?s a ?Concept} limit 10" http://demo.openlinksw.com/sparql
]]></programlisting>
</sect2>
<sect2 id="rdfinsertmethodsload"><title>SPARQL Insert using LOAD</title>
<para>SPARQL INSERT operation can be done using the LOAD feature.</para>
<para><emphasis>Example:</emphasis></para>
<para>Execute from ISQL:</para>
<programlisting><![CDATA[
SPARQL insert in graph <http://mygraph.com>
{
<http://myopenlink.net/dataspace/Kingsley#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> .
<http://myopenlink.net/dataspace/Kingsley#this>
<http://rdfs.org/sioc/ns#id>
<Kingsley> .
<http://myopenlink.net/dataspace/Caroline#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> .
<http://myopenlink.net/dataspace/Caroline#this>
<http://rdfs.org/sioc/ns#id>
<Caroline> .
<http://myopenlink.net/dataspace/Matt#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> .
<http://myopenlink.net/dataspace/Matt#this>
<http://rdfs.org/sioc/ns#id>
<Matt> .
<http://myopenlink.net/dataspace/demo#this>
<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>
<http://rdfs.org/sioc/ns#User> .
<http://myopenlink.net/dataspace/demo#this>
<http://rdfs.org/sioc/ns#id>
<demo> .};
]]></programlisting>
<para>Create DAV collection which is visible to public, for ex: http://localhost:8890/DAV/tmp</para>
<para>Upload to the DAV collection the following file for ex. with name listall.rq and with the following content:</para>
<programlisting><![CDATA[
SPARQL
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sioc: <http://rdfs.org/sioc/ns#>
SELECT ?x ?p ?o
FROM <http://mygraph.com>
WHERE
{
?x rdf:type sioc:User .
?x ?p ?o.
?x sioc:id ?id .
FILTER REGEX(str(?id), "^King")
}
ORDER BY ?x
]]></programlisting>
<para>Now from ISQL execute the following command:</para>
<programlisting><![CDATA[
SQL>SPARQL
load bif:concat ("http://", bif:registry_get("URIQADefaultHost"), "/DAV/tmp/listall.rq") into graph <http://myNewGraph.com>;
]]></programlisting>
<para>As result should be shown:</para>
<programlisting><![CDATA[
callret-0
VARCHAR
_______________________________________________________________________________
Load <http://localhost:8890/DAV/tmp/listall.rq> into graph <http://myNewGraph.com> -- done
1 Rows. -- 321 msec.
]]></programlisting>
</sect2>
<sect2 id="rdfindertmethodsparqlendpoint"><title>SPARQL Insert via /sparql endpoint</title>
<para>SPARQL INSERT operation can be sent to a web service endpoint as a single statement and executed in sequence.</para>
<para><emphasis>Example:</emphasis></para>
<para>Using the Virtuoso ISQL tool or using the /sparql UI at http://host:port/sparql, execute the following:</para>
<itemizedlist>
<listitem>Insert into graph http://BookStore.com 3 triples:
<programlisting><![CDATA[
SQL>SPARQL insert in graph <http://BookStore.com>
{ <http://www.dajobe.org/foaf.rdf#i> <http://purl.org/dc/elements/1.1/date> <1999-04-01T00:00:00> .
<http://www.w3.org/People/Berners-Lee/card#i> <http://purl.org/dc/elements/1.1/date> <1998-05-03T00:00:00> .
<http://www.w3.org/People/Connolly/#me> <http://purl.org/dc/elements/1.1/date> <2001-02-08T00:00:00> };
]]></programlisting>
</listitem>
<listitem>As result will be shown the message:
<programlisting><![CDATA[
SQL>Insert into <http://BookStore.com>
3 triples -- done
]]></programlisting>
</listitem>
<listitem>Next we will select all triples from the graph http://BookStore.com:
<programlisting><![CDATA[
SQL>SPARQL SELECT * FROM <http://BookStore.com> WHERE {?s ?p ?o};
]]></programlisting>
</listitem>
<listitem>As result will be shown:
<programlisting><![CDATA[
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.w3.org/People/Berners-Lee/card#i http://purl.org/dc/elements/1.1/date 1998-05-03T00:00:00
http://www.w3.org/People/Connolly/#me http://purl.org/dc/elements/1.1/date 2001-02-08T00:00:00
http://www.dajobe.org/foaf.rdf#i http://purl.org/dc/elements/1.1/date 1999-04-01T00:00:00
3 Rows. -- 0 msec.
]]></programlisting>
</listitem>
<listitem>Now let's insert into graph another http://NewBookStore.com graph's values:
<programlisting><![CDATA[
SQL>SPARQL
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
INSERT INTO GRAPH <http://NewBookStore.com> { ?book ?p ?v }
WHERE
{ GRAPH <http://BookStore.com>
{ ?book dc:date ?date
FILTER ( xsd:dateTime(?date) < xsd:dateTime("2000-01-01T00:00:00")).
?book ?p ?v.
}
};
]]></programlisting>
</listitem>
<listitem>As result will be shown:
<programlisting><![CDATA[
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <http://NewBookStore.com>, 2 triples -- done
]]></programlisting>
</listitem>
<listitem>Finally we will check the triples from the graph NewBookStore.com:
<programlisting><![CDATA[
SQL> SPARQL
SELECT *
FROM <http://NewBookStore.com>
WHERE {?s ?p ?o};
]]></programlisting>
</listitem>
<listitem>As result will be shown:
<programlisting><![CDATA[
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.w3.org/People/Berners-Lee/card#i http://purl.org/dc/elements/1.1/date 1998-05-03T00:00:00
http://www.dajobe.org/foaf.rdf#i http://purl.org/dc/elements/1.1/date 1999-04-01T00:00:00
2 Rows. -- 10 msec.
]]></programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="rdfinsertmethodsparqlqueryandodswiki"><title>SPARQL Insert via HTTP Post using Content-Type: application/sparql-query and ODS wiki</title>
<para>With HTTP Post and ODS wiki can be written an rdf document and respectively to be performed over it INSERT/UPDATE action.</para>
<para>You can write to a file using SIOC terms for ODS-Wiki</para>
<para>You can check with sparql the inserted / updated triples in the Quad Store.</para>
<para><emphasis>Example:</emphasis></para>
<para>Suppose there is ODS user test3 with ODS password 1, which has testWiki wiki instance.</para>
<para>Execute the following:</para>
<programlisting><![CDATA[
curl -i -d "INSERT {<http://localhost:8890/dataspace/test3/wiki/testWiki> <http://atomowl.org/ontologies/atomrdf#contains> <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://rdfs.org/sioc/ns#has_container> <http://localhost:8890/dataspace/test3/wiki/testWiki> . <http://localhost:8890/dataspace/test3/wiki/testWiki> <http://atomowl.org/ontologies/atomrdf#entry> <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> . <http://localhost:8890/dataspace/test3/wiki/testWiki> <http://rdfs.org/sioc/ns#container_of> <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://rdfs.org/sioc/ns#topic> <http://localhost:8890/dataspace/test3/wiki/testWiki> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://atomowl.org/ontologies/atomrdf#source> <http://localhost:8890/dataspace/test3/wiki/testWiki> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/types#Comment> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://atomowl.org/ontologies/atomrdf#Entry> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://www.w3.org/2000/01/rdf-schema#label> 'MyTest' . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://atomowl.org/ontologies/atomrdf#Link> . <http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://rdfs.org/sioc/ns#content> <test>}" -u "test3:1" -H "Content-Type: application/sparql-query" http://localhost:8890/DAV/home/test3/wiki/testWiki/MyTest
]]></programlisting>
<para>As result we should have 2 files created:</para>
<itemizedlist>
<listitem>In the user DAV folder "DAV/home/test3/wiki/testWiki/" will be created a file "MyTest" with type "application/sparql-query". You can view the content of this file from the Conductor UI or from the user's Briefcase UI, path "DAV/home/test3/wiki/testWiki". Its content will be:
<programlisting><![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki"><ns0pred:entry xmlns:ns0pred="http://atomowl.org/ontologies/atomrdf#" rdf:resource="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:label xmlns:ns0pred="http://www.w3.org/2000/01/rdf-schema#">MyTest</ns0pred:label></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:type xmlns:ns0pred="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="http://atomowl.org/ontologies/atomrdf#Link"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:type xmlns:ns0pred="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="http://rdfs.org/sioc/types#Comment"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:type xmlns:ns0pred="http://www.w3.org/1999/02/22-rdf-syntax-ns#" rdf:resource="http://atomowl.org/ontologies/atomrdf#Entry"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:has_container xmlns:ns0pred="http://rdfs.org/sioc/ns#" rdf:resource="http://localhost:8890/dataspace/test3/wiki/testWiki"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki"><ns0pred:container_of xmlns:ns0pred="http://rdfs.org/sioc/ns#" rdf:resource="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki"><ns0pred:contains xmlns:ns0pred="http://atomowl.org/ontologies/atomrdf#" rdf:resource="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:content xmlns:ns0pred="http://rdfs.org/sioc/ns#">test</ns0pred:content></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:topic xmlns:ns0pred="http://rdfs.org/sioc/ns#" rdf:resource="http://localhost:8890/dataspace/test3/wiki/testWiki"/></rdf:Description>
<rdf:Description rdf:about="http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest"><ns0pred:source xmlns:ns0pred="http://atomowl.org/ontologies/atomrdf#" rdf:resource="http://localhost:8890/dataspace/test3/wiki/testWiki"/></rdf:Description>
</rdf:RDF>
]]></programlisting>
</listitem>
<listitem>To the user's wiki instance will be added a new WikiWord "MyTest" with content the value of the SIOC term attribute "content":
<programlisting><![CDATA[
<http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest> <http://rdfs.org/sioc/ns#content> <test>
i.e. the content will be "test".
]]></programlisting>
</listitem>
</itemizedlist>
<para>Now let's check what data was inserted in the Quad Store:</para>
<itemizedlist>
<listitem>Go to the sparql endpoint, i.e. for ex. to http://localhost:8890/sparql</listitem>
<listitem>Enter for Default Graph URI:
<programlisting><![CDATA[
http://localhost:8890/DAV/home/test3/wiki/testWiki/MyTest
]]></programlisting>
</listitem>
<listitem>Enter for Query text:
<programlisting><![CDATA[
SELECT * WHERE {?s ?p ?o}
]]></programlisting>
</listitem>
<listitem>Click the "Run Query" button.</listitem>
<listitem>As result will be shown the inserted triples:
<programlisting><![CDATA[
s p o
http://localhost:8890/dataspace/test3/wiki/testWiki http://rdfs.org/sioc/ns#container_of http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest
http://localhost:8890/dataspace/test3/wiki/testWiki http://atomowl.org/ontologies/atomrdf#entry http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest
http://localhost:8890/dataspace/test3/wiki/testWiki http://atomowl.org/ontologies/atomrdf#contains http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://rdfs.org/sioc/types#Comment
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://atomowl.org/ontologies/atomrdf#Entry
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://atomowl.org/ontologies/atomrdf#Link
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://www.w3.org/2000/01/rdf-schema#label MyTest
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://rdfs.org/sioc/ns#has_container http://localhost:8890/dataspace/test3/wiki/testWiki
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://rdfs.org/sioc/ns#content test
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://rdfs.org/sioc/ns#topic http://localhost:8890/dataspace/test3/wiki/testWiki
http://localhost:8890/dataspace/test3/wiki/testWiki/MyTest http://atomowl.org/ontologies/atomrdf#source http://localhost:8890/dataspace/test3/wiki/testWiki
]]></programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="rdfinsertmethodwebdav">
<title>Using WebDAV</title>
<para> Example using WebDAV (mount folder to DAV and dump; if this is the rdf_sink
the Quad Store is updated automatically, or you can load from DAV manually to quad store)</para>
<para><emphasis>Example:</emphasis></para>
<para><emphasis>Example 1: Using ODS Briefcase</emphasis></para>
<itemizedlist>
<listitem>Go to your ods location, for ex. http://localhost:8890/ods</listitem>
<listitem>Register user, for ex. user test1</listitem>
<listitem>Login if not already in ods</listitem>
<listitem>Go to ODS -> Briefcase</listitem>
<listitem>Go to ODS -> Briefcase</listitem>
<listitem>Click the "New folder" icon from the Main Briefcase horizontal navigation</listitem>
<listitem>Enter for name for ex. "mytest" and click the "Create" button.
<figure id="uc6" float="1">
<title>Using Briefcase UI</title>
<graphic fileref="ui/uc6.png"/>
</figure>
</listitem>
<listitem>Go to folder "mytest" and click the click the "Upload" icon from the Main Briefcase horizontal navigation</listitem>
<listitem>Enter for name for ex. "mytest" and click the "Create" button.
<figure id="uc7" float="1">
<title>Using Briefcase UI</title>
<graphic fileref="ui/uc7.png"/>
</figure>
</listitem>
<listitem>In the shown form set:
<itemizedlist>
<listitem>Destination: RDF Store</listitem>
<listitem>RDF graph name for ex. with the value: http://localhost:8890/DAV/home/test2/mytest/</listitem>
<listitem>Select URL or File. For ex. you can select the following file with name jose.rdf:
<programlisting><![CDATA[
<rdf:RDF xmlns="http://www.example/jose/foaf.rdf#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:log="http://www.w3.org/2000/10/swap/log#"
xmlns:myfoaf="http://www.example/jose/foaf.rdf#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<foaf:Person rdf:about="http://www.example/jose/foaf.rdf#jose">
<foaf:homepage rdf:resource="http://www.example/jose/"/>
<foaf:knows rdf:resource="http://www.example/jose/foaf.rdf#juan"/>
<foaf:name>Jose Jimen~ez</foaf:name>
<foaf:nick>Jo</foaf:nick>
<foaf:workplaceHomepage rdf:resource="http://www.corp.example/"/>
</foaf:Person>
<foaf:Person rdf:about="http://www.example/jose/foaf.rdf#juan">
<foaf:mbox rdf:resource="mailto:juan@mail.example"/>
</foaf:Person>
<foaf:Person rdf:about="http://www.example/jose/foaf.rdf#julia">
<foaf:mbox rdf:resource="mailto:julia@mail.example"/>
</foaf:Person>
<rdf:Description rdf:about="http://www.example/jose/foaf.rdf#kendall">
<foaf:knows rdf:resource="http://www.example/jose/foaf.rdf#edd"/>
</rdf:Description>
</rdf:RDF>
]]></programlisting>
</listitem>
</itemizedlist>
</listitem>
<listitem>You can also perform the steps from above by uploading the file in the rdf_sink
folder i.e. in Briefcase it will be with this path: DAV/home/test2/rdf_sink and respectively the "RDF graph name"
will have this value: http://host:port/DAV/home/username/rdf_sink/</listitem>
</itemizedlist>
<para>Execute from ISQL or from the SPARQL endpoint the following query:</para>
<programlisting><![CDATA[
SELECT * FROM <http://localhost:8890/DAV/home/test2/mytest/>
WHERE {?s ?p ?o}
]]></programlisting>
<para>As result should be shown:</para>
<programlisting><![CDATA[
s p o
http://www.example/jose/foaf.rdf#jose http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/nick Jo
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/name Jose Jimen~ez
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/knows http://www.example/jose/foaf.rdf#juan
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/homepage http://www.example/jose/
http://www.example/jose/foaf.rdf#jose http://xmlns.com/foaf/0.1/workplaceHomepage http://www.corp.example/
http://www.example/jose/foaf.rdf#kendall http://xmlns.com/foaf/0.1/knows http://www.example/jose/foaf.rdf#edd
http://www.example/jose/foaf.rdf#julia http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.example/jose/foaf.rdf#julia http://xmlns.com/foaf/0.1/mbox mailto:julia@mail.example
http://www.example/jose/foaf.rdf#juan http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Person
http://www.example/jose/foaf.rdf#juan http://xmlns.com/foaf/0.1/mbox mailto:juan@mail.example
]]></programlisting>
<para><emphasis>Example 2: Using Conductor UI</emphasis></para>
<itemizedlist>
<listitem>Go to Conductor UI, for ex. at http://localhost:8890/conductor</listitem>
<listitem>Login as dba user</listitem>
<listitem>Go to Web Application Server
<figure id="uc1" float="1">
<title>Using Conductor UI</title>
<graphic fileref="ui/uc1.png"/>
</figure>
</listitem>
<listitem>Click the "New Folder" button.</listitem>
<listitem>Enter for name for ex. test and click the "Create" button.
<figure id="uc2" float="1">
<title>Using Conductor UI</title>
<graphic fileref="ui/uc2.png"/>
</figure>
</listitem>
<listitem>Click the new folder "test" name link.
<figure id="uc3" float="1">
<title>Using Conductor UI</title>
<graphic fileref="ui/uc3.png"/>
</figure>
</listitem>
<listitem>Click the "Upload" button and in the shown form select Destination: RDF Store.
<figure id="uc4" float="1">
<title>Using Conductor UI</title>
<graphic fileref="ui/uc4.png"/>
</figure>
</listitem>
<listitem>In the shown form click the "Browse" button in order to select a file, for ex. the file jose.rdf
and set the "RDF IRI*"
<figure id="uc5" float="1">
<title>Using Conductor UI</title>
<graphic fileref="ui/uc5.png"/>
</figure>
</listitem>
<listitem>Click the "Upload" button.</listitem>
</itemizedlist>
</sect2>
<sect2 id="rdfinsertmethodvirtuosocrawler">
<title>Using Virtuoso Crawler</title>
<para>Using Virtuoso Crawler (which includes the Sponger options so you crawl
non-RDF but get RDF and this can go to the Quad Store)</para>
<para><emphasis>Example:</emphasis></para>
<para>Go to Conductor UI. For ex. at http://localhost:8890/conductor</para>
<para>Login as dba user</para>
<para>Go to tab Web Application Server</para>
<para>Go to tab Content Imports</para>
<para>Click the "New Target" button</para>
<para>In the shown form:</para>
<itemizedlist>
<listitem>Enter for "Target description": Tim Berners-Lee's electronic Business Card</listitem>
<listitem>Enter for "Target URL": http://www.w3.org/People/Berners-Lee</listitem>
<listitem>Enter for "Copy to local DAV collection" for ex.: /DAV/home/demo/rdf_sink/</listitem>
<listitem>Choose from the list "Local resources owner": demo</listitem>
<listitem>Check the check.box with label "Store metadata".</listitem>
<listitem>Check all the check-boxes shown below the check-box "Store metadata".</listitem>
<listitem>Click the button "Create".
<figure id="rdfinsertwebdav1" float="1">
<title>Using Virtuoso Crawler</title>
<graphic fileref="ui/rdfinsert1.png"/>
</figure>
</listitem>
</itemizedlist>
<para>Click the button "Import Queues".</para>
<para>For "Robot target" with label "Tim Berners-Lee's electronic Business Card"
click the start link.</para>
<para>As result should be shown the number of the pages retrieved.</para>
<figure id="rdfinsertwebdav2" float="1">
<title>Using Virtuoso Crawler</title>
<graphic fileref="ui/rdfinsert2.png"/>
</figure>
<para>Now using the sparql endpoint with sponger option "Use only local data"
enter for Default Graph URI: http://www.w3.org/People/Berners-Lee and execute the following query: </para>
<programlisting><![CDATA[
SELECT *
WHERE {?s ?p ?o}
]]></programlisting>
<para>As result should be shown the following triples:</para>
<programlisting><![CDATA[
s p o
http://www.w3.org/People/Berners-Lee http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Document
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Answers for young people - Tim Berners-Lee
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Berners-Lee: Weaving the Web
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Declaration by Tim BL 28 Feb 1996 w.r.t. CDA challenge
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Errata - Berners-Lee: Weaving the Web
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Frequently asked questions by the Press - Tim BL
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Glossary - Weaving the Web - Berners-Lee
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Longer Bio for Tim Berners-Lee
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Michael Dertouzos has left us
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title The Future of the Web and Europe
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title The World Wide Web: Past, Present and Future
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title The World Wide Web: A very short personal history
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Tim Berners-Lee
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Tim Berners-Lee - 3Com Founders chair
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Tim Berners-Lee: Disclosures
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Tim Berners-Lee: WWW and UU and I
http://www.w3.org/People/Berners-Lee http://purl.org/dc/elements/1.1/title Tim Berners-Lee: WorldWideWeb, the first Web client
]]></programlisting>
<para><emphasis>Example: Use of schedular to interface Virtuoso Quad Store with PTSW using the following program:</emphasis></para>
<programlisting><![CDATA[
create procedure PTSW_CRAWL ()
{
declare xt, xp any;
declare content, headers any;
content := http_get ('http://pingthesemanticweb.com/export/', headers);
xt := xtree_doc (content);
xp := xpath_eval ('//rdfdocument/@url', xt, 0);
foreach (any x in xp) do
{
x := cast (x as varchar);
dbg_obj_print (x);
{
declare exit handler for sqlstate '*' {
log_message (sprintf ('PTSW crawler can not load : %s', x));
};
sparql load ?:x into graph ?:x;
update DB.DBA.SYS_HTTP_SPONGE set HS_LOCAL_IRI = x, HS_EXPIRATION = null WHERE HS_LOCAL_IRI = 'destMD5=' || md5 (x) || '&graphMD5=' || md5 (x);
commit work;
}
}
}
;
insert soft SYS_SCHEDULED_EVENT (SE_SQL, SE_START, SE_INTERVAL, SE_NAME)
values ('DB.DBA.PTSW_CRAWL ()', cast (stringtime ('0:0') as DATETIME), 60, 'PTSW Crawling');
]]></programlisting>
</sect2>
<sect2 id="rdfinsertmethodsparqlqueryandsponger">
<title>Using SPARQL Query and Sponger (i.e. we Sponge the Resources in the FROM Clause or values for the graph-uri parameter in SPARQL protocol URLs)</title>
<para><emphasis>Example:</emphasis></para>
<para>Execute the following query: </para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT ?id
FROM NAMED <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
OPTION (get:soft "soft", get:method "GET")
WHERE { GRAPH ?g { ?id a ?o } }
limit 10;
]]></programlisting>
<para>As result will be shown the retrieved triples:</para>
<programlisting><![CDATA[
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com#this
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/612
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/612
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/610
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/610
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/856
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/856
10 Rows. -- 20 msec.
]]></programlisting>
</sect2>
<sect2 id="rdfinsertmethodplapis">
<title>Using Virtuoso PL APIs</title>
<para><emphasis>Example:</emphasis></para>
<para>In the example script we implement a basic mapper which maps a text/plain mime type
to an imaginary ontology, which extends the class Document from FOAF with properties 'txt:UniqueWords'
and 'txt:Chars', where the prefix 'txt:' we specify as 'urn:txt:v0.0:'.</para>
<programlisting><![CDATA[
use DB;
create procedure DB.DBA.RDF_LOAD_TXT_META
(
in graph_iri varchar,
in new_origin_uri varchar,
in dest varchar,
inout ret_body any,
inout aq any,
inout ps any,
inout ser_key any
)
{
declare words, chars int;
declare vtb, arr, subj, ses, str any;
declare ses any;
-- if any error we just say nothing can be done
declare exit handler for sqlstate '*'
{
return 0;
};
subj := coalesce (dest, new_origin_uri);
vtb := vt_batch ();
chars := length (ret_body);
-- using the text index procedures we get a list of words
vt_batch_feed (vtb, ret_body, 1);
arr := vt_batch_strings_array (vtb);
-- the list has 'word' and positions array , so we must divide by 2
words := length (arr) / 2;
ses := string_output ();
-- we compose a N3 literal
http (sprintf ('<%s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .\n', subj), ses);
http (sprintf ('<%s> <urn:txt:v0.0:UniqueWords> "%d" .\n', subj, words), ses);
http (sprintf ('<%s> <urn:txt:v0.0:Chars> "%d" .\n', subj, chars), ses);
str := string_output_string (ses);
-- we push the N3 text into the local store
DB.DBA.TTLP (str, new_origin_uri, subj);
return 1;
}
;
--
DELETE FROM DB.DBA.SYS_RDF_MAPPERS WHERE RM_HOOK = 'DB.DBA.RDF_LOAD_TXT_META';
INSERT SOFT DB.DBA.SYS_RDF_MAPPERS (RM_PATTERN, RM_TYPE, RM_HOOK, RM_KEY, RM_DESCRIPTION)
VALUES ('(text/plain)', 'MIME', 'DB.DBA.RDF_LOAD_TXT_META', null, 'Text Files (demo)');
-- here we set order to some large number so don't break existing mappers
update DB.DBA.SYS_RDF_MAPPERS set RM_ID = 2000 WHERE RM_HOOK = 'DB.DBA.RDF_LOAD_TXT_META';
]]></programlisting>
<para>To test the mapper we just use /sparql endpoint with option 'Retrieve remote
RDF data for all missing source graphs' to execute:</para>
<programlisting><![CDATA[
SELECT * FROM <http://demo.openlinksw.com:8890/tutorial/hosting/ho_s_30/WebCalendar/tools/summary.txt>
WHERE { ?s ?p ?o }
]]></programlisting>
<para>To check the results:</para>
<itemizedlist>
<listitem>Make sure the initial state of tutorial <ulink url="http://demo.openlinksw.com/tutorial/rdf/rd_s_1/rd_s_1.vsp">RD_S_1</ulink> is set.</listitem>
<listitem>Go to http://demo.openlinksw.com/sparql</listitem>
<listitem>Enter for Default Graph URI this value:</listitem>
<programlisting><![CDATA[
http://localhost:80/tutorial/hosting/ho_s_30/WebCalendar/tools/summary.txt
]]></programlisting>
<listitem>Enter for Query text:</listitem>
<programlisting><![CDATA[
SELECT *
WHERE {?s ?p ?o}
]]></programlisting>
<listitem>Click the "Run Query" button.</listitem>
<listitem>As result should be shown the following triples:</listitem>
<programlisting><![CDATA[
s p o
http://localhost:80/tutorial/hosting/ho_s_30/WebCalendar/tools/summary.txt http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://xmlns.com/foaf/0.1/Document
http://localhost:80/tutorial/hosting/ho_s_30/WebCalendar/tools/summary.txt urn:txt:v0.0:UniqueWords 47
http://localhost:80/tutorial/hosting/ho_s_30/WebCalendar/tools/summary.txt urn:txt:v0.0:Chars 625
]]></programlisting>
</itemizedlist>
<para><emphasis>Important: Setting Sponger Permissions</emphasis></para>
<para>In order to allow the Sponger to update the local RDF quad store with triples
constituting the sponged structured data, the role "SPARQL_SPONGE" must be granted to the
account "SPARQL", i.e., to the owner account of /sparql web service endpoint.
This should normally be the case. If not, you must manually grant this
permission. As with most Virtuoso DBA tasks, the Conductor provides the simplest means of
doing this.</para>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem>The <link linkend="fn_rdf_load_rdfxml">DB.DBA.RDF_LOAD_RDFXML</link> function to
parse the content of RDF/XML text.</listitem>
<listitem>The <link linkend="fn_ttlp_mt">DB.DBA.TTLP_MT</link> function to
parse TTL (TURTLE or N3 resource).</listitem>
<listitem>The <link linkend="fn_gz_file_open">gz_file_open</link> function to
retrieve content of a gzipped file and example for loading gzipped N3 and Turtle files.</listitem>
</itemizedlist>
</tip>
</sect2>
<sect2 id="rdfinsertmethodsimilerdfbankapi">
<title>Using SIMILE RDF Bank API</title>
<para>Virtuoso implements the HTTP-based Semantic Bank API that enables client
applications to post to its RDF Triple Store. This method offers an alternative to
using Virtuoso/PL functions or WebDAV uploads as the triples-insertion mechanism.</para>
<para><emphasis>Example:</emphasis></para>
<para>From your machine go to Firefox->Tools->PiggyBank->My Semantic Bank Accounts</para>
<para>Add in the shown form:</para>
<itemizedlist>
<listitem>For bank: address: http://demo.openlinksw.com/bank</listitem>
<listitem>For account id: demo</listitem>
<listitem>For password: demo</listitem>
</itemizedlist>
<para>Go to http://demo.openlinksw.com/ods</para>
<para>Log in as user demo, password: demo</para>
<para>Go to the Weblog tab from the main ODS Navigation</para>
<para>Click on weblog instance name, for ex. "demo's Weblog".</para>
<para>When the weblog home page is loaded, click Alt + P.</para>
<para>As result is shown the "My PiggyBank" page with all the collected information
presented in items.</para>
<para>For several of the items add Tags from the form "Tag" shown for each of them.</para>
<para>As result should be shown the message "Last updated: [here goes the date value].</para>
<para>You can also click "Save" and "Publish" for these items.</para>
<para>Go to http://demo.openlinksw.com/sparql</para>
<para>Enter for the "Default Graph URI" field: http://simile.org/piggybank/demo</para>
<para>Enter for the "Query text" text-area:</para>
<programlisting><![CDATA[
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix sioc: <http://rdfs.org/sioc/ns#>
SELECT *
FROM <http://simile.org/piggybank/demo>
WHERE {?s ?p ?o}
]]></programlisting>
<para>Click "Run Query".</para>
<para>As results are shown the found results.</para>
</sect2>
<sect2 id="rdfinsertmethodrdfnet">
<title>Using RDF NET</title>
<para><emphasis>Example:</emphasis></para>
<para>Execute the following query:</para>
<programlisting><![CDATA[
SQL> SELECT DB.DBA.HTTP_RDF_NET ('sparql load
"http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com"
into graph <http://www.openlinksw.com/>');
]]></programlisting>
<para>As result should be shown:</para>
<programlisting><![CDATA[
callret
VARCHAR
_______________________________________________________
<?xml version="1.0" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:vcard="http://www.w3.org/2001/vcard-rdf/3.0#"
xmlns="http://example.org/book/" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:ns="http://example.org/ns#">
<rdf:Description>
<callret-0>Load <http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com>
into graph <http://www.openlinksw.com/> -- done</callret-0>
</rdf:Description>
</rdf:RDF>
1 Rows. -- 1982 msec.
]]></programlisting>
</sect2>
<sect2 id="rdfinsertmethodproxy">
<title>Using the RDF Proxy (Sponger) Service</title>
<para>Triples can be inserted also using the Sponger Proxy URI Service. For more information and examples see <link linkend="rdfproxyservice">here</link>.</para>
</sect2>
</sect1>
<sect1 id="rdfsparqlintegrationmiddleware"><title>Integration Middleware</title>
<sect2 id="virtuososponger"><title>RDFizer Middleware (Sponger)</title>
<sect3 id="virtuosospongerintro"><title>Introduction</title>
<para>The Virtuoso Sponger is a middleware component of Virtuoso that generates RDF Linked Data
from a variety of data sources. The sponger is transparently integrated into Virtuoso's SPARQL Query
Processor, where it delivers URI de-referencing functionality and data caching services. Optionally,
it can be used by the <link linkend="importtargets">Virtuoso Content Crawler</link> to periodically
build and replenish local RDF graphs.
</para>
<para>The sponger is a fully fledged HTTP proxy service that is also directly accessible via SOAP or
REST interfaces.</para>
<figure id="virtuosospongerdiagram" float="1">
<title>Virtuoso Sponger</title>
<graphic fileref="linked_data_gen_opts3.png"/>
</figure>
<para>
A majority of the worlds data naturally resides in non RDF form at the current time. The Sponger
delivers middleware that accelerates the bootstrap of the Semantic Data Web by generating RDF
from non RDF data sources, unobtrusively.
</para>
<para>
When an RDF aware client requests data from a network accessible resource via the Sponger
the following events occur:
</para>
<itemizedlist>
<listitem>A requests in made for data in RDF form, and if RDF is returned nothing further happens</listitem>
<listitem>If RDF isn't returned, then the Sponger passes the data through a Metadata Extraction
Pipeline process (using Metadata Extractors)</listitem>
<listitem>The extracted data is transformed to RDF via a Mapping Pipeline process (RDF is extracted by way
of Ontology matching and mapping) that results in RDF Entities (instance data) generation</listitem>
<listitem>RDF Entities are returned to the client</listitem>
</itemizedlist>
<para>The imported data forms a local cache and its invalidation rules conform to those of traditional
HTTP clients (Web Browsers). Thus, expiration time is determined based on subsequent data fetches of
the same resource (note: the first data load will record the 'expires' header) with current time
compared to expiration time stored in the local cache. If HTTP 'expires' header data isn't returned
by the source data server, then the "Sponger" will derive it's own invalidation time frame by
evaluating the 'date' header and 'last-modified' HTTP headers. Irrespective of path taken,
local cache invalidation is driven by an assessment of current time relative to recorded expiration time.
</para>
<para>Designed with a pluggable architecture, the Sponger's core functionality is provided by Cartridges.
Each cartridge includes Data Extractors which extract data from one or more data sources, and Ontology
Mappers which map the extracted data to one or more ontologies/schemas, and route to producing RDF
Linked Data.
</para>
<para>The Schema Mappers are typically XSLT (e.g. GRDDL and other OpenLink Mapping Schemes) or
Virtuoso PL based. The Metadata Extractors may be developed in Virtuoso PL, C/C++, Java, or any
other language that can be integrated into the Virtuoso via it's server extensions APIs.
</para>
<para>
The Sponger also includes a pluggable name resolution mechanism that enables the development of
Custom Resolvers for naming schemes (e.g. URNs) associated with protocols beyond HTTP.
Examples of custom resolvers include:
</para>
<itemizedlist>
<listitem>LSID</listitem>
<listitem>DOI</listitem>
</itemizedlist>
<para><emphasis>How is it used?</emphasis></para>
<para>The Sponger can be invoked via the following mechanisms:</para>
<orderedlist>
<listitem>Virtuoso SPARQL query processor</listitem>
<listitem>OpenLink RDF client applications via the Virtuoso RDF Proxy Service</listitem>
<listitem>From Virtuoso PL, by calling the cartridge hook function directly</listitem>
<listitem>ODS-Briefcase (Virtuoso WebDAV) - a component of the OpenLink Data Spaces distributed collaborative application platform</listitem>
</orderedlist>
<para>File metadata extraction by ODS-Briefcase details you can find at the <ulink url="http://virtuoso.openlinksw.com/Whitepapers/pdf/sponger_whitepaper_10102007.pdf">Virtuoso Sponger whitepaper</ulink>.</para>
<para><emphasis>SPARQL Query Processor IRI Dereferencing</emphasis></para>
<para>The Sponger is transparently integrated into the Virtuoso SPARQL query processor, where it supports
IRI dereferencing.</para>
<para>Given the distributed nature of RDF data, it is quite possible when executing a SPARQL query that
some of the referenced data resides outside the local quad store. To cope with this scenario, the Virtuoso
SPARQL query processor can be instructed to retrieve the external data and cache it in local quad storage.
This feature is exposed through a set of Virtuoso SPARQL extensions known as "IRI dereferencing".
Essentially these enable downloading and local storage of selected triples either from one or more
named graphs or based on a proximity search from a starting URI for entities matching the select
criteria and also related by the specified predicates, up to a given depth. Because the SPARQL
processor understands only RDF data (serialized as RDF/XML, Turtle, N3), it utilizes the Sponger
RDF mapper functionality when dereferencing web or file resources which don't naturally contain RDF data.</para>
<para><emphasis>RDF Proxy Service</emphasis></para>
<para>The Sponger's functionality is also exposed via an in-built REST style Web service. This web
service takes a target URL and either returns the content "as is" or tries to transform (by sponging)
to RDF. Thus, the proxy service can be used as a 'pipe' for RDF browsers to browse non-RDF sources.</para>
<para>When the rdf_mappers package is installed, Virtuoso reserves the path '/about/[id|data|rdf|html]/http/' for
Sponger Proxy URI Service. For example, if a Virtuoso installation on host example.com listens for HTTP
requests on port 8080 then client applications should use a 'service endpoint' string equal to
'http://example.com:8080/about/[id|data|rdf|html]/http/'. If the rdf_mappers package is not installed, then
the service uses the path '/proxy/rdf/'.</para>
<para>Note: The old Sponger Proxy URI Service pattern '/proxy/' is now deprecated.</para>
<para><emphasis>Example:</emphasis></para>
<para>The following URLs return information about musician John Cale, gleaned from the MusicBrainz
music metadatabase, rendered as RDF or HTML respectively. (The sponged data is available in the HTML
rendering through the foaf:primaryTopic property.)</para>
<itemizedlist mark="bullet">
<listitem>http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/artist/72c090b6-a68e-4cb9-b330-85278681a714.html</listitem>
<listitem>http://demo.openlinksw.com/about/html/http/musicbrainz.org/artist/72c090b6-a68e-4cb9-b330-85278681a714.html</listitem>
</itemizedlist>
<sect4 id="virtuosospongercartridwh"><title>What is a Cartridge?</title>
<para>The Sponger is comprised of cartridges which are themselves comprised of an entity extractor
and an ontology mapper. Entities extracted from non-RDF resources are used as the basis for generating
structured data by mapping them to a suitable ontology. A cartridge is invoked through its cartridge
hook, a Virtuoso/PL procedure entry point and binding to the cartridge's entity extractor and
ontology mapper.</para>
</sect4>
<sect4 id="virtuosospongercartridges"><title>Supported Non RDF Data Sources</title>
<itemizedlist>
<listitem>Standard Formats
<para>These Cartridges handle open formats: <emphasis>typically community-developed,
openly-documented, and freely-licensed data structures.</emphasis></para>
<table>
<tgroup cols="4">
<thead>
<row>
<entry>Cartridge</entry><entry>Sample URI</entry><entry>Resource Description</entry><entry>Linked Data Graph</entry>
</row>
</thead>
<tbody>
<row><entry>AB Meta </entry><entry> <ulink url="http://abmeta.org/album2.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/abmeta.org/album2.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://abmeta.org/album2.html">Data Explorer View</ulink> </entry></row>
<row><entry>APML </entry><entry> <ulink url="https://apml.engagd.com/apml/danielabarbosa.myopenid.com.apml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/https://apml.engagd.com/apml/danielabarbosa.myopenid.com.apml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=https://apml.engagd.com/apml/danielabarbosa.myopenid.com.apml">Data Explorer View</ulink> </entry></row>
<row><entry>ATOM </entry><entry> <ulink url="http://www.openlinksw.com/blog/~kidehen/gems/atom.xml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.openlinksw.com/blog/~kidehen/gems/atom.xml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.openlinksw.com/blog/~kidehen/gems/atom.xml">Data Explorer View</ulink> </entry></row>
<row><entry>DC </entry><entry> <ulink url="http://dublincore.org/2008/01/14/dcterms.rdf">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/dublincore.org/2008/01/14/dcterms.rdf">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://dublincore.org/2008/01/14/dcterms.rdf">Data Explorer View</ulink> </entry></row>
<row><entry>eRDF </entry><entry> <ulink url="http://www.w3.org/2001/sw/grddl-wg/doc29/hotel-data.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.w3.org/2001/sw/grddl-wg/doc29/hotel-data.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.w3.org/2001/sw/grddl-wg/doc29/hotel-data.html">Data Explorer View</ulink> </entry></row>
<row><entry>GRDDL </entry><entry> <ulink url="http://www.w3.org/2001/sw/grddl-wg/doc29/hotel-data.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.w3.org/2001/sw/grddl-wg/doc29/hotel-data.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.w3.org/2001/sw/grddl-wg/doc29/hotel-data.html">Data Explorer View</ulink> </entry></row>
<row><entry>hAudio </entry><entry> <ulink url="http://openmediaweb.org/index.php/2008/01/13/publishing-my-workout-music-in-haudio/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/openmediaweb.org/index.php/2008/01/13/publishing-my-workout-music-in-haudio/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://openmediaweb.org/index.php/2008/01/13/publishing-my-workout-music-in-haudio/">Data Explorer View</ulink> </entry></row>
<row><entry>hCalendar </entry><entry> <ulink url="http://www.maine.gov/portal/government/calendar.shtml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.maine.gov/portal/government/calendar.shtml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.maine.gov/portal/government/calendar.shtml">Data Explorer View</ulink> </entry></row>
<row><entry>hCard </entry><entry> <ulink url="http://www.lawyer-directory.net/lawyer/Grand-Rapids-Bar-Association-Grand-Rapids-law434032.htm">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.lawyer-directory.net/lawyer/Grand-Rapids-Bar-Association-Grand-Rapids-law434032.htm">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.lawyer-directory.net/lawyer/Grand-Rapids-Bar-Association-Grand-Rapids-law434032.htm">Data Explorer View</ulink> </entry></row>
<row><entry>hListing </entry><entry> <ulink url="http://sfbay.craigslist.org/nby/apa/1280124800.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/sfbay.craigslist.org/nby/apa/1280124800.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://sfbay.craigslist.org/nby/apa/1280124800.html">Data Explorer View</ulink> </entry></row>
<row><entry>hProduct </entry><entry> <ulink url="http://www.bestbuy.com/shop/cartman">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.bestbuy.com/shop/cartman">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.bestbuy.com/shop/cartman">Data Explorer View</ulink> </entry></row>
<row><entry>HR-XML </entry><entry> <ulink url="http://ns.hr-xml.org/2_5/HR-XML-2_5/SEP/ResumeExample.xml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/ns.hr-xml.org/2_5/HR-XML-2_5/SEP/ResumeExample.xml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://ns.hr-xml.org/2_5/HR-XML-2_5/SEP/ResumeExample.xml">Data Explorer View</ulink> </entry></row>
<row><entry>hResume </entry><entry> <ulink url="http://brad.hawidu.com/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/brad.hawidu.com/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://brad.hawidu.com/">Data Explorer View</ulink> </entry></row>
<row><entry>hReview </entry><entry> <ulink url="http://www.concertbuzz.net/genres/classic-rock/jethro-tull.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.concertbuzz.net/genres/classic-rock/jethro-tull.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.concertbuzz.net/genres/classic-rock/jethro-tull.html">Data Explorer View</ulink> </entry></row>
<row><entry>iCalendar </entry><entry> <ulink url="http://kidehen.idehen.net/DAV/home/kidehen/Public/LDP-Spring2008.ics">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/kidehen.idehen.net/DAV/home/kidehen/Public/LDP-Spring2008.ics">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://kidehen.idehen.net/DAV/home/kidehen/Public/LDP-Spring2008.ics">Data Explorer View</ulink> </entry></row>
<row><entry>Images </entry><entry> <ulink url="http://farm4.static.flickr.com/3067/2590298570_304a594899_t.jpg">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/farm4.static.flickr.com/3067/2590298570_304a594899_t.jpg">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://farm4.static.flickr.com/3067/2590298570_304a594899_t.jpg">Data Explorer View</ulink> </entry></row>
<row><entry>OO document </entry><entry> <ulink url="http://www.pitonyak.org/AndrewMacro.odt">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.pitonyak.org/AndrewMacro.odt">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.pitonyak.org/AndrewMacro.odt">Data Explorer View</ulink> </entry></row>
<row><entry>OPML </entry><entry> <ulink url="http://news.bbc.co.uk/rss/feeds.opml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/news.bbc.co.uk/rss/feeds.opml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://news.bbc.co.uk/rss/feeds.opml">Data Explorer View</ulink> </entry></row>
<row><entry>PPTX </entry><entry> <ulink url="http://download.microsoft.com/download/4/D/E/4DE0D83D-7845-4FD1-9A8E-12F532EC81BC/Keynote.pptx">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/download.microsoft.com/download/4/D/E/4DE0D83D-7845-4FD1-9A8E-12F532EC81BC/Keynote.pptx">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://download.microsoft.com/download/4/D/E/4DE0D83D-7845-4FD1-9A8E-12F532EC81BC/Keynote.pptx">Data Explorer View</ulink> </entry></row>
<row><entry>RDFa </entry><entry> <ulink url="http://virtuoso.openlinksw.com/presentations/Creating_Deploying_Exploiting_Linked_Data2/Creating_Deploying_Exploiting_Linked_Data2_TimBL_v3.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/virtuoso.openlinksw.com/presentations/Creating_Deploying_Exploiting_Linked_Data2/Creating_Deploying_Exploiting_Linked_Data2_TimBL_v3.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://virtuoso.openlinksw.com/presentations/Creating_Deploying_Exploiting_Linked_Data2/Creating_Deploying_Exploiting_Linked_Data2_TimBL_v3.html">Data Explorer View</ulink> </entry></row>
<row><entry>RSS </entry><entry> <ulink url="http://microformats.org/feed/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/microformats.org/feed/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://microformats.org/feed/">Data Explorer View</ulink> </entry></row>
<row><entry>Slidy </entry><entry> <ulink url="http://slideshow.rubyforge.org/microformats.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/slideshow.rubyforge.org/microformats.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://slideshow.rubyforge.org/microformats.html">Data Explorer View</ulink> </entry></row>
<row><entry>vCalendar </entry><entry> <ulink url="http://upcoming.org/event/130719/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/upcoming.org/event/130719/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://upcoming.org/event/130719/">Data Explorer View</ulink> </entry></row>
<row><entry>vCard </entry><entry> <ulink url="http://tech.yahoo.com/pr/apple-ipod-video-30gb-black-mp3-player/1992981873">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/tech.yahoo.com/pr/apple-ipod-video-30gb-black-mp3-player/1992981873">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://tech.yahoo.com/pr/apple-ipod-video-30gb-black-mp3-player/1992981873">Data Explorer View</ulink> </entry></row>
<row><entry>XBEL </entry><entry> <ulink url="http://xbel.sourceforge.net/bookmarks/xbel.xbel">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/xbel.sourceforge.net/bookmarks/xbel.xbel">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://xbel.sourceforge.net/bookmarks/xbel.xbel">Data Explorer View</ulink> </entry></row>
<row><entry>XBRL </entry><entry> <ulink url="http://www.sec.gov/Archives/edgar/data/51143/000110465908059468/ibm-20080429.xml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.sec.gov/Archives/edgar/data/51143/000110465908059468/ibm-20080429.xml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.sec.gov/Archives/edgar/data/51143/000110465908059468/ibm-20080429.xml">Data Explorer View</ulink> </entry></row>
<row><entry>XFN </entry><entry> <ulink url="http://www.molly.com/people.php">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.molly.com/people.php">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.molly.com/people.php">Data Explorer View</ulink> </entry></row>
<row><entry>XHTML </entry><entry> <ulink url="http://www.lespetitescases.net/semantique-et-xhtml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.lespetitescases.net/semantique-et-xhtml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.lespetitescases.net/semantique-et-xhtml">Data Explorer View</ulink> </entry></row>
<row><entry>XSLT </entry><entry> <ulink url="http://www.w3.org/2003/12/rdf-in-xhtml-xslts/complete-example.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.w3.org/2003/12/rdf-in-xhtml-xslts/complete-example.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.w3.org/2003/12/rdf-in-xhtml-xslts/complete-example.html">Data Explorer View</ulink> </entry></row>
</tbody>
</tgroup>
</table>
</listitem>
<listitem>Vendor-specific Web Services
<para>These Cartridges handle closed formats: typically proprietary, sometimes undocumented, possibly
licensed to no-one except the format originator. Sometimes data may not be parsed as desired or expected,
as many of these Cartridges have required reverse-engineering of the data format in question.</para>
<table>
<tgroup cols="4">
<thead>
<row>
<entry>Cartridge</entry><entry>Sample URI</entry><entry>Resource Description</entry><entry>Linked Data Graph</entry>
</row>
</thead>
<tbody>
<row><entry>Amazon </entry><entry> <ulink url="http://www.amazon.com/gp/product/0553383043">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.amazon.com/gp/product/0553383043">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.amazon.com/gp/product/0553383043">Data Explorer View</ulink> </entry></row>
<row><entry>Apple </entry><entry> <ulink url="http://www.apple.com/iphone/iphone-3gs/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.apple.com/iphone/iphone-3gs/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.apple.com/iphone/iphone-3gs/">Data Explorer View</ulink> </entry></row>
<row><entry>Bing </entry><entry> <ulink url="http://www.bing.com/community/members/livesearch/default.aspx">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.bing.com/community/members/livesearch/default.aspx">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.bing.com/community/members/livesearch/default.aspx">Data Explorer View</ulink> </entry></row>
<row><entry>Bugzillas </entry><entry> <ulink url="https://bugzilla.mozilla.org/show_bug.cgi?id=251714">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/https://bugzilla.mozilla.org/show_bug.cgi?id=251714">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=https://bugzilla.mozilla.org/show_bug.cgi?id=251714">Data Explorer View</ulink> </entry></row>
<row><entry>CrunchBase </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/rdf/http://www.crunchbase.com/company/google%23video_embeds-370">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/linkeddata.uriburner.com/about/rdf/http://www.crunchbase.com/company/google%23video_embeds-370">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://linkeddata.uriburner.com/about/rdf/http://www.crunchbase.com/company/google%23video_embeds-370">Data Explorer View</ulink> </entry></row>
<row><entry>Delicious </entry><entry> <ulink url="http://delicious.com/popular/blog">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/delicious.com/popular/blog">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://delicious.com/popular/blog">Data Explorer View</ulink> </entry></row>
<row><entry>Digg </entry><entry> <ulink url="http://digg.com/general_sciences/at_last-stem_cells_without_side_effects_">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/digg.com/general_sciences/at_last-stem_cells_without_side_effects_">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://digg.com/general_sciences/at_last-stem_cells_without_side_effects_">Data Explorer View</ulink> </entry></row>
<row><entry>Discogs </entry><entry> <ulink url="http://www.discogs.com/release/634302">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.discogs.com/release/634302">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.discogs.com/release/634302">Data Explorer View</ulink> </entry></row>
<row><entry>Disqus </entry><entry> <ulink url="http://blog.disqus.net/2008/08/25/reblog-comments-can-be-blog-posts/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/blog.disqus.net/2008/08/25/reblog-comments-can-be-blog-posts/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://blog.disqus.net/2008/08/25/reblog-comments-can-be-blog-posts/">Data Explorer View</ulink> </entry></row>
<row><entry>DOI </entry><entry> <ulink url="http://doi.ieeecomputersociety.org/10.1109/MIC.2008.16">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/doi.ieeecomputersociety.org/10.1109/MIC.2008.16">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://doi.ieeecomputersociety.org/10.1109/MIC.2008.16">Data Explorer View</ulink> </entry></row>
<row><entry>FaceBook </entry><entry> <ulink url="http://www.facebook.com/profile.php?id=841100003">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.facebook.com/profile.php?id=841100003">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.facebook.com/profile.php?id=841100003">Data Explorer View</ulink> </entry></row>
<row><entry>Flickr </entry><entry> <ulink url="http://farm1.static.flickr.com/212/496684670_7122c831ed.jpg">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/farm1.static.flickr.com/212/496684670_7122c831ed.jpg">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://farm1.static.flickr.com/212/496684670_7122c831ed.jpg">Data Explorer View</ulink> </entry></row>
<row><entry>Freebase </entry><entry> <ulink url="http://www.freebase.com/view/en/abraham_lincoln">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.freebase.com/view/en/abraham_lincoln">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.freebase.com/view/en/abraham_lincoln">Data Explorer View</ulink> </entry></row>
<row><entry>Geonames </entry><entry> <ulink url="http://ws.geonames.org/search?q=london&maxRows=10&type=rdf">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/ws.geonames.org/search?q=london&maxRows=10&type=rdf">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://ws.geonames.org/search?q=london&maxRows=10&type=rdf">Data Explorer View</ulink> </entry></row>
<row><entry>geoURL </entry><entry> <ulink url="http://geourl.org/near?p=wiki.worldflicks.org/saanen.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/geourl.org/near?p=wiki.worldflicks.org/saanen.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://geourl.org/near?p=wiki.worldflicks.org/saanen.html">Data Explorer View</ulink> </entry></row>
<row><entry>Get Satisfaction </entry><entry> <ulink url="http://getsatisfaction.com/mozilla/topics/ubiquity_mostly_fails_on_mac_ppc">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/getsatisfaction.com/mozilla/topics/ubiquity_mostly_fails_on_mac_ppc">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://getsatisfaction.com/mozilla/topics/ubiquity_mostly_fails_on_mac_ppc">Data Explorer View</ulink> </entry></row>
<row><entry>Google Social Graph </entry><entry> <ulink url="http://socialgraph.apis.google.com/lookup?q=http://example.com/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/socialgraph.apis.google.com/lookup?q=http://example.com/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://socialgraph.apis.google.com/lookup?q=http://example.com/">Data Explorer View</ulink> </entry></row>
<row><entry>GoogleBase </entry><entry> <ulink url="http://www.google.com/base/feeds/snippets?bq=%20%5bemployer:%20Hewlett-Packard%5d%20%20%5bjob%20type:full-time%5d">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.google.com/base/feeds/snippets?bq=%20%5bemployer:%20Hewlett-Packard%5d%20%20%5bjob%20type:full-time%5d">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.google.com/base/feeds/snippets?bq=%20%5bemployer:%20Hewlett-Packard%5d%20%20%5bjob%20type:full-time%5d">Data Explorer View</ulink> </entry></row>
<row><entry>Hoovers </entry><entry> <ulink url="http://www.hoovers.com/openlink/--ID__104304--/free-co-factsheet.xhtml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.hoovers.com/openlink/--ID__104304--/free-co-factsheet.xhtml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.hoovers.com/openlink/--ID__104304--/free-co-factsheet.xhtml">Data Explorer View</ulink> </entry></row>
<row><entry>ISBN </entry><entry> <ulink url="http://isbndb.com/d/person/berners_lee_tim.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/isbndb.com/d/person/berners_lee_tim.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://isbndb.com/d/person/berners_lee_tim.html">Data Explorer View</ulink> </entry></row>
<row><entry>LastFM </entry><entry> <ulink url="http://www.last.fm/music/+noredirect/Teddy+Pendegrass">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.last.fm/music/+noredirect/Teddy+Pendegrass">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.last.fm/music/+noredirect/Teddy+Pendegrass">Data Explorer View</ulink> </entry></row>
<row><entry>LibraryThing </entry><entry> <ulink url="http://www.librarything.com/work/1060">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.librarything.com/work/1060">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.librarything.com/work/1060">Data Explorer View</ulink> </entry></row>
<row><entry>LSID </entry><entry> <ulink url="http://lsid.tdwg.org/urn:lsid:ubio.org:namebank:11815">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/lsid.tdwg.org/urn:lsid:ubio.org:namebank:11815">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://lsid.tdwg.org/urn:lsid:ubio.org:namebank:11815">Data Explorer View</ulink> </entry></row>
<row><entry>Magnolia </entry><entry> <ulink url="http://www.magnoliaav.com/Products/Category/tabid/238/categoryId/117/Default.aspx">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.magnoliaav.com/Products/Category/tabid/238/categoryId/117/Default.aspx">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.magnoliaav.com/Products/Category/tabid/238/categoryId/117/Default.aspx">Data Explorer View</ulink> </entry></row>
<row><entry>Meetup </entry><entry> <ulink url="http://www.meetup.com/The-Cambridge-Semantic-Web-Meetup-Group/%23this">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.meetup.com/The-Cambridge-Semantic-Web-Meetup-Group/%23this">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.meetup.com/The-Cambridge-Semantic-Web-Meetup-Group/%23this">Data Explorer View</ulink> </entry></row>
<row><entry>MusicBrainz </entry><entry> <ulink url="http://musicbrainz.org/release/37e955d4-a53c-45aa-a812-1b23b88dbc13.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/musicbrainz.org/release/37e955d4-a53c-45aa-a812-1b23b88dbc13.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://musicbrainz.org/release/37e955d4-a53c-45aa-a812-1b23b88dbc13.html">Data Explorer View</ulink> </entry></row>
<row><entry>Ning </entry><entry> <ulink url="http://www.ning.com/main/popular?trend=professional">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.ning.com/main/popular?trend=professional">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.ning.com/main/popular?trend=professional">Data Explorer View</ulink> </entry></row>
<row><entry>OAI </entry><entry> <ulink url="http://news.cnet.com/IBM%2C-screensaver-to-tackle-smallpox/2100-1008_3-983374.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/news.cnet.com/IBM%2C-screensaver-to-tackle-smallpox/2100-1008_3-983374.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://news.cnet.com/IBM%2C-screensaver-to-tackle-smallpox/2100-1008_3-983374.html">Data Explorer View</ulink> </entry></row>
<row><entry>Open Social </entry><entry> <ulink url="http://socialgraph.apis.google.com/otherme?pretty=1&q=www.openlinksw.com/blog/~kidehen/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/socialgraph.apis.google.com/otherme?pretty=1&q=www.openlinksw.com/blog/~kidehen/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://socialgraph.apis.google.com/otherme?pretty=1&q=www.openlinksw.com/blog/~kidehen/">Data Explorer View</ulink> </entry></row>
<row><entry>OpenLibrary </entry><entry> <ulink url="http://openlibrary.org/b/OL7983950M">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/openlibrary.org/b/OL7983950M">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://openlibrary.org/b/OL7983950M">Data Explorer View</ulink> </entry></row>
<row><entry>OpenStreetMap </entry><entry> <ulink url="http://openstreetmap.org/?lat=57.6569&lon=11.8886&zoom=14&layers=B000FTF">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/openstreetmap.org/?lat=57.6569&lon=11.8886&zoom=14&layers=B000FTF">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://openstreetmap.org/?lat=57.6569&lon=11.8886&zoom=14&layers=B000FTF">Data Explorer View</ulink> </entry></row>
<row><entry>oReilly </entry><entry> <ulink url="http://oreilly.com/catalog/9780596523206/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/oreilly.com/catalog/9780596523206/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://oreilly.com/catalog/9780596523206/">Data Explorer View</ulink> </entry></row>
<row><entry>Picasa </entry><entry> <ulink url="http://picasaweb.google.com/quitetall/ZurichAtDawn#5339484766701840338">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/picasaweb.google.com/quitetall/ZurichAtDawn#5339484766701840338">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://picasaweb.google.com/quitetall/ZurichAtDawn#5339484766701840338">Data Explorer View</ulink> </entry></row>
<row><entry>PowerPoint </entry><entry> <ulink url="http://virtuoso.openlinksw.com/presentations/Solving_Real_Problems_Using_Linked_Data/Solving_Real_Problems_Using_Linked_Data.ppt">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/virtuoso.openlinksw.com/presentations/Solving_Real_Problems_Using_Linked_Data/Solving_Real_Problems_Using_Linked_Data.ppt">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://virtuoso.openlinksw.com/presentations/Solving_Real_Problems_Using_Linked_Data/Solving_Real_Problems_Using_Linked_Data.ppt">Data Explorer View</ulink> </entry></row>
<row><entry>Radio Pop </entry><entry> <ulink url="http://www.radiopop.co.uk/users/tristanf/friends.xml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.radiopop.co.uk/users/tristanf/friends.xml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.radiopop.co.uk/users/tristanf/friends.xml">Data Explorer View</ulink> </entry></row>
<row><entry>Rhapsody </entry><entry> <ulink url="http://mp3.rhapsody.com/playlistdetail?playlistId=ply.25288413">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/mp3.rhapsody.com/playlistdetail?playlistId=ply.25288413">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://mp3.rhapsody.com/playlistdetail?playlistId=ply.25288413">Data Explorer View</ulink> </entry></row>
<row><entry>SalesForce.com </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/rdf/https://na6.salesforce.com/0038000000ViF6k#this">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/linkeddata.uriburner.com/about/rdf/https://na6.salesforce.com/0038000000ViF6k#this">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://linkeddata.uriburner.com/about/rdf/https://na6.salesforce.com/0038000000ViF6k#this">Data Explorer View</ulink> </entry></row>
<row><entry>SlideShare </entry><entry> <ulink url="http://www.slideshare.net/rumito/rdf-views-of-sql-data-power-point-presentation-1-173180/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.slideshare.net/rumito/rdf-views-of-sql-data-power-point-presentation-1-173180/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.slideshare.net/rumito/rdf-views-of-sql-data-power-point-presentation-1-173180/">Data Explorer View</ulink> </entry></row>
<row><entry>SVG </entry><entry> <ulink url="http://www.schepers.cc/semweb/rdf-diagram.svg">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.schepers.cc/semweb/rdf-diagram.svg">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.schepers.cc/semweb/rdf-diagram.svg">Data Explorer View</ulink> </entry></row>
<row><entry>TWFY They Work For You </entry><entry> <ulink url="http://www.theyworkforyou.com/mp/diane_abbott/hackney_north_and_stoke_newington">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.theyworkforyou.com/mp/diane_abbott/hackney_north_and_stoke_newington">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.theyworkforyou.com/mp/diane_abbott/hackney_north_and_stoke_newington">Data Explorer View</ulink> </entry></row>
<row><entry>Web Resource CC (Licenses) </entry><entry> <ulink url="http://creativecommons.org/licenses/by-nc-nd/2.5/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/creativecommons.org/licenses/by-nc-nd/2.5/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://creativecommons.org/licenses/by-nc-nd/2.5/">Data Explorer View</ulink> </entry></row>
<row><entry>XBRL based SEC Filings </entry><entry> <ulink url="http://www.sec.gov/Archives/edgar/data/789019/000119312507259490/msft-20070930.xml">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.sec.gov/Archives/edgar/data/789019/000119312507259490/msft-20070930.xml">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.sec.gov/Archives/edgar/data/789019/000119312507259490/msft-20070930.xml">Data Explorer View</ulink> </entry></row>
<row><entry>xFolk </entry><entry> <ulink url="http://blogmarks.net/blog/?2005/06/07/33-blogsync-reloaded">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/blogmarks.net/blog/?2005/06/07/33-blogsync-reloaded">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://blogmarks.net/blog/?2005/06/07/33-blogsync-reloaded">Data Explorer View</ulink> </entry></row>
<row><entry>Yahoo! Finance </entry><entry> <ulink url="http://finance.yahoo.com/q?s=AAPL">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/finance.yahoo.com/q?s=AAPL">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://finance.yahoo.com/q?s=AAPL">Data Explorer View</ulink> </entry></row>
<row><entry>Yahoo! SearchMonkey </entry><entry> <ulink url="http://tech.groups.yahoo.com/group/ysearchboss/message/1983">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/tech.groups.yahoo.com/group/ysearchboss/message/1983">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://tech.groups.yahoo.com/group/ysearchboss/message/1983">Data Explorer View</ulink> </entry></row>
<row><entry>Yahoo! Traffic Data </entry><entry> <ulink url="http://local.yahooapis.com/MapsService/V1/trafficData?appid=Jz0wAU7V34Ff7gCzblxD.86qjGTEn._H3KA3PEajNE3xBMIbQtEZqIqHRh0G&street=701+First+Street&city=Sunnyvale&state=CA">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/local.yahooapis.com/MapsService/V1/trafficData?appid=Jz0wAU7V34Ff7gCzblxD.86qjGTEn._H3KA3PEajNE3xBMIbQtEZqIqHRh0G&street=701+First+Street&city=Sunnyvale&state=CA">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://local.yahooapis.com/MapsService/V1/trafficData?appid=Jz0wAU7V34Ff7gCzblxD.86qjGTEn._H3KA3PEajNE3xBMIbQtEZqIqHRh0G&street=701+First+Street&city=Sunnyvale&state=CA">Data Explorer View</ulink> </entry></row>
<row><entry>Yahoo! Weather </entry><entry> <ulink url="http://weather.yahooapis.com/forecastrss?p=94089">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/weather.yahooapis.com/forecastrss?p=94089">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://weather.yahooapis.com/forecastrss?p=94089">Data Explorer View</ulink> </entry></row>
<row><entry>Yelp </entry><entry> <ulink url="http://api.yelp.com/business_review_search?term=cream%20puffs&location=650%20Mission%20St%2ASan%20Francisco%2A%20CA&ywsid=XXXXXXXXXXXXXXXX">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/api.yelp.com/business_review_search?term=cream%20puffs&location=650%20Mission%20St%2ASan%20Francisco%2A%20CA&ywsid=XXXXXXXXXXXXXXXX">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://api.yelp.com/business_review_search?term=cream%20puffs&location=650%20Mission%20St%2ASan%20Francisco%2A%20CA&ywsid=XXXXXXXXXXXXXXXX">Data Explorer View</ulink> </entry></row>
<row><entry>Youtube </entry><entry> <ulink url="http://www.youtube.com/watch?v=6eGcsGPgUTw">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.youtube.com/watch?v=6eGcsGPgUTw">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.youtube.com/watch?v=6eGcsGPgUTw">Data Explorer View</ulink> </entry></row>
</tbody>
</tgroup>
</table>
</listitem>
<listitem>Meta Cartridges (delivering Lookups & Joins against other Linked Data Spaces)
<para>These Cartridges submit the Resource identified by the URI to third-party Web Services for processing.
Returned RDF supplements the RDF generated by other Cartridges, such as those in the preceding tables.
Locally generated RDF may also be submitted to the third-party services, instead of or in addition to
the original Resource itself.</para>
<table>
<tgroup cols="4">
<thead>
<row>
<entry>Cartridge</entry><entry>Sample URI</entry><entry>Resource Description</entry><entry>Linked Data Graph</entry>
</row>
</thead>
<tbody>
<row><entry>BBC </entry><entry> <ulink url="http://news.bbc.co.uk/1/hi/uk/7615539.stm">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http://www.hinducurrents.com/publisher/249/BBC+NEWS/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.hinducurrents.com/publisher/249/BBC+NEWS/">Data Explorer View</ulink> </entry></row>
<row><entry>CNET </entry><entry> <ulink url="http://shopper.cnet.com/multifunction-devices/canon-pixma-mp240/4014-3181_9-33200106.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.xomreviews.com/shopper.cnet.com">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.xomreviews.com/shopper.cnet.com">Data Explorer View</ulink> </entry></row>
<row><entry>DBpedia </entry><entry> <ulink url="http://dbpedia.org/page/TweetDeck">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.programmableweb.com/api/dbpedia">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.programmableweb.com/api/dbpedia">Data Explorer View</ulink> </entry></row>
<row><entry>eBay </entry><entry> <ulink url="http://shop.ebay.com/stores/__W0QQLHQ5fSellerWithStoreZ1QQ_nkwZtoys?_rdc=1">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/wordpress.xdroop.com/space/HotWheels/Buying+Hotwheels+On+eBay">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://wordpress.xdroop.com/space/HotWheels/Buying+Hotwheels+On+eBay">Data Explorer View</ulink> </entry></row>
<row><entry>FriendFeed </entry><entry> <ulink url="http://friendfeed.com/informationweek/0f212311/web-link-shrinkage-powers-spam-surge">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.informationweek.com/news/security/vulnerabilities/showArticle.jhtml?articleID=218401098">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.informationweek.com/news/security/vulnerabilities/showArticle.jhtml?articleID=218401098">Data Explorer View</ulink> </entry></row>
<row><entry>Get Glue </entry><entry> <ulink url="http://getglue.com/smartlinks">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.readwriteweb.com/archives/get_glue_on_your_iphone.php">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.readwriteweb.com/archives/get_glue_on_your_iphone.php">Data Explorer View</ulink> </entry></row>
<row><entry>LOD </entry><entry> <ulink url="http://lod.openlinksw.com/b3s/search.vsp?q=1">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/lod.openlinksw.com/b3s/search.vsp?q=1">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://lod.openlinksw.com/b3s/search.vsp?q=1">Data Explorer View</ulink> </entry></row>
<row><entry>New York Times </entry><entry> <ulink url="http://www.nytimes.com/2005/03/17/technology/circuits/17stat.html?ex=1268715600&en=6840507aca561cf8&ei=5090&partner=rssuserland">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/download.cnet.com/New-York-Times-Crosswords-Monthly-Subscription/3000-2111_4-10918973.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://download.cnet.com/New-York-Times-Crosswords-Monthly-Subscription/3000-2111_4-10918973.html">Data Explorer View</ulink> </entry></row>
<row><entry>OpenCalais </entry><entry> <ulink url="http://d.opencalais.com/er/company/ralg-tr1r/7cf71bb9-2969-35d3-8fa1-3723bdb5958c">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/news.cnet.com/8301-13505_3-9805771-16.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://news.cnet.com/8301-13505_3-9805771-16.html">Data Explorer View</ulink> </entry></row>
<row><entry>Technorati </entry><entry> <ulink url="http://support.technorati.com/support/siteguide/tags">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/download.cnet.com/Technorati-Tag/3000-12565_4-10658084.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://download.cnet.com/Technorati-Tag/3000-12565_4-10658084.html">Data Explorer View</ulink> </entry></row>
<row><entry>Twine </entry><entry> <ulink url="http://www.twine.com/item/11yg1gn9s-1cj/sweoig-taskforces-communityprojects-linkingopendata-esw-wiki">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/esw.w3.org/topic/SweoIG/TaskForces/CommunityProjects/LinkingOpenData/">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://esw.w3.org/topic/SweoIG/TaskForces/CommunityProjects/LinkingOpenData/">Data Explorer View</ulink> </entry></row>
<row><entry>Twitter </entry><entry> <ulink url="http://twitter.com/Techmeme/">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.techmeme.com/081001/p43">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.techmeme.com/081001/p43">Data Explorer View</ulink> </entry></row>
<row><entry>World Bank </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/web.worldbank.org/WBSITE/EXTERNAL/TOPICS/EXTEDUCATION/0,,contentMDK:20263110~menuPK:531742~pagePK:210058~piPK:210062~theSitePK:282386,00.html">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/www.lib.berkeley.edu/doemoff/govinfo/intl/gov_ibrd.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://www.lib.berkeley.edu/doemoff/govinfo/intl/gov_ibrd.html">Data Explorer View</ulink> </entry></row>
<row><entry>Zemanta </entry><entry> <ulink url="http://developer.zemanta.com/wiki/helloworld/ruby">example</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/about/html/http/kobesearch.cpan.org/htdocs/Net-Zemanta/Net/Zemanta/Suggest.pm.html">HTML Representation</ulink> </entry><entry> <ulink url="http://linkeddata.uriburner.com/ode/?uri=http://kobesearch.cpan.org/htdocs/Net-Zemanta/Net/Zemanta/Suggest.pm.html">Data Explorer View</ulink> </entry></row>
</tbody>
</tgroup>
</table>
</listitem>
</itemizedlist>
</sect4>
<sect4 id="virtuosospongercartridgetypes"><title>Types of Cartridges</title>
<para><emphasis>Basic</emphasis></para>
<para>Sponger cartridges are invoked as follows:</para>
<para>When the SPARQL processor dereferences a URI, it plays the role of an HTTP user agent (client)
that makes a content type specific request to an HTTP server via the HTTP request's Accept headers.
The following then occurs:</para>
<itemizedlist>
<listitem>If the content type returned is RDF then no further transformation is needed and the process
stops. For instance, when consuming an (X)HTML document with a GRDDL profile, the profile URI points to a
data provider that simply returns RDF instance data. </listitem>
<listitem>If the content type is not RDF (i.e. application/rdf+xml or text/rdf+n3 ), for instance
'text/plain', the Sponger looks in the Cartridge Registry iterating over every record for which the
RM_ENABLED flag is true, with the look-up sequence ordered on the RM_ID column values. For each record,
the processor tries matching the content type or URL against the RM_PATTERN value and, if there is
match, the function specified in RM_HOOK column is called. If the function doesn't exist, or signals
an error, the SPARQL processor looks at next record.
<itemizedlist>
<listitem>If the hook returns zero, the next cartridge is tried. (A cartridge function can return
zero if it believes a subsequent cartridge in the chain is capable of extracting more RDF data.)</listitem>
<listitem>If the result returned by the hook is negative, the Sponger is instructed that no
RDF was generated and the process stops.
<itemizedlist>
<listitem>If the hook result is positive, the Sponger is informed that structured data was
retrieved and the process stops. </listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</listitem>
<listitem>If none of the cartridges match the source data signature (content type or URL), the
ODS-Briefcase WebDAV metadata extractor and RDF generator is called.</listitem>
</itemizedlist>
<para><emphasis>Meta</emphasis></para>
<para>Virtuoso also supports another cartridge type - a 'meta-cartridge'. Meta-cartridges act as
post-processors in the cartridge pipeline, augmenting entity descriptions in an RDF graph with
additional information gleaned from 'lookup' data sources and web services.</para>
</sect4>
</sect3>
<sect3 id="virtuosospongercartridgesextractorusecases"><title>RDF Cartridges Use Cases</title>
<para>This section contains examples of Web resources which can be transformed by RDF Cartridges.
It also states where additional setup for given cartridges is needed i.e. keys account names etc.
</para>
<para><emphasis>Service based:</emphasis></para>
<itemizedlist>
<listitem>amazon
<programlisting><![CDATA[
needs: api key
example: http://www.amazon.com/gp/product/0553383043
]]></programlisting>
</listitem>
<listitem>ebay
<programlisting><![CDATA[
needs: account, api-key
example: http://cgi.ebay.com/RARE-DAY-IN-FAIRY-LAND-ELEPHANT-FOLIO-20-FULL-COLOR_W0QQitemZ140209597189QQihZ004QQcategoryZ29223QQssPageNameZWDVWQQrdZ1QQcmdZViewItem
]]></programlisting>
</listitem>
<listitem>flickr
needs: api-key
example: http://farm1.static.flickr.com/212/496684670_7122c831ed.jpg
<programlisting><![CDATA[
]]></programlisting>
</listitem>
<listitem>mbz
<programlisting><![CDATA[
example: http://musicbrainz.org/release/37e955d4-a53c-45aa-a812-1b23b88dbc13.html
]]></programlisting>
</listitem>
<listitem>mql (freebase)
<programlisting><![CDATA[
example: http://www.freebase.com/view/en/beta_ursae_majoris
]]></programlisting>
</listitem>
<listitem>facebook
<programlisting><![CDATA[
needs: api-key, secret, persistent-session-id
example: http://www.facebook.com/profile.php?id=841100003
]]></programlisting>
</listitem>
<listitem>yahoo-stock
<programlisting><![CDATA[
example: http://finance.yahoo.com/q?s=AAPL
]]></programlisting>
</listitem>
<listitem>yahoo-traffic
<programlisting><![CDATA[
example: http://local.yahooapis.com/MapsService/V1/trafficData?appid=YahooDemo&street=701+First+Street&city=Sunnyvale&state=CA
]]></programlisting>
</listitem>
<listitem>Bugzilla
<programlisting><![CDATA[
example: https://bugzilla.mozilla.org/show_bug.cgi?id=251714
]]></programlisting>
</listitem>
<listitem>SVG</listitem>
<listitem>OO document
<programlisting><![CDATA[
needs: unzip plugin
]]></programlisting>
</listitem>
<listitem>Wikipedia
<programlisting><![CDATA[
needs: php plugin & dbpedia extractor
example: http://wikipedia.org/wiki/London
]]></programlisting>
</listitem>
<listitem>Opencalais</listitem>
<listitem>iCalendar</listitem>
</itemizedlist>
<para><emphasis>GRDDL</emphasis></para>
<itemizedlist>
<listitem>Google Base (google)
<programlisting><![CDATA[
example: http://www.google.com/base/feeds/snippets/17891817243016304554
]]></programlisting>
</listitem>
<listitem>eRDF</listitem>
<listitem>RDFa</listitem>
<listitem>hCard</listitem>
<listitem>hCalendar</listitem>
<listitem>hReview</listitem>
<listitem>relLicense</listitem>
<listitem>XBRL</listitem>
<listitem>HR-XML</listitem>
<listitem>DC</listitem>
<listitem>geoURL</listitem>
<listitem>Ning</listitem>
<listitem>XFN</listitem>
<listitem>xFolk</listitem>
</itemizedlist>
<para><emphasis>URN handlers</emphasis></para>
<itemizedlist>
<listitem>LSID
<programlisting><![CDATA[
example: urn:lsid:ubio.org:namebank:12292
]]></programlisting>
</listitem>
<listitem>DOI
<programlisting><![CDATA[
needs: hslookup plugin, relevant html, pdf, xml etc. mappers enabled
example: doi:10.1038/35057062
]]></programlisting>
</listitem>
<listitem>OAI
<programlisting><![CDATA[
example: oai:dcmi.ischool.washington.edu:article/8
]]></programlisting>
</listitem>
</itemizedlist>
<sect4 id="virtuosospongerrdfmappers"><title>SPARQL IRI Dereferencing</title>
<para>The Virtuoso SPARQL engine (called for brevity just SPARQL bellow) supports IRI Dereferencing,
however it understands only RDF data, that is it can retrieve only files containing RDF/XML, turtle
or N3 serialized RDF data, if format is unknown it will try mapping with built-in WebDAV metadata
extractor. In order to extend this feature with dereferencing web or file resources which naturally
don't have RDF data (like PDF, JPEG files for example) is provided a special mechanism in SPARQL
engine. This mechanism is called RDF mappers for translation of non-RDF data files to RDF.</para>
<para>In order to instruct the SPARQL to call a RDF mapper it needs to be registered and it will
be called for a given URL or MIME type pattern. In other words, when unknown for SPARQL format is
received during URL dereferencing process, it will look into a special registry (a table) to match
either the MIME type or IRI using a regular expression, if match is found the mapper function will
be called.</para>
<sect5 id="virtuosospongerproxy"><title>Sponger Proxy service</title>
<para>Sponger functionality is also exposed via Virtuoso's "/proxy/rdf/" endpoint, as an in-built
REST style Web service available in any Virtuoso standard installation. This web service takes
a target URL and either returns the content "as is" or tries to transform (by sponging) to RDF.
Thus, the proxy service can be used as a 'pipe' for RDF browsers to browse non-RDF sources.
</para>
<para>For more information see <link linkend="rdfproxyservice">RDF Sponger Proxy service</link></para>
</sect5>
<sect5 id="virtuosospongercache"><title>Cache Invalidation</title>
<para>To clear cache on all values of HS_LOCAL_IRI of the SYS_HTTP_SPONGE table use:</para>
<programlisting><![CDATA[
SPARQL clear graph <A-Named-Graph>;
]]></programlisting>
</sect5>
</sect4>
</sect3>
<sect3 id="virtuosospongerfacetinstall">
<title>Virtuoso Facet Browser Installation and configuration</title>
<sect4 id="virtuosospongerfacetinstallprereq">
<title>Prerequisites</title>
<para>Requires Virtuoso 6.0 TP1 or higher for use.
</para>
</sect4>
<sect4 id="virtuosospongerfacetinstallpreinst">
<title>Pre Installation</title>
<para>If you have an existing Virtuoso 6.x installation, and your Quad Store has greater than
10K worth of triples, please perform the following steps:
</para>
<orderedlist>
<listitem>Run the following commands using the Virtuoso isql program before installing the Facet
Browser VAD:
<programlisting><![CDATA[
drop index RDF_QUAD_OPGS;
drop index RDF_QUAD_POGS;
drop index RDF_QUAD_GPOS;
drop index RDF_QUAD_OGPS;
checkpoint;
create table R2 (G iri_id_8, S iri_id_8, P iri_id_8, O any, primary key (S, P, O, G));
alter index R2 on R2 partition (S int (0hexffff00));
log_enable (2);
INSERT INTO R2 (G, S, P, O) select G, S, P, O FROM rdf_quad;
DROP TABLE RDF_QUAD;
ALTER TABLE r2 rename RDF_QUAD;
checkpoint;
create bitmap index RDF_QUAD_OPGS on RDF_QUAD (O, P, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_POGS on RDF_QUAD (P, O, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_GPOS on RDF_QUAD (G, P, O, S) partition (O varchar (-1, 0hexffff));
checkpoint;
]]></programlisting>
</listitem>
</orderedlist>
<para>Note this step may take sometime depending on how many triples are already in your Quad Store.
</para>
</sect4>
<sect4 id="virtuosospongerfacetinstallvadinst">
<title>VAD Package Installation</title>
<orderedlist>
<listitem>Download and install the <ulink url="http://download.openlinksw.com/packages/5.0/virtuoso/fct_dav.vad">Virtuoso Facet Browser VAD</ulink>
package using the Conductor System Admin - > Packages tab.
<figure id="fctinst1" float="1">
<title>Install the FCT package</title>
<graphic fileref="ui/fctinst1.png"/>
</figure>
</listitem>
<listitem>Grant <emphasis>select</emphasis> privileges on the <emphasis>RDF_QUAD</emphasis> table to the
<emphasis>SPARQL</emphasis> user:
<programlisting><![CDATA[
grant SELECT on DB.DBA.RDF_QUAD to "SPARQL";
]]></programlisting>
</listitem>
<listitem>An updated Virtuoso RDF Mappers VAD is required. Download and install the
<ulink url="http://download.openlinksw.com/packages/5.0/virtuoso/rdf_mappers_dav.vad">RDF Mappers VAD</ulink>
package using the Conductor System Admin - > Packages tab.
<figure id="fctinst2" float="1">
<title>Install the RDF Mappers package</title>
<graphic fileref="ui/fctinst2.png"/>
</figure>
</listitem>
<listitem>The HTML interface of the Faceted Browser Engine is exposed at: <emphasis>http://<cname>/fct</emphasis>,
where "cname" is the hostname:portno your Virtuoso instance is running on.
<figure id="fctinst3" float="1">
<title>FCT HTML interface</title>
<graphic fileref="ui/fctinst3.png"/>
</figure>
</listitem>
<listitem>The Facet Browser Engine exposes a REST API at the endpoint:
<emphasis>http://<cname>/fct/service</emphasis>.
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="virtuosospongerfacentuirestapi">Virtuoso APIs for Facet REST services</link></listitem>
<listitem><link linkend="rdfiridereferencingfacetws">Facets Web Service and Linked Data</link></listitem>
</itemizedlist>
</tip>
</listitem>
</orderedlist>
</sect4>
<sect4 id="virtuosospongerfacetinstallposinst">
<title>Post Installation</title>
<orderedlist>
<listitem>Build Full Text Indexes by running the following commands using the Virtuoso
<emphasis>isql</emphasis> program:
<programlisting><![CDATA[
RDF_OBJ_FT_RULE_ADD (null, null, 'All');
VT_INC_INDEX_DB_DBA_RDF_OBJ ();
]]></programlisting>
</listitem>
<listitem>Run the following procedure using the Virtuoso <emphasis>isql</emphasis> program to
populate label lookup tables periodically and activate the <emphasis>Label</emphasis> text box of the
<emphasis>URI Lookup(by Label)</emphasis> tab:
<programlisting><![CDATA[
urilbl_ac_init_db()
]]></programlisting>
</listitem>
<listitem>Run the following procedure using the Virtuoso <emphasis>isql</emphasis> program to calculate the IRI ranks.
Note this should be run periodically as the data grows to re-rank the IRIs.
<programlisting><![CDATA[
s_rank()
]]></programlisting>
</listitem>
<listitem>Sponge some data to load some RDF triples in the quad store. This can easily be done using
the Virtuoso <emphasis>description.vsp</emphasis> page which provides a hypertext description of RDF Linked Data, by describing
the following page for example (or one of your choice):
<programlisting><![CDATA[
http://cname/about/html/http/news.cnet.com
]]></programlisting>
<figure id="fctinst4" float="1">
<title>Sponge data</title>
<graphic fileref="ui/fctinst4.png"/>
</figure>
</listitem>
<listitem>Use the Facet Browser Search and Find User Interface to search for information on "CNET"
<figure id="fctinst5" float="1">
<title>Facet Browser Search</title>
<graphic fileref="ui/fctinst5.png"/>
</figure>
</listitem>
<listitem>Results of the following form should be returned for the data sponged.
<figure id="fctinst6" float="1">
<title>Facet Browser Search Results</title>
<graphic fileref="ui/fctinst6.png"/>
</figure>
</listitem>
<listitem>Click "Types" link shown at the right vertical Navigation</listitem>
<listitem>Results of the classes/properties should be returned:
<figure id="fctinst7" float="1">
<title>Results of the classes/properties</title>
<graphic fileref="ui/fctinst7.png"/>
</figure>
</listitem>
<listitem>To exclude a type unhatch the checkbox associated with the type:
<figure id="fctinst8" float="1">
<title>Exclude Type(s)</title>
<graphic fileref="ui/fctinst8.png"/>
</figure>
</listitem>
<listitem>Click the Type URI link</listitem>
<listitem>Results of excluding the Type(s) should be shown:
<figure id="fctinst9" float="1">
<title>Results of Excluded Type(s)</title>
<graphic fileref="ui/fctinst9.png"/>
</figure>
</listitem>
<listitem>The Facet Browser Web service endpoint can also be queried to obtain the same results:
<programlisting><![CDATA[
$ more cnet.xml
<?xml version="1.0"?>
<query xmlns="http://openlinksw.com/services/facets/1.0" inference="" same-as="">
<text>CNET</text>
<view type="text" limit="20" offset=""/>
</query>
$ curl -H "Content-Type: text/xml" -d @cnet.xml http://cname/fct/service
<fct:facets xmlns:fct="http://openlinksw.com/services/facets/1.0/">
<fct:sparql> SELECT ?s1 as ?c1, (bif:search_excerpt (bif:vector ('CNET'), ?o1)) as ?c2, ?sc, ?rank WHERE {{{ SELECT ?s1, (?sc * 3e-1) as ?sc, ?o1, (sql:rnk_scale (<LONG::IRI_RANK> (?s1))) as ?rank WHERE { ?s1 ?s1textp ?o1 . ?o1 bif:contains '"CNET"' option (score ?sc) . } ORDER BY DESC (?sc * 3e-1 + sql:rnk_scale (<LONG::IRI_RANK> (?s1))) LIMIT 20 OFFSET 0 }}}</fct:sparql>
<fct:time>16</fct:time>
<fct:complete>yes</fct:complete>
<fct:timeout>0</fct:timeout>
<fct:db-activity> 131R rnd 36R seq 0P disk 0B / 0 messages</fct:db-activity>
<fct:result type="text">
<fct:row>
<fct:column datatype="trank">4.5</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.com">http://news.com</fct:column>
<fct:column>Technology News - CNET News</fct:column>
<fct:column><span class="srch_xerpt"><b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">4.5</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com/2547-1_3-0-20.xml">http://news.cnet.com/2547-1_3-0-20.xml</fct:column>
<fct:column>CNET News.com</fct:column>
<fct:column><span class="srch_xerpt"><b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">4.5</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com">http://news.cnet.com</fct:column>
<fct:column>Technology News - CNET News</fct:column>
<fct:column><span class="srch_xerpt"><b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3.9</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.com">http://news.com</fct:column>
<fct:column>Technology News - CNET News</fct:column>
<fct:column><span class="srch_xerpt">Technology News <b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3.9</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com">http://news.cnet.com</fct:column>
<fct:column>Technology News - CNET News</fct:column>
<fct:column><span class="srch_xerpt">Technology News <b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.com">http://news.com</fct:column>
<fct:column>Technology News - CNET News</fct:column>
<fct:column><span class="srch_xerpt">Tech news and business reports by <b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com/2547-1_3-0-20.xml">http://news.cnet.com/2547-1_3-0-20.xml</fct:column>
<fct:column>CNET News.com</fct:column>
<fct:column><span class="srch_xerpt">Tech news and business reports by <b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com">http://news.cnet.com</fct:column>
<fct:column>Technology News - CNET News</fct:column>
<fct:column><span class="srch_xerpt">Tech news and business reports by <b>CNET</b> News.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.com#6">http://news.com#6</fct:column>
<fct:column>There's an electric car in your future</fct:column>
<fct:column><span class="srch_xerpt">... <b>CNET</b> Car Tech posts photos of electric cars expected to come out by 2011.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com/2547-1_3-0-20.xml#9">http://news.cnet.com/2547-1_3-0-20.xml#9</fct:column>
<fct:column>There's an electric car in your future</fct:column>
<fct:column><span class="srch_xerpt">... <b>CNET</b> Car Tech posts photos of electric cars expected to come out by 2011.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com#9">http://news.cnet.com#9</fct:column>
<fct:column>There's an electric car in your future</fct:column>
<fct:column><span class="srch_xerpt">... <b>CNET</b> Car Tech posts photos of electric cars expected to come out by 2011.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.com#6">http://news.com#6</fct:column>
<fct:column>There's an electric car in your future</fct:column>
<fct:column><span class="srch_xerpt">... <b>CNET</b> Car Tech posts photos of electric cars expected to come out by 2011.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com/2547-1_3-0-20.xml#9">http://news.cnet.com/2547-1_3-0-20.xml#9</fct:column>
<fct:column>There's an electric car in your future</fct:column>
<fct:column><span class="srch_xerpt">... <b>CNET</b> Car Tech posts photos of electric cars expected to come out by 2011.</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="trank">3</fct:column>
<fct:column datatype="erank">5.881291583872905e-014</fct:column>
<fct:column datatype="url" shortform="http://news.cnet.com#9">http://news.cnet.com#9</fct:column>
<fct:column>There's an electric car in your future</fct:column>
<fct:column><span class="srch_xerpt">... <b>CNET</b> Car Tech posts photos of electric cars expected to come out by 2011.</span></fct:column>
</fct:row>
</fct:result>
</fct:facets>
]]></programlisting>
</listitem>
<listitem>In the <emphasis>Label</emphasis> text box of the <emphasis>URI Lookup (by Label)</emphasis>
tab enter the name of a rdfs label to be <emphasis>Describe</emphasis>'d:
<figure id="fctinst10" float="1">
<title>Query Facet Browser Web service endpoint</title>
<graphic fileref="ui/fctinst10.png"/>
</figure>
</listitem>
<listitem>Select a URI from the list of available Labels to obtain a description of the URI:
<figure id="fctinst11" float="1">
<title>Select a URI from the list of available Labels</title>
<graphic fileref="ui/fctinst11.png"/>
</figure>
</listitem>
<listitem>In the <emphasis>URI</emphasis> text box of the <emphasis>URI Lookup</emphasis> tab enter
the name URI to be <emphasis>Describe</emphasis>'d:
<figure id="fctinst12" float="1">
<title>Enter URI</title>
<graphic fileref="ui/fctinst12.png"/>
</figure>
</listitem>
<listitem>Select a URI from the list of available Labels to obtain a description of the URI:
<figure id="fctinst13" float="1">
<title>Obtain a description of the URI</title>
<graphic fileref="ui/fctinst13.png"/>
</figure>
</listitem>
<listitem>If data is loaded into the quad store via DML functions (TTLP, RDF_LOAD_RDFXML etc.) the
following procedure needs to run from <emphasis>isql</emphasis> to build the free text indexes required each time:
<programlisting><![CDATA[
VT_INC_INDEX_DB_DBA_RDF_OBJ ()
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
<sect4 id="virtuosospongerfaceusagest">
<title>Usage Statistics</title>
<orderedlist>
<listitem>Use the Faceted Browser Search and Find User Interface to search for information on "Michael Jackson":
<figure id="VirtFacetUsage1" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage1.png"/>
</figure>
</listitem>
<listitem>Results of the following form should be returned for the data sponged:
<figure id="VirtFacetUsage2" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage2.png"/>
</figure>
</listitem>
<listitem>Click the "Types" link under "Navigation"
</listitem>
<listitem>Results about "Michael Jackson" as Type/Label/Count list should be returned.
</listitem>
<listitem>Click a type link, for ex.:
<programlisting><![CDATA[
dbpedia-owl:Artist
]]></programlisting>
<figure id="VirtFacetUsage8" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage8.png"/>
</figure>
</listitem>
<listitem>Should be shown type results and:
<programlisting><![CDATA[
Displaying types of e1 where:
e1 has any property whose value contains "Michael Jackson".
e1 is a dbpedia-owl:Artist . Drop
]]></programlisting>
<figure id="VirtFacetUsage9" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage9.png"/>
</figure>
</listitem>
<listitem>Click the "Show values" link under "Navigation"
</listitem>
<listitem>Results should be shown for "Michael Jackson" as values and text summaries associated with pattern:
<programlisting><![CDATA[
Displaying values and text summaries associated with pattern e1 where:
e1 has any property whose value contains "Michael Jackson".
e1 is a dbpedia-owl:Artist . Drop
]]></programlisting>
</listitem>
<listitem>Click the link:
<programlisting><![CDATA[
dbpedia:Michael_Jackson
]]></programlisting>
<figure id="VirtFacetUsage10" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage10.png"/>
</figure>
</listitem>
<listitem>Results about "Michael Jackson" as property/value list should be returned:
<figure id="VirtFacetUsage3" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage3.png"/>
</figure>
</listitem>
<listitem>Click the "Usage Statistics" link under "Actions" shown right of the list.
</listitem>
<listitem>Results of usage statistics for "Michael Jackson" grouped in 4 tabs should be shown:
<orderedlist>
<listitem>Referenced by Graphs: shows how many times the URI is found as subject in the relevant graph(s):
<programlisting><![CDATA[
SPARQL
SELECT ?g count (*)
where
{
graph ?g { <URI> ?p ?o }
}
group by ?g
order by desc 2
limit 20
]]></programlisting>
<figure id="VirtFacetUsage4" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage4.png"/>
</figure>
</listitem>
<listitem>Source Graphs: shows how many times the URI is found as object in the relevant graph(s):
<programlisting><![CDATA[
SPARQL
SELECT ?g count (*)
where
{
graph ?g { ?s ?p <URI> }
}
group by ?g
order by desc 2
limit 20
]]></programlisting>
<figure id="VirtFacetUsage5" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage5.png"/>
</figure>
</listitem>
<listitem>Direct co-references: shows results as subject and calculated rank, based on running transitive closure over owl:sameAs of the URI in subject or object:
<programlisting><![CDATA[
SPARQL
SELECT ?syn ( sql:rnk_scale (<LONG::IRI_RANK> (?syn)))
where
{
{ SELECT ?s ?syn
where
{
{?syn owl:sameAs ?s } union {?s owl:sameAs ?syn}
}
}
option (transitive, t_distinct, t_min (0), T_in (?s), t_out (?syn)) . filter (!isliteral (?syn) && ?s = <URI> )
}
order by desc 2
limit 20
]]></programlisting>
<figure id="VirtFacetUsage6" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage6.png"/>
</figure>
</listitem>
<listitem>Indirect co-references: shows expanded results for objects concur with the URI by IFP:
<programlisting><![CDATA[
SPARQL
SELECT distinct ?syn ?p ?o (sql:rnk_scale (<LONG::IRI_RANK> (?syn)))
where
{ <URI> ?p ?o . filter (0 != (<LONG::bif:rdf_is_sub> ("b3sifp", ?p, lod:ifp_like, 3))) .
?syn ?p ?o .
}
order by desc 4
limit 20
]]></programlisting>
<figure id="VirtFacetUsage7" float="1">
<title>Usage Statistics</title>
<graphic fileref="ui/VirtFacetUsage7.png"/>
</figure>
</listitem>
</orderedlist>
</listitem>
</orderedlist>
</sect4>
<sect4 id="virtuosospongerfacetexample"><title>Examples</title>
<para><emphasis>Example for Use Faceted Navigation to Explore Virtuoso hosted Linked Data</emphasis></para>
<para>The following example demonstrates a simple scenario of tracking Kingsley Idehen's conversations $
across the Web, using the Virtuoso Faceted Browser hosted on URIBurner.</para>
<orderedlist>
<listitem>Go to http://uriburner.com/fct/
<figure id="fct1" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct1.png"/>
</figure>
</listitem>
<listitem>Enter a free text search pattern (for example, "Kingsley Idehen"), and click Search
<figure id="fct2" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct2.png"/>
</figure>
</listitem>
<listitem>Your initial query results page will display a list of literal value snippets from property
values associated with the query text pattern
<figure id="fct3" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct3.png"/>
</figure>
</listitem>
<listitem>Using the Navigation section on the right, click on "Types", which alters the contents
of the query results area by presenting CURIE based hyperlinks for each of the Entity Types associated
with Property values that contains the query text pattern
<figure id="fct4" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct4.png"/>
</figure>
</listitem>
<listitem>Click on the "foaf:Person" link to narrow the result set down to Entities of this Type,
un-hatch the checkbox beside this link for Negation (filtering out) based on this Entity Type
<figure id="fct5" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct5.png"/>
</figure>
</listitem>
<listitem>You can filter further, by switching (pivoting) to the a Property based view, by returning
to the Navigation section and then clicking on "Properties" or "Referencing Properties" links; in either
case, you have further filtering of based on the combination of Properties and Entities where Entities
in the result-set contain values matching the query text pattern
<figure id="fct6" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct6.png"/>
</figure>
</listitem>
<listitem>From the list of Property Types, click on the "foaf:interest" link to filter further,
based on the values of this property
<figure id="fct7" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct7.png"/>
</figure>
</listitem>
<listitem>From the list of "foaf:interest" Values, click on "dbpedia:Linked_Data", which filters
the result-set further to display reveal Entity Identifier Links (Generic HTTP URIs) and Labels for
each "foaf:Person" associated with the property "foaf:interest", in the URIBurner data space. At
the time of writing guide, there is only one Entity of Type: foaf:person, and the Generic HTTP URI
for this Entity is: http:///www.openlinksw.com/dataspace/person/kidehen@openlinksw.com#this.
<figure id="fct8" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct8.png"/>
</figure>
</listitem>
<listitem>Click on one of the HTTP URIs in the filtered results-set to obtain a detailed structured
description of a given Entity. Each listed Property is a Link; thus, each Property is a link to other
structured Entity descriptions
<figure id="fct9" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct9.png"/>
</figure>
</listitem>
<listitem>Click on "Usage Statistics" link to get a summary view of this Linked Data Space,
"Reference" and "Source" graphs are akin to saying "Table X" and "Table Y" where each table
is the container of Records re. RDBMS or Worksheet re. Spreadsheet.:
<figure id="fct10" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct10.png"/>
</figure>
<figure id="fct11" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct11.png"/>
</figure>
</listitem>
<listitem>"Direct" and "In-Direct" co-references show other references (Identifiers) that relate
associated with Kingsley Idehen (like saying: here are his other names or his know by this name in
this other place)
<figure id="fct12" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct12.png"/>
</figure>
<figure id="fct13" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct13.png"/>
</figure>
</listitem>
<listitem>Click on "Settings" check "owl:sameAs" and it sets a context mode for the session
(meaning: a set of rules to take place)
<figure id="fct14" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct14.png"/>
</figure>
</listitem>
<listitem>Go back to the "Direct Co-reference" tab
<figure id="fct15" float="1">
<title>Faceted Navigation Example</title>
<graphic fileref="ui/fct15.png"/>
</figure>
</listitem>
<listitem>As result each link will unveil a union (combination) of all the the data associated
with all Kingsley Idehen's other Identifiers (other Names in other places), i.e., they all show the
same data.</listitem>
</orderedlist>
</sect4>
</sect3>
<sect3 id="virtuosospongerfacent">
<title>Virtuoso Facets Web Service</title>
<para>The Virtuoso Facets web service is a general purpose RDF query facility for facet based browsing.
It takes an XML description of the view desired and generates the reply as an XML tree containing the
requested data. The user agent or a local web page can use XSLT for rendering this for the end user.
The selection of facets and values is represented as an XML tree. The rationale for this is the fact
that such a representation is easier to process in an application than the SPARQL source text or a
parse tree of SPARQL and more compactly captures the specific subset of SPARQL needed for faceted
browsing. The web service returns the SPARQL source text also, thus this can serve as a basis for
and-crafted queries.</para>
<para>The top element of the tree is <query>, it must be in namespace
"http://openlinksw.com/services/facets/1.0/".</para>
<para>This has the following attributes:</para>
<itemizedlist mark="bullet">
<listitem>graph="graph_iri" - default is search in all graphs but system defaults may override this</listitem>
<listitem>timeout="no_of_msec" - default is no timeout, but system defaults may override this</listitem>
<listitem>inference="name" where name is a name of an inference context declared with rdfs_rule_set.</listitem>
<listitem>same-as="boolean" - If "boolean" is "yes", then owl:sameAs links will be considered in the query evaluation.</listitem>
</itemizedlist>
<para>The result is a tree of the form:</para>
<programlisting><![CDATA[
<facets xmlns="http://openlinksw.com/services/facets/1.0/">
<result><row><column datatype="..." shortform="..." xml:lang="..">...</column></row></result>
<time>msecs</time>
<complete>yes or no</complete>
<db-activity>resource use string</db-activity>
<sparql>sparql statement text</sparql>
</facets>
]]></programlisting>
<para>By convention, the first column is the subject selected by the view element, typically a URI, the second a label of the URI
and the third, if present, is either a count or a search summary.</para>
<para>The first column's text child is the text form of the value. The column element has the following attributes
qualifying this further:</para>
<itemizedlist mark="bullet">
<listitem>datatype - The xsd type of the value. If this is a URI, the datatype is "uri" </listitem>
<listitem>shortform - If the value is a URI, this is an abbreviated form where known namespaces are replaced with
their prefixes and very long URI's are truncated preserving start and end. </listitem>
<listitem>xml:lang - if the value is a language tagged string, this is the language</listitem>
</itemizedlist>
<para>The query has the top level element <query>. The child elements of this represent conditions
pertaining to a single subject. A join is expressed with the property or property-of element. This has
in turn children which state conditions on a property of the first subject. property and property-of
elements can be nested to an arbitrary depth and many can occur inside one containing element. In this way,
tree-shaped structures of joins can be expressed.</para>
<para>Expressing more complex relationships, such as intermediate grouping, subqueries, arithmetic or
such requires writing the query in SPARQL. The XML format is a shorthand for easy automatic composition
of queries needed for showing facets, not a replacement for SPARQL.</para>
<para>A facet query contains a single view element. This specifies which subject of the joined
subjects is shown. Its attributes specify the manner of viewing, e.g. list of distinct values, distinct
values with occurrence counts, properties or classes of the selected subjects etc.</para>
<para>The top query element or any property or property-of element can have the following types of children:</para>
<programlisting><![CDATA[
<text property="iri">text pattern</text>
]]></programlisting>
<para>The subject has an O that matches the text pattern. If property is given, the text pattern must
occur in a value of this property. If not specified, any property will do. The value "none" for property
is the same as not specifying a property. This is restricted to occurring directly under the top level
query element.</para>
<programlisting><![CDATA[
<class iri="iri" inference="ctx_name" />
]]></programlisting>
<para>The S must be an instance of this class. If inference is specified then option (input:inference
"ctx_name" is added and applies to this pattern alone.</para>
<programlisting><![CDATA[
<property iri="iri" same_as="yes" inference="ctx_name">]]></programlisting>
<para>The child elements of this are conditions that apply to the value of this property of the S that
is in scope in the enclosing <query> or <property> element. If same_as is present, then
option (input:same-as "yes") is added to the triple pattern which specifies this property. If inference
is present, then option (input:inference "ctx_name") is added to the triple pattern for the property.</para>
<programlisting><![CDATA[
<property-of iri="iri" same_as="yes" inference="ctx_name" >
]]></programlisting>
<para>The child elements of this are conditions that apply to an S which has property "iri" whose object
is the S in scope in the enclosing <query> or <property> element. The options are otherwise
the same as with property.</para>
<programlisting><![CDATA[
<value datatype="type" xml:lang="lng" op="= | < | > | >= | <=">value </value>
]]></programlisting>
<para>When this occurs inside <property> or <property-of> this means that the property in
scope has the specified relation to the value. type and language can be used for XML typed or language
tagged literals. The "uri" type means that the value is a qualified name of a URI. If this occurs
directly under the <query> element, this means that the query starts with a fixed subject.
If this is so, then there must be property or propertyof elements or the view element must specify
properties or classes, list is not allowed as a view type. This is so because the query must have
at least one triple pattern.</para>
<programlisting><![CDATA[
<view type="view" limit="n" offset="n" >
]]></programlisting>
<para>This may occur once inside a <query> element but may occur either at top level or inside
property or property-of elements. This specifies what which subject is presented in the result set.</para>
<para>The type can be:</para>
<itemizedlist mark="bullet">
<listitem>"properties"
<programlisting><![CDATA[
SPARQL
SELECT ?p count (*) { ?this_s ?p ?any_o ...}
GROUP BY ?p
ORDER BY DESC 2
LIMIT l OFFSET 0
]]></programlisting>
</listitem>
<listitem>"properties-in"
<programlisting><![CDATA[
SPARQL
SELECT ?p count (*) { ?any_s ?p ?this_s ... }
GROUP BY ?p
ORDER BY DESC 2
LIMIT L OFFSET 0
]]></programlisting>
</listitem>
<listitem>"classes"
<programlisting><![CDATA[
SPARQL
SELECT ?c count (*)
WHERE { ?xx a ?c ... }
GROUP BY ?c
ORDER BY DESC 2
LIMIT l OFFSET 0
]]></programlisting>
</listitem>
<listitem>"text"
<programlisting><![CDATA[
SPARQL
SELECT DISTINCT ?s (bif:search_excerpt (sql:search_terms (""pattern"), ?o)) ...
LIMIT l OFFSET 0
]]></programlisting>
</listitem>
<listitem>"list"
<programlisting><![CDATA[
SPARQL
SELECT DISTINCT ?s long::sql:fct_label (?s) ...
LIMIT l OFFSET 0
]]></programlisting>
</listitem>
<listitem></listitem>
<listitem>"list-count"
<programlisting><![CDATA[
SPARQL
SELECT ?s COUNT (*) ....
GROUP BY ?s
ORDER BY DESC 2
]]></programlisting>
</listitem>
<listitem>"alphabet"
<programlisting><![CDATA[
SPARQL
SELECT (sql:subseq (?s, 0, 1)) count (*) ...
GROUP BY (sql:subseq (?s, 0, 1))
ORDER BY 1
]]></programlisting>
</listitem>
<listitem>"geo"
<programlisting><![CDATA[
SPARQL
SELECT DISTINCT ?lat ?long ?s
WHERE ?s geo:lat ?lat . ?s geo:long ?long . ... }
]]></programlisting>
</listitem>
<listitem>"years"
<programlisting><![CDATA[
SPARQL
SELECT sql::year (?s) count (*) ...
GROUP BY (bif:year (?s))
ORDER BY 1
OFFSET 0 LIMIT l
]]></programlisting>
</listitem>
<listitem>"months"
<programlisting><![CDATA[
SPARQL
SELECT sql::round_month (?s) count (*) ...
GROUP BY (sql:round_month (?s))
ORDER BY 1 OFFSET 0 LIMIT l
]]></programlisting>
</listitem>
<listitem>"weeks"
<programlisting><![CDATA[
SPARQL
SELECT sql::round_week (?s) COUNT (*) ...
GROUP BY (sql:round_week (?s))
ORDER BY 1 OFFSET 0 LIMIT l
]]></programlisting>
</listitem>
<listitem>"describe"
<programlisting><![CDATA[
SPARQL describe ?s ... OFFSET 0 LIMIT l
]]></programlisting>
</listitem>
</itemizedlist>
<sect4 id="virtuosospongerfacentcust">
<title>Customizing</title>
<para>The following types of customization will be generally useful:</para>
<itemizedlist mark="bullet">
<listitem>Resource accounting and limitations, managing access and login</listitem>
<listitem>Localization, choice of labels shown with class/property/instance URI's</listitem>
<listitem>Adding types of views, for example timelines, map or business graphics </listitem>
<listitem>Controlling navigation, for example choosing what type of view is initially presented when opening a given property.</listitem>
<listitem>Page layout, captions, help texts, etc.</listitem>
</itemizedlist>
<para>The source code is divided in two SQL files and a number of XSLT sheets. The file facet.sql has the code for the web service. The
facet_view.sql file contains the procedures for the sample HTML interface.</para>
</sect4>
<sect4 id="virtuosospongerfacentexamples">
<title>Examples</title>
<para>Note: in all examples the default namespace xmlns="http://openlinksw.com/services/facets/1.0/" is omitted for brevity.</para>
<para>For people called Mike:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<view type="text"/>
</query>
]]></programlisting>
<para>To open the list of people who Mike knows:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<view type="properties"/>
</query>
]]></programlisting>
<para>To show the list of subjects Mike knows:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<view type="list" />
</property>
</query>
]]></programlisting>
<para>To show the properties of people Mike knows:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<view type="properties" />
</property>
</query>
]]></programlisting>
<para>To show the names:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<view type="list" />
</property>
</property>
</query>
]]></programlisting>
<para>To specify one named Joe:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
<view type="properties" />
</property>
</query>
]]></programlisting>
<para>This lists the properties of the friends of Mike that are called Joe.</para>
<para>To show the Mikes that know a Joe, one would change the shown variable in the navigation and get:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
</property>
<view type="text" />
</query>
]]></programlisting>
<para>This would be the search summaries of subjects with Mike in some field that know a subject with name Joe.</para>
<para>Now to specify that Mike must be a member of a discussion board:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
</property>
<view type="property-in" />
</query>
]]></programlisting>
<para>This lists the properties of triples whom object is Mike. Pick sioc:member_of</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
</property>
<property-of iri="sioc:member_of>
<view type="list" />
</property-of>
</query>
]]></programlisting>
<para>This would show things where Mike is a member. To specify that the thing must be a forum:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
</property>
<property-of iri="sioc:member_of>
<view type="classes" />
</property-of>
</query>
]]></programlisting>
<para>This shows classes of things where Mike is a member Clicking on sioc:Forum gives:</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
</property>
<property-of iri="sioc:member_of>
<class iri="sioc:Forum" />
<view type="classes"/>
</property-of>
</query>
]]></programlisting>
<para>The view stays with classes, but now scoped
to the classes of things where Mike is a member that are instances of sioc:Forum.</para>
<para>To go look at the list of Mikes with the added
restriction, click the shown variable in the navigation and set it to s1.</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
</property>
<property-of iri="sioc:member_of>
<class iri="sioc:Forum" />
</property-of>
<view type="list"/>
</query>
]]></programlisting>
<para>To say that Joe must also have a geekCode, One clicks the shown variable and sets it to s2 and the view to properties.</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
<view type="properties"/>
</property>
<property-of iri="sioc:member_of>
<class iri="sioc:Forum" />
</property-of>
</query>
]]></programlisting>
<para>Pick geekCode</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
<property iri="geekCode">
<view type="list"/>
</property>
</property>
<property-of iri="sioc:member_of>
<class iri="sioc:Forum" />
</property-of>
</query>
]]></programlisting>
<para>We specify no restriction on the geekCode. Click the shown variable to take the focus back to Mike.</para>
<programlisting><![CDATA[
<query>
<text>Mike</text>
<property iri="foaf:knows>
<property iri="foaf:name>
<value>Joe</value>
</property>
<property iri="geekCode"></property>
</property>
<property-of iri="sioc:member_of>
<class iri="sioc:Forum" />
</property-of>
<view type="text"/>
</query>
]]></programlisting>
</sect4>
<sect4 id="virtuosospongerfacentui">
<title>WebService Interface</title>
<sect5 id="virtuosospongerfacentuirest">
<title>REST interface</title>
<para>The Virtuoso Facets web service provide following REST interface:</para>
<para>Service description:</para>
<itemizedlist mark="bullet">
<listitem>Endpoint: http://<cname>/fct/service for ex. http://lod.openlinksw.com/fct/service </listitem>
<listitem>HTTP method: POST</listitem>
<listitem>Content-Type: MUST be 'text/xml'</listitem>
<listitem>The entity body must be XML document with top element 'query' as described above.</listitem>
<listitem>The request response namespace MUST be "http://openlinksw.com/services/facets/1.0"</listitem>
</itemizedlist>
<para>Error conditions:</para>
<para>The all error conditions are reported via 'Error explanation'</para>
<para>Files:</para>
<para>The facet_svc.sql contains web service code and virtual directory mapping, and it uses
fct_req.xsl & fct_resp.xsl as request & response filters.</para>
<para>Example:</para>
<para>Using CURL program</para>
<programlisting><![CDATA[
curl -H "Content-Type: text/xml" -d @post.xml http://lod.openlinksw.com/fct/service
]]></programlisting>
<para>Where 'post.xml' document contains query document:</para>
<programlisting><![CDATA[
<?xml version="1.0"?>
<query xmlns="http://openlinksw.com/services/facets/1.0" inference="" same-as="">
<text> Seattle Mariners traveled all the way to Japan to watch</text>
<view type="text" limit="20" offset=""/>
</query>
]]></programlisting>
<para>Produces following response:</para>
<programlisting><![CDATA[
<fct:facets xmlns:fct="http://openlinksw.com/services/facets/1.0/">
<fct:sparql> SELECT distinct ?s1 as ?c1, (bif:search_excerpt (bif:vector ('THE', 'MARINERS', 'WAY', 'SEATTLE', 'WATCH', 'ALL', 'TO', 'JAPAN', 'TRAVELED'), ?o1)) as ?c2 WHERE { ?s1 ?s1textp ?o1 . FILTER (bif:contains (?o1, '(THE AND MARINERS AND WAY AND SEATTLE AND WATCH AND ALL AND TO AND JAPAN AND TRAVELED)')) . } LIMIT 20 OFFSET 0 </fct:sparql>
<fct:time>116</fct:time>
<fct:complete>yes</fct:complete>
<fct:db-activity> 134R rnd 9.488KR seq 0P disk 8.966MB / 602 messages</fct:db-activity>
<fct:result>
<fct:row>
<fct:column datatype="url" shortform="http://bobdupuy.mlbl...ld_baseball__6.html">http://bobdupuy.mlblogs.com/bobdupuy/2006/03/world_baseball__6.html></fct:column>
<fct:column />
<fct:column><span class="srch_xerpt">... While Chuck Armstrong president of <b>the</b> <b>Seattle</b> <b>Mariners</b> <b>traveled</b> <b>all</b> <b>the</b> <b>way</b> <b>to</b> <b>Japan</b> <b>to</b> <b>watch</b> Ichiro... for <b>the</b> advancing <b>Japan</b> team last week <b>the</b> star from <b>the</b> <b>Seattle</b> roster so far in Round 1 has without a doubt... leading <b>the</b> Dominican <b>to</b> its...</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="url" shortform="http://bobdupuy.mlbl...ld_baseball__6.html">http://bobdupuy.mlblogs.com/bobdupuy/2006/03/world_baseball__6.html></fct:column>
<fct:column />
<fct:column><span class="srch_xerpt">Orlando While Chuck Armstrong president of <b>the</b> <b>Seattle</b> <b>Mariners</b> <b>traveled</b> <b>all</b> <b>the</b> <b>way</b> <b>to</b> <b>Japan</b> <b>to</b> <b>watch</b>... perform for <b>the</b> advancing <b>Japan</b> team last week <b>the</b> star from <b>the</b> <b>Seattle</b> roster so far in Round 1 has without...</span></fct:column>
</fct:row>
</fct:result>
</fct:facets>
]]></programlisting>
</sect5>
<sect5 id="virtuosospongerfacentuirestapi">
<title>Virtuoso APIs for Facet REST services</title>
<para>The Virtuoso APIs for FCT REST services are Virtuoso Stored Procedures that enable faceted browsing
over Linked Data hosted in the RDF Quad Store. This also includes Linked Data that is progressively
added to the Quad Store via URI de-referencing.
</para>
<para>They enable the use Virtuoso's VSP/VSPX technology to produce (X)HTML-based Linked Data explorer
pages that are endowed with high-performance (in-process) faceted browsing capability.
</para>
<para>You can use this API with Virtuoso SQL calls that provide data to your VSP/VSPX, ASP.NET, PHP,
etc., -based interfaces using ODBC, JDBC, ADO.NET, or XMLA connectivity (SPASQL) to Virtuoso.
</para>
<sect6 id="virtuosospongerfacentuirestapidef">
<title>API Definition</title>
<programlisting><![CDATA[
CREATE PROCEDURE
fct_exec
(
IN tree ANY ,
IN timeout INT
)
{
DECLARE start_time,
view3,
inx,
n_rows INT ;
DECLARE sqls,
msg,
qr,
qr2,
act,
query VARCHAR ;
DECLARE md,
res,
results,
more ANY ;
DECLARE tmp ANY ;
DECLARE offs,
lim INT ;
SET result_timeout = _min
(
timeout,
ATOI
(
registry_get ('fct_timeout_max')
)
)
;
offs := xpath_eval ('//query/view/@offset', tree);
lim := xpath_eval ('//query/view/@limit', tree);
-- db_activity ();
results := vector (null, null, null);
more := vector ();
IF
(
xpath_eval
(
'//query[@view3="yes"]//view[@type="text"]',
tree
)
IS NOT NULL
)
{
more := VECTOR ('classes', 'properties');
}
sqls := '00000';
qr := fct_query
(
xpath_eval ('//query', tree, 1)
)
;
query := qr;
-- dbg_obj_print (qr);
qr2 := fct_xml_wrap (tree, qr);
start_time := msec_time ();
dbg_printf('query: %s', qr2);
EXEC
(
qr2,
sqls,
msg,
vector (),
0,
md,
res
)
;
n_rows := row_count ();
act := db_activity ();
SET result_timeout = 0;
IF (
sqls <> '00000'
AND
sqls <> 'S1TAT'
)
SIGNAL (sqls, msg);
IF (
NOT ISARRAY (res)
OR
0 = length (res)
OR
NOT ISARRAY (res[0])
OR
0 = length (res[0])
)
results[0] := xtree_doc ('<result/>');
ELSE
results[0] := res[0][0];
inx := 1;
FOREACH (VARCHAR tp IN more) DO
{
tree := XMLUpdate (
tree,
'/query/view/@type',
tp,
'/query/view/@limit',
'40',
'/query/view/@offset',
'0'
)
;
qr := fct_query (xpath_eval ('//query', tree, 1));
qr2 := fct_xml_wrap (tree, qr);
sqls := '00000';
SET result_timeout = _min (
timeout,
ATOI
(
registry_get ('fct_timeout_max')
)
)
;
EXEC (
qr2,
sqls,
msg,
vector (),
0,
md,
res
);
n_rows := row_count ();
act := db_activity ();
SET result_timeout = 0;
IF ( sqls <> '00000'
AND
sqls <> 'S1TAT'
)
SIGNAL (sqls, msg);
IF (
ISARRAY (res)
AND
LENGTH (res)
AND
ISARRAY (res[0])
AND
LENGTH (res[0])
)
{
tmp := res[0][0];
tmp := XMLUpdate (tmp, '/result/@type', tp);
results[inx] := tmp;
}
inx := inx + 1;
}
res := XMLELEMENT
(
"facets",
XMLELEMENT
( "sparql", query ),
XMLELEMENT
( "time", msec_time () - start_time ),
XMLELEMENT
(
"complete",
CASE WHEN sqls = 'S1TAT'
THEN 'no'
ELSE 'yes'
END
),
XMLELEMENT
(
"timeout",
_min
(
timeout * 2,
ATOI
(
registry_get
( 'fct_timeout_max' )
)
)
),
XMLELEMENT
("db-activity", act),
XMLELEMENT
("processed", n_rows),
XMLELEMENT
(
"view",
XMLATTRIBUTES
(
offs AS "offset",
lim AS "limit"
)
),
results[0],
results[1],
results[2]
);
---- for debugging:
--string_to_file ('ret.xml', serialize_to_UTF8_xml (res), -2);
-- dbg_obj_print (res);
RETURN res;
}
;
]]></programlisting>
</sect6>
<sect6 id="virtuosospongerfacentuirestapiexmp">
<title>Example</title>
<para>
The following example shows how to use the fct_exec APi in vsp page to perform a "text" search for the
word "Mike" assuming this exists in your Virtuoso RDF store (if not amend the query in the fct_example.vsp
code sample below to search for text known to exist).
</para>
<orderedlist>
<listitem>The service can be used in the following sample fct_example.vsp:
<programlisting><![CDATA[
<?vsp
declare txt, reply, tree any;
declare timeout int;
tree := xtree_doc ('
<query>
<text>Mike</text>
<view type="text"/>
</query>
');
timeout := 3000;
reply := fct_exec (tree, timeout);
txt := string_output ();
http_value (xslt ('virt://WS.WS.SYS_DAV_RES.RES_FULL_PATH.RES_CONTENT:/DAV/fct_example.xsl',
reply,
vector ()),
null, txt);
http (txt);
?>
]]></programlisting>
</listitem>
<listitem>The xsl:
<programlisting><![CDATA[
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-1"/>
<xsl:variable name="rowcnt" select="count(/facets/result/row)"/>
<xsl:template match="facets">
<div id="res">
<xsl:if test="/facets/complete = 'yes' and /facets/processed = 0 and $rowcnt = 0">
<div class="empty_result">
Nothing found.
</div>
</xsl:if>
<xsl:for-each select="/facets/result">
<xsl:call-template name="render-result"/>
</xsl:for-each>
</div>
<!-- #res -->
</xsl:template>
<xsl:template name="render-result">
<table class="result" border="1">
<thead>
<tr>
<th>Entity</th>
<th>Title</th>
<th>Text excerpt</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="row">
<tr>
<td class="rnk">
<xsl:for-each select="column[@datatype='trank' or @datatype='erank']">
<xsl:choose>
<xsl:when test="./@datatype='trank'">Text Rank:</xsl:when>
<xsl:when test="./@datatype='erank'">Entity Rank:</xsl:when>
</xsl:choose>
<xsl:value-of select="."/>
<br/>
</xsl:for-each>
</td>
<xsl:for-each select="column">
<xsl:choose>
<xsl:when test="'url' = ./@datatype">
<td>
<a>
<xsl:attribute name="href">http://lod.openlinksw.com/describe/?url=<xsl:value-of select="urlify (.)"/></xsl:attribute>
<xsl:attribute name="title"><xsl:value-of select="."/></xsl:attribute>
<xsl:choose>
<xsl:when test="'' != ./@shortform">
<xsl:value-of select="./@shortform"/>
</xsl:when>
<xsl:when test="'erank' = ./@datatype or 'trank' = ./@datatype">rank</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</a>
</td>
</xsl:when>
<xsl:when test="'erank' = ./@datatype or 'trank' = ./@datatype"/>
<xsl:when test="'srch_xerpt' = ./span/@class">
<td>
<xsl:value-of select="."/>
</td>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:for-each>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
]]></programlisting>
</listitem>
<listitem>The result of executing the fct_example.vsp should be:
<figure id="fcapiex1" float="1">
<title>Facet API Example</title>
<graphic fileref="ui/fcapiex1.png"/>
</figure>
</listitem>
</orderedlist>
</sect6>
</sect5>
<sect5 id="virtuosospongerfacentuirest">
<title>SOAP interface</title>
<para>The facet web service is also available via SOAP protocol.</para>
<para>The request message contains single element 'query' with syntax explained earlier. Also the
SOAPAction HTTP header should be '#query' . After successful evaluation of the query, the service
will return a SOAP envelope containing in the Body element single 'facets' element described above.</para>
<para>Example:</para>
<para>This example shows execution of same command as in example for REST interface here it using SOAP:</para>
<para>Request message:</para>
<programlisting><![CDATA[
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<query xmlns="http://openlinksw.com/services/facets/1.0/" inference="" same-as="">
<text>Seattle Mariners traveled all the way to Japan to watch</text>
<view type="text" limit="20" offset="0"/>
</query>
</SOAP:Body>
</SOAP:Envelope>
]]></programlisting>
<para>Response message:</para>
<programlisting><![CDATA[
<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body>
<fct:facets xmlns:fct="http://openlinksw.com/services/facets/1.0/">
<fct:sparql>SELECT distinct ?s1 as ?c1, (bif:search_excerpt (bif:vector ('THE', 'MARINERS', 'WAY', 'SEATTLE', 'WATCH', 'ALL', 'TO', 'JAPAN', 'TRAVELED'), ?o1)) as ?c2 where { ?s1 ?s1textp ?o1 . filter (bif:contains (?o1, '(THE AND MARINERS AND WAY AND SEATTLE AND WATCH AND ALL AND TO AND JAPAN AND TRAVELED)')) . } LIMIT 20 OFFSET 0</fct:sparql>
<fct:time>114</fct:time>
<fct:complete>yes</fct:complete>
<fct:db-activity> 134R rnd 9.488KR seq 0P disk 8.966MB / 602 messages</fct:db-activity>
<fct:result>
<fct:row>
<fct:column datatype="url" shortform="http://bobdupuy.mlbl...ld_baseball__6.html">http://bobdupuy.mlblogs.com/bobdupuy/2006/03/world_baseball__6.html</fct:column>
<fct:column/>
<fct:column><span class="srch_xerpt">... While Chuck Armstrong president of <b>the</b> <b>Seattle</b> <b>Mariners</b> <b>traveled</b> <b>all</b> <b>the</b> <b>way</b> <b>to</b> <b>Japan</b> <b>to</b> <b>watch</b> Ichiro... for <b>the</b> advancing <b>Japan</b> team last week <b>the</b> star from <b>the</b> <b>Seattle</b> roster so far in Round 1 has without a doubt... leading <b>the</b> Dominican <b>to</b> its...</span></fct:column>
</fct:row>
<fct:row>
<fct:column datatype="url" shortform="http://bobdupuy.mlbl...ld_baseball__6.html">http://bobdupuy.mlblogs.com/bobdupuy/2006/03/world_baseball__6.html</fct:column>
<fct:column/>
<fct:column><span class="srch_xerpt">Orlando While Chuck Armstrong president of <b>the</b> <b>Seattle</b> <b>Mariners</b> <b>traveled</b> <b>all</b> <b>the</b> <b>way</b> <b>to</b> <b>Japan</b> <b>to</b> <b>watch</b>... perform for <b>the</b> advancing <b>Japan</b> team last week <b>the</b> star from <b>the</b> <b>Seattle</b> roster so far in Round 1 has without...</span></fct:column>
</fct:row>
</fct:result>
</fct:facets>
</SOAP:Body>
</SOAP:Envelope>
]]></programlisting>
</sect5>
</sect4>
</sect3>
</sect2>
<sect2 id="rdfenterpriseandintegration">
<title>Enterprise Data Access & Integration</title>
<sect3 id="rdfviewsenterprbsm">
<title>BSBM to RDF</title>
<programlisting><![CDATA[
use DB;
CREATE TABLE DB.DBA.ProductFeature (
nr integer primary key,
label varchar(100) not null,
comment varchar(1500) not null,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.ProductFeature to public
;
CREATE TABLE DB.DBA.ProductType (
nr integer primary key,
label varchar(100) not null,
comment varchar(1500) not null,
parent integer,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.ProductType to public
;
CREATE TABLE DB.DBA.Producer (
nr integer primary key,
label varchar(100) not null,
comment varchar(1500) not null,
homepage varchar(100) not null,
country char(2) not null,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.Producer to public
;
create index producer_homepage on DB.DBA.Producer (homepage)
;
CREATE TABLE DB.DBA.Product (
nr integer primary key,
label varchar(100) not null,
comment varchar not null,
producer integer not null,
propertyNum1 integer,
propertyNum2 integer,
propertyNum3 integer,
propertyNum4 integer,
propertyNum5 integer,
propertyNum6 integer,
propertyTex1 varchar(200),
propertyTex2 varchar(200),
propertyTex3 varchar(200),
propertyTex4 varchar(200),
propertyTex5 varchar(200),
propertyTex6 varchar(200),
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.Product to public
;
create index product_lbl on DB.DBA.Product (label)
;
create unique index product_producer_nr on DB.DBA.Product (producer, nr)
;
create index product_pn1 on DB.DBA.Product (propertyNum1)
;
create index product_pn2 on DB.DBA.Product (propertyNum2)
;
create index product_pn3 on DB.DBA.Product (propertyNum3)
;
create text index on DB.DBA.Product (label) with key nr
;
CREATE TABLE DB.DBA.ProductTypeProduct (
product integer not null,
productType integer not null,
PRIMARY KEY (product, productType)
)
;
grant SELECT on DB.DBA.ProductTypeProduct to public
;
create index ptype_inv on DB.DBA.ProductTypeProduct (productType, product)
;
CREATE TABLE DB.DBA.ProductFeatureProduct (
product integer not null,
productFeature integer not null,
PRIMARY KEY (product, productFeature)
)
;
grant SELECT on DB.DBA.ProductFeatureProduct to public
;
create index pfeature_inv on DB.DBA.ProductFeatureProduct (productFeature, product)
;
CREATE TABLE DB.DBA.Vendor (
nr integer primary key,
label varchar(100) not null,
comment varchar not null,
homepage varchar(100) not null,
country char(2) not null,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.Vendor to public
;
create index vendor_country on DB.DBA.Vendor (country)
;
create index vendor_homepage on DB.DBA.Vendor (homepage)
;
CREATE TABLE DB.DBA.Offer (
nr integer primary key,
product integer not null,
producer integer,
vendor integer not null,
price double precision not null,
validFrom date not null,
validTo date not null,
deliveryDays integer not null,
offerWebpage varchar(100) not null,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.Offer to public
;
create index offer_product on DB.DBA.Offer (product, deliveryDays)
;
create unique index offer_producer_product on DB.DBA.Offer (producer, product, nr)
;
create index offer_validto on DB.DBA.Offer (validTo)
;
create index offer_vendor_product on DB.DBA.Offer (vendor, product)
;
create index offer_webpage on DB.DBA.Offer (offerWebpage)
;
CREATE TABLE DB.DBA.Person (
nr integer primary key,
name varchar(30) not null,
mbox_sha1sum char(40) not null,
country char(2) not null,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.Person to public
;
CREATE TABLE DB.DBA.Review (
nr integer primary key,
product integer not null,
producer integer,
person integer not null,
reviewDate date not null,
title varchar(200) not null,
text long varchar not null,
textlang char(2) not null,
rating1 integer,
rating2 integer,
rating3 integer,
rating4 integer,
publisher integer not null,
publishDate date not null
)
;
grant SELECT on DB.DBA.Review to public
;
create unique index review_product on DB.DBA.Review (product, producer, nr)
;
create unique index review_producer_product on DB.DBA.Review (producer, product, nr)
;
create bitmap index review_textlang on DB.DBA.Review (textlang)
;
DB.DBA.XML_SET_NS_DECL ('foaf', 'http://xmlns.com/foaf/0.1/', 2)
;
DB.DBA.XML_SET_NS_DECL ('dc', 'http://purl.org/dc/elements/1.1/', 2)
;
DB.DBA.XML_SET_NS_DECL ('xsd', 'http://www.w3.org/2001/XMLSchema-datatypes/', 2)
;
DB.DBA.XML_SET_NS_DECL ('rev', 'http://purl.org/stuff/rev#', 2)
;
DB.DBA.XML_SET_NS_DECL ('bsbm', 'http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/vocabulary/', 2)
;
DB.DBA.XML_SET_NS_DECL ('bsbm-inst', 'http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/', 2)
;
SPARQL drop quad map bsbm:SingleGraphView
;
SPARQL create iri class bsbm:ProductFeature-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductFeature%d" (in nr integer not null)
;
SPARQL create iri class bsbm:ProductType-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductType%d" (in nr integer not null)
;
SPARQL create iri class bsbm:Producer-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromProducer%d/Producer%d" (in nr_ integer not null, in nr integer not null)
;
SPARQL create iri class bsbm:Product-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromProducer%d/Product%d" (in producer integer not null, in nr integer not null)
;
SPARQL create iri class bsbm:Vendor-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromVendor%d/Vendor%d" (in nr_ integer not null, in nr integer not null)
;
SPARQL create iri class bsbm:Offer-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromVendor%d/Offer%d" (in vendor integer not null, in nr integer not null)
;
SPARQL create iri class bsbm:StdInst-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/StandardizationInstitution%d" (in publisher integer not null)
;
SPARQL create iri class bsbm:Person-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromRatingSite%d/Person%d" (in publisher integer not null, in nr integer not null)
;
SPARQL create iri class bsbm:Review-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromRatingSite%d/Review%d" (in site integer, in nr integer not null)
;
SPARQL create iri class bsbm:ISO3166-country-iri "http://downlode.org/rdf/iso-3166/countries#%s" (in code varchar not null)
;
SPARQL create iri class bsbm:homepage-iri "%s" (in homepage varchar not null) option (returns "http://%s")
;
SPARQL create iri class bsbm:RatingSite-iri "http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/dataFromRatingSite%d/RatingSite%d" (in nr_ integer not null, in nr integer not null)
;
SPARQL
alter quad storage virtrdf:DefaultQuadStorage
FROM DB.DBA.ProductFeature as pfeature
FROM DB.DBA.ProductType as ptype
FROM DB.DBA.Producer as producer
FROM DB.DBA.Product as product text literal product.label
FROM DB.DBA.ProductTypeProduct as ptypeproduct
FROM DB.DBA.ProductFeatureProduct as pfeatureproduct
FROM DB.DBA.Vendor as vendor
FROM DB.DBA.Offer as offer
FROM DB.DBA.Person as person
FROM DB.DBA.Review as review
where (^{product.}^.nr = ^{ptypeproduct.}^.product)
where (^{product.}^.nr = ^{pfeatureproduct.}^.product)
{
create bsbm:SingleGraphView as graph <BSBM> option (exclusive)
{
bsbm:Product-iri (product.producer, product.nr)
a bsbm:Product ;
rdfs:label product.label ;
rdfs:comment product.comment ;
bsbm:producer bsbm:Producer-iri (product.producer, product.producer) ;
bsbm:productPropertyTextual1 product.propertyTex1 ;
bsbm:productPropertyTextual2 product.propertyTex2 ;
bsbm:productPropertyTextual3 product.propertyTex3 ;
bsbm:productPropertyTextual4 product.propertyTex4 ;
bsbm:productPropertyTextual5 product.propertyTex5 ;
bsbm:productPropertyTextual6 product.propertyTex6 ;
bsbm:productPropertyNumeric1 product.propertyNum1 ;
bsbm:productPropertyNumeric2 product.propertyNum2 ;
bsbm:productPropertyNumeric3 product.propertyNum3 ;
bsbm:productPropertyNumeric4 product.propertyNum4 ;
bsbm:productPropertyNumeric5 product.propertyNum5 ;
bsbm:productPropertyNumeric6 product.propertyNum6 ;
rdf:type bsbm:ProductType-iri (ptypeproduct.productType) ;
bsbm:productFeature bsbm:ProductFeature-iri (pfeatureproduct.productFeature) ;
dc:publisher bsbm:Producer-iri (product.publisher, product.publisher) ;
dc:date product.publishDate .
bsbm:ProductType-iri (ptype.nr)
a bsbm:ProductType ;
rdfs:label ptype.label ;
rdfs:comment ptype.comment ;
rdfs:subClassOf bsbm:ProductType-iri (ptype.parent) ;
dc:publisher bsbm:StdInst-iri (ptype.publisher) ;
dc:date ptype.publishDate .
bsbm:ProductFeature-iri (pfeature.nr)
a bsbm:ProductFeature ;
rdfs:label pfeature.label ;
rdfs:comment pfeature.comment ;
dc:publisher bsbm:StdInst-iri (pfeature.publisher) ;
dc:date pfeature.publishDate .
bsbm:Producer-iri (producer.nr, producer.nr)
a bsbm:Producer ;
rdfs:label producer.label ;
rdfs:comment producer.comment ;
foaf:homepage bsbm:homepage-iri (producer.homepage) ;
bsbm:country bsbm:ISO3166-country-iri (producer.country) ;
dc:publisher bsbm:Producer-iri (producer.nr, producer.nr) ;
dc:date producer.publishDate .
bsbm:Vendor-iri (vendor.nr, vendor.nr)
a bsbm:Vendor ;
rdfs:label vendor.label ;
rdfs:comment vendor.comment ;
foaf:homepage bsbm:homepage-iri (vendor.homepage) ;
bsbm:country bsbm:ISO3166-country-iri (vendor.country) ;
dc:publisher bsbm:Vendor-iri (vendor.publisher, vendor.publisher) ;
dc:date vendor.publishDate .
bsbm:Offer-iri (offer.vendor, offer.nr)
a bsbm:Offer ;
bsbm:product bsbm:Product-iri (offer.producer, offer.product) ;
bsbm:vendor bsbm:Vendor-iri (offer.vendor, offer.vendor) ;
bsbm:vendor bsbm:Vendor-iri (offer.vendor, offer.vendor) ;
bsbm:price offer.price ;
bsbm:validFrom offer.validFrom ;
bsbm:validTo offer.validTo ;
bsbm:deliveryDays offer.deliveryDays ;
bsbm:offerWebpage bsbm:homepage-iri (offer.offerWebpage) ;
dc:publisher bsbm:Vendor-iri (offer.publisher, offer.publisher) ;
dc:date offer.publishDate .
bsbm:Person-iri (person.publisher, person.nr)
a foaf:Person ;
foaf:name person.name ;
foaf:mbox_sha1sum person.mbox_sha1sum ;
bsbm:country bsbm:ISO3166-country-iri (person.country) ;
dc:publisher bsbm:RatingSite-iri (person.publisher, person.publisher) ;
dc:date person.publishDate .
bsbm:Review-iri (review.publisher, review.nr)
a rev:Review ;
bsbm:reviewFor bsbm:Product-iri (review.producer, review.product) ;
bsbm:producer bsbm:Producer-iri (review.producer, review.producer) ;
rev:reviewer bsbm:Person-iri (review.publisher, review.person) ;
bsbm:reviewDate review.reviewDate ;
dc:title review.title ;
rev:text review.text lang review.textlang ;
bsbm:rating1 review.rating1 ;
bsbm:rating2 review.rating2 ;
bsbm:rating3 review.rating3 ;
bsbm:rating4 review.rating4 ;
dc:publisher bsbm:RatingSite-iri (review.publisher, review.publisher) ;
dc:date review.publishDate .
}
}
;
]]></programlisting>
</sect3>
</sect2>
<sect2 id="rdfviews"><title>RDF Views over RDBMS Data Source</title>
<para>
RDF Views map relational data into RDF and allow customizing RDF representation of locally stored RDF data.
To let SPARQL clients access relational data as well as physical RDF graphs in a single query, we introduce a declarative Meta Schema Language for mapping SQL Data to RDF Ontologies.
As a result, all types of clients can efficiently access all data stored on the server.
The mapping functionality dynamically generates RDF Data Sets for popular ontologies such as SIOC, SKOS, FOAF, and ATOM/OWL without disruption to the existing database infrastructure of Web 1.0 or Web 2.0 solutions.
RDF views are also suitable for declaring custom representation for RDF triples, e.g. property tables, where one row holds many single-valued properties.
</para>
<sect3 id="rdfviewsintro"><title>Introduction</title>
<para>
The Virtuoso RDF Views meta schema is a built-in feature of Virtuoso's SPARQL to SQL translator.
It recognizes triple patterns that refer to graphs for which an alternate representation is declared and translates these into SQL accordingly.
The main purpose of this is evaluating SPARQL queries against existing relational databases.
There exists previous work from many parties for rendering relational data as RDF and opening it to SPARQL access.
We can mention D2RQ, SPASQL, Squirrel RDF, DBLP and others.
The Virtuoso effort differs from these mainly in the following:
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Integration with a triple store.
Virtuoso can process a query for which some triple patterns will go to local or remote relational data and some to local physical RDF triples.
</listitem><listitem>SPARQL query can be used in any place where SQL can.
Database connectivity protocols are neutral to the syntax of queries they transmit, thus any SQL client, e.g. JDBC, ODBC or XMLA application, can send SPARQL queries and fetch result sets.
Moreover, a SQL query may contain SPARQL subqueries and SPARQL expressions may use SQL built-in functions and stored procedures.
</listitem><listitem>Integration with SQL.
Since SPARQL and SQL share the same run time and query optimizer, the query compilation decisions are always made with the best knowledge of the data and its location.
This is especially important when mixing triples and relational data or when dealing with relational data distributed across many outside databases.
</listitem><listitem>No limits on SPARQL.
It remains possible to make queries with unspecified graph or predicate against mapped relational data, even though these may sometimes be inefficient.
</listitem><listitem>Coverage of the whole relational model.
Multi-part keys etc. are supported in all places.
</listitem>
</itemizedlist>
</sect3>
<sect3 id="rdfviewrationale"><title>Rationale</title>
<para>
Since most of the data that is of likely use for the emerging semantic web is stored in relational databases, the argument for exposing this to SPARQL access is clear.
We note that historically, SQL access to relational data has essentially never been given to the public outside of the organization.
If programmatic access to corporate IS has been available to partners or the public, it has been through dynamic web pages or more recently web services.
There are reasons of performance, security, maintainability and so forth for this.
</para><para>
The culture of the emerging semantic web is however taking a different turn.
Since RDF and OWL offer a mergeable and queryable model for heterogeneous data, it is more meaningful and maintainable to expose selected data for outside query than it would be with SQL.
Advances in hardware make this also less of a performance issue than it would have been in the client-server database era.
</para><para>
In the context of Virtuoso, since Virtuoso is originally a virtual/federated database, incorporating SPARQL to relational mapping is an evident extension of the product's mission as a multi-protocol, multi-platform connector between information systems.
</para>
</sect3>
<sect3 id="rdfviewquadmapatternsvalueandiriclasses"><title>Quad Map Patterns, Value and IRI Classes</title>
<para>
In the simplest sense, any relational schema can be rendered into RDF by converting all primary keys and foreign keys into IRI's, assigning a predicate IRI to each column, and an rdf:type predicate for each row linking it to a RDF class IRI corresponding to the table.
Then a triple with the primary key IRI as subject, the column IRI as predicate and the column's value as object is considered to exist for each column that is neither part of a primary or foreign key.
</para><para>
Strictly equating a subject value to a row and each column to a predicate is often good but is too restrictive for the general case.
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Multiple triples with the same subject and predicate can exist.
</listitem><listitem>A single subject can get single-valued properties from multiple tables or in some cases stored procedures.
</listitem><listitem>An IRI value of a subject or other field of a triple can be composed from more than one SQL value, these values may reside in different columns, maybe in different joined tables.
</listitem><listitem>Some table rows should be excluded from mapping.
</listitem></itemizedlist>
<para>
Thus in the most common case the RDF meta schema should consist of independent transformations; the domain of each transformation is a result-set of some SQL <emphasis>SELECT</emphasis> statement and range is a set of triples.
The <emphasis>SELECT</emphasis> that produce the domain is quite simple: it does not use aggregate functions, joins and sorting, only inner joins and <emphasis>WHERE</emphasis> conditions.
There is no need to support outer joins in the RDF meta schema because NULLs are usually bad inputs for functions that produce IRIs.
In the rare cases when NULLs are OK for functions, outer joins can be encapsulated in SQL views.
The range of mapping can be described by a SPARQL triple pattern: a pattern field is a variable if it depends on table columns, otherwise it is a constant.
Values of variables in the pattern may have additional restrictions on datatypes, when datatypes of columns are known.
</para><para>
This common case of an RDF meta schema is implemented in Virtuoso, with one adjustment.
Virtuoso stores quads, not triples, using the graph field (G) to indicate that a triple belongs to some particular application or resource.
A SPARQL query may use quads from different graphs without large difference between G and the other three fields of a quad.
E.g., variable <emphasis>?g</emphasis> in expression <emphasis>GRAPH ?g {...}</emphasis> can be unbound.
SPARQL has special syntax for "graph group patterns" that is convenient for sets of triple patterns with a common graph, but it also has shorthands for common subject and predicate, so the difference is no more than in syntax.
There is only one feature that is specific for graphs but not for other fields: the SPARQL compiler can create restrictions on graphs according to <emphasis>FROM</emphasis> and <emphasis>FROM NAMED</emphasis> clauses.
</para><para>
Virtuoso RDF Views should offer the same flexibility with the graphs as SPARQL addressing physical triples.
A transformation cannot always be identified by the graph used for ranges because graph may be composed from SQL data. The key element of the meta schema is a "<emphasis>quad map pattern</emphasis>".
A simple quad map pattern fully defines one particular transformation from one set of relational columns into triples that match one SPARQL graph pattern.
The main part of quad map pattern is four declarations of "<emphasis>quad map values</emphasis>", each declaration specifies how to calculate the value of the corresponding triple field from the SQL data.
The pattern also lists boolean SQL expressions that should be used to filter out unwanted rows of source data (and to join multiple tables if source columns belong to different tables).
There are also quad map patterns that group together similar quad patterns but do not specify any real transformation or even prevent unwanted transformations from being used, they are described in "Grouping Map Patterns" below.
</para><para>
Quad map values refer to schema elements of two further types: "IRI classes" and "literal classes".
</para>
<sect4 id="rdfviewiriclasses"><title>IRI Classes</title>
<para>
An IRI class declares that a column or set of columns gets converted into a IRI in a certain way.
The conversion of this sort can be declared revertible (bijection) so an IRI can be parsed into original SQL values; this is useful when some equality of an IRI constant and a calculated IRI can be replaced with an equality of a parse result of a constant and an SQL column that is index criteria or simply faster.
In addition, the SPARQL optimizer will eliminate redundant conversions if one IRI class is explicitly declared as a subclass of another.
The most flexible declaration for conversion consists of specifying functions that assemble and disassemble from IRI into its constituent parts.
This is overkill for typical conversions so it is possible to specify only one sprintf-style format string such that <emphasis>sprintf()</emphasis> SQL function will print an IRI using this format and <emphasis>sprintf_inverse()</emphasis> will be able to parse it back.
</para><para>The use of <emphasis>sprintf_inverse()</emphasis> assumes that the format does not contain fragments like <emphasis>'%s%s'</emphasis> that make it impossible to separate parts of IRI from each other.
</para><para>
In the following, we shall map the Virtuoso users and user roles system tables into the SIOC ontology.
</para>
<programlisting><![CDATA[
create iri class oplsioc:user_iri "http://myhost/sys/user?id=%d"
(in uid integer not null) .
create iri class oplsioc:group_iri "http://myhost/sys/group?id=%d"
(in gid integer not null) .
create iri class oplsioc:membership_iri
"http://myhost/sys/membership?super=%d&sub=%d"
(in super integer not null, in sub integer not null) .
create iri class oplsioc:dav_iri "http://myhost%s"
(in path varchar) .
]]></programlisting>
<para>
These IRI classes are used for mapping data from the <emphasis>DB.DBA.SYS_USERS</emphasis> and <emphasis>DB.DBA.SYS_ROLE_GRANTS</emphasis> system tables that are defined in Virtuoso as follows:
</para>
<programlisting><![CDATA[
create table DB.DBA.SYS_USERS (
U_ID integer not null unique,
U_NAME char (128) not null primary key,
U_IS_ROLE integer default 0,
U_FULL_NAME char (128),
U_E_MAIL char (128) default ",
U_ACCOUNT_DISABLED integer default 1,
U_DAV_ENABLE integer default 0,
U_SQL_ENABLE integer default 1,
U_HOME varchar (128),
. . .
);
]]></programlisting>
<para>
Single record in <emphasis>DB.DBA.SYS_USERS</emphasis> corresponds to a plain user or a group (role).
Users and roles are collectively named "grantees". Thus a role may be granted to another role or to a user account.
A role grant may be direct (explicit) or assigned by recursion.
</para>
<programlisting><![CDATA[
create table SYS_ROLE_GRANTS (
GI_SUPER integer,
GI_SUB integer,
GI_DIRECT integer default 1,
. . .
primary key (GI_SUPER, GI_SUB, GI_DIRECT));
]]></programlisting>
<para>One IRI class usually corresponds to one ontology class, because similar things are usually called similarly.
One may wish to use identifiers of ontology classes as identifiers of related IRI classes, to not remember double number of names, e.g. <emphasis>create IRI class mybank:XpressXfer</emphasis> for subjects that will have <emphasis>rdf:type</emphasis> property <emphasis>mybank:XpressXfer</emphasis> made by mapping. That is technically possible but proven to become inconvenient and misleading as application evolves. While RDF types tend to persist, IRI classes may change over time or same subject may get more than one name via more than one IRI class, say, for exports to different systems. It is found to be more convenient to compose names of IRI classes by adding some common prefixes or suffixes to RDF classes (or to table names), say, write <emphasis>create IRI class mybank:XpressXfer_iri</emphasis>.</para>
</sect4>
<sect4 id="rdfviewliteralclasses"><title>Literal Classes</title>
<para>
A "literal class" declares that a column or set of columns gets converted into a literal instead of an IRI.
More precisely, the result of conversion can be <emphasis>IRI_ID</emphasis> so it represents an IRI, but in current version of Virtuoso this is supported only for some internal built-in literal classes, not for classes declared by the user.
So for user-defined literal class the result of the conversion is an RDF literal even if it is a string representation of a valid IRI.
</para><para>
In any case, a literal class can be used only in quad map values of O fields, because Virtuoso does not support literal values as subjects.
</para><para>
A special case of literal class is the identity class that converts a value from <emphasis>varchar</emphasis> column into an untyped literal and value from column of any other SQL datatype into a typed literal with type from XMLSchema set, i.e. <emphasis>xsd:integer</emphasis>, <emphasis>xsd:dateTime</emphasis> and so on.
Columns of types <emphasis>ANY</emphasis> and <emphasis>IRI_ID</emphasis> are not supported.
</para><para>
The SPARQL optimizer knows that RDF literal types are pairwise disjoint so literal classes that produce literals of different types are known to be pairwise disjoint.
The optimizer will replace a join on two disjoint literal classes with an empty statement, to simplify the resulting query.
</para>
</sect4>
<sect4 id="rdfviewsimplequadmappatterns"><title>Simple Quad Map Patterns</title>
<para>
The following declaration of quad map pattern is self-explanatory. The line for <emphasis>object</emphasis> uses identity literal class so there's no need to specify its name.
</para>
<programlisting><![CDATA[
graph <http://myhost/sys>
subject oplsioc:user_iri (DB.DBA.SYS_USERS.U_ID)
predicate foaf:email
object DB.DBA.SYS_USERS.U_E_MAIL
]]></programlisting>
<para>
The description language also supports SPARQL-style notation that contains less keywords and eliminates duplicate graphs, subjects and predicates.
The following add two patterns with constant graph IRI <emphasis><http://myhost/sys></emphasis> and subjects are made from column <emphasis>DB.DBA.SYS_USERS.U_ID</emphasis> by <emphasis>oplsioc:user_iri</emphasis>.
</para>
<programlisting><![CDATA[
graph <http://myhost/sys>
{
oplsioc:user_iri (DB.DBA.SYS_USERS.U_ID)
a sioc:user ;
oplsioc:name DB.DBA.SYS_USERS.U_FULL_NAME .
}
]]></programlisting>
</sect4>
<sect4 id="rdfviewassigningnamestoquadmappatterns"><title>Assigning Names To Quad Map Patterns</title>
<para>
In real applications, quad map patterns should be named, for schema manipulation and keeping debug info readable.
Thus it is much better to rewrite the previous example as
</para>
<programlisting><![CDATA[
create virtrdf:SysUsers as graph <http://myhost/sys>
{
oplsioc:user_iri (DB.DBA.SYS_USERS.U_ID)
a sioc:user
as virtrdf:SysUserType-User;
oplsioc:name DB.DBA.SYS_USERS.U_FULL_NAME
as virtrdf:SysUsersFullName .
}
]]></programlisting>
<para>
Using these names, one may later write, say, <emphasis>drop quad map virtrdf:SysUserType-User</emphasis>.
</para><para>
One name, <emphasis>virtrdf:DefaultQuadMap</emphasis> is reserved.
It is an internal quad map pattern used to access "native-form" quads from <emphasis>DB.DBA.RDF_QUAD</emphasis>:
</para>
<programlisting><![CDATA[
create virtrdf:DefaultQuadMap as
graph rdfdf:default-iid-nonblank (DB.DBA.RDF_QUAD.G)
subject rdfdf:default-iid (DB.DBA.RDF_QUAD.S)
predicate rdfdf:default-iid-nonblank (DB.DBA.RDF_QUAD.P)
object rdfdf:default (DB.DBA.RDF_QUAD.O)
]]></programlisting>
<para>
IRI classes from <emphasis>rdfdf:...</emphasis> namespace are also reserved.
</para>
</sect4>
<sect4 id="rdfviewgroupingmappatterns"><title>Grouping Map Patterns</title>
<para>
The previous example actually contains three map patterns, not two.
The name <emphasis>virtrdf:SysUsers</emphasis> refers to a "<emphasis>group map pattern</emphasis>" that does not define any real transformation of relational data into RDF but helps organize quad map patterns into a tree.
Group may contain both quad map patterns and other groups.
A group can be manipulated as a whole, e.g. <emphasis>drop quad map virtrdf:SysUsers</emphasis> will remove all three map patterns.
</para>
</sect4>
</sect3>
<sect3 id="rdfviewconfiguringrdfstorages"><title>Configuring RDF Storages</title>
<para>
"<emphasis>Quad Storage</emphasis>" is a named set of quad map patterns.
The declaration <emphasis>define input:storage storage-name</emphasis> states that a SPARQL query will be executed using only quad patterns of the given quad storage.
Declarations of IRI classes, literal classes and quad patterns are shared between all quad storages of an RDF meta schema but every quad storage contains only a subset of all available quad patterns.
Two quad storages are always defined:
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>A <emphasis>virtrdf:default</emphasis> one usually consists of everything (all user-relational mappings plus <emphasis>virtrdf:DefaultQuadMap</emphasis> for "native-form" quads from <emphasis>DB.DBA.RDF_QUAD</emphasis>)
</listitem><listitem>A <emphasis>virtrdf:empty</emphasis> storage refers solely to <emphasis>DB.DBA.RDF_QUAD</emphasis> and can not be altered.
</listitem></itemizedlist>
<para>
Three statements for manipulating storages are
</para>
<itemizedlist mark="number" spacing="compact">
<listitem><emphasis>create quad storage storage-name { quad-map-decls } .</emphasis>
</listitem><listitem><emphasis>alter quad storage storage-name { quad-map-decls-or-drops } .</emphasis>
</listitem><listitem><emphasis>drop quad storage storage-name . </emphasis>
</listitem></itemizedlist>
<para>
A map pattern can be created only as a part of <emphasis>create quad storage</emphasis> or <emphasis>alter quad storage</emphasis> statement, so initially it is used by exactly one storage.
It can be imported to some other storage using directive <emphasis>create map-id using storage source-storage</emphasis>. E.g., declarations of many storages create <emphasis>virtrdf:DefaultQuadMap</emphasis> using storage <emphasis>virtrdf:DefaultQuadStorage</emphasis>.
</para><para>
Only a "top-level" quad map pattern (standalone or a whole group with descendants) can be imported, member of a group can not.
The import directive also can not be a part of some group declaration.
</para><para>
The directive <emphasis>drop quad map map-name</emphasis> removes a map from one storage when it appears inside <emphasis>alter quad storage</emphasis> statement.
Otherwise it removes the map from all storages.
There exists garbage collection for quad map patterns, so any unused map is immediately deleted.
A group is deleted with all its descendants.
</para>
</sect3>
<sect3 id="rdfviewtranslationofpatterns"><title>Translation Of SPARQL Triple Patterns To Quad Map Patterns</title>
<para>
When a SPARQL query is compiled into SQL using a quad storage, every triple pattern should become a subquery that retrieves data from relational tables.
This subquery is an <emphasis>UNION ALL</emphasis> of joins generated from appropriate quad map patterns.
The complete SQL query is composed from these basic subqueries.
Thus the first operation of the SQL generation for a triple pattern is searching for quad map patterns that may in principle produce triples that match the triple pattern.
</para><para>
The more restrictions contained in the triple pattern the fewer quad map patterns will be used.
A triple pattern <emphasis>graph ?g { ?s ?p ?o }</emphasis> is common enough to invoke all data transformations of the storage.
A triple pattern <emphasis>graph <g> { ?s <p> <o> }</emphasis> will usually intersect with the range of only one quad map.
Sometimes it is possible to prove that the storage can not contain any data that matches the given triple pattern, hence zero number of members of <emphasis>UNION ALL</emphasis> will result in constantly empty result-set.
</para>
<para>The search for quad maps for a given pair of triple pattern and quad map storage is quite simple.
The storage is treated as a tree of map patterns where quad map patterns are leafs, grouping patterns are inner nodes and the whole storage is also treated as a grouping pattern that specify no fields and contains all top-level map patterns of the storage.
</para>
<para>
The tree is traversed from the root, left to right, non-leaf vertex are checked before their children.
The check of a vertex consists of up to four field checks, for G, S, P and O.
Every field check compares the field definition in the vertex and the corresponding field in the triple pattern, G and G, S and S and so on.
Note that a non-leaf vertex defines less than four of its fields, e.g., the root vertex does not define any of its fields and top-level <emphasis>graph map { ... }</emphasis> defines only graph.
Checks are performed only for defined fields and return one of three values: "failed", "passed", "full match", according to the following rules:
</para>
<table><title>Matching Triple Field and Vertex Field</title>
<tgroup cols="3">
<thead><row>
<entry>Field of vertex</entry><entry>Field in triple pattern</entry><entry>Result</entry>
</row></thead>
<tbody>
<row><entry>constant</entry><entry>same constant</entry><entry>full match</entry></row>
<row><entry>constant</entry><entry>different constant</entry><entry>failed</entry></row>
<row><entry>constant</entry><entry>variable of same type</entry><entry>passed</entry></row>
<row><entry>constant</entry><entry>variable of different type</entry><entry>failed</entry></row>
<row><entry>quad map value</entry><entry>constant of same type</entry><entry>full match</entry></row>
<row><entry>quad map value</entry><entry>constant of different type</entry><entry>failed</entry></row>
<row><entry>quad map value of type X</entry><entry>variable, X or subtype of X</entry><entry>full match</entry></row>
<row><entry>quad map value of type X</entry><entry>variable, supertype of X</entry><entry>passed</entry></row>
<row><entry>quad map value of type X</entry><entry>variable, type does not intersect with X</entry><entry>failed</entry></row>
</tbody>
</tgroup>
</table>
<para>
If any of the checks fails, the vertex and all its children are excluded from the rest of processing.
Otherwise, if all four fields are defined for the quad map pattern, the map is added to the list of matching map patterns.
The difference between "passed" and "full match" is significant only if the map is declared with <emphasis>option (exclusive)</emphasis>
If all performed checks return "full match" and <emphasis>option (exclusive)</emphasis> is set then the traverse of the tree is stopped as soon as all children of the vertex are traversed.
The most typical use of this option is when the application developer is sure that all triples of a graph belong to his application and they come from his own quad map patterns, not from <emphasis>DB.DBA.RDF_QUAD</emphasis>.
This is to prevent the SPARQL compiler from generating redundant subqueries accessing <emphasis>DB.DBA.RDF_QUAD</emphasis>.
The declaration may look like
</para>
<programlisting><![CDATA[
create quad storage <mystorage>
{
graph <mygraph> option (exclusive) { . . . }
create virtrdf:DefaultQuadMap
using storage virtrdf:DefaultQuadStorage .
}
]]></programlisting>
<para>
Exclusive patterns make the order of declarations important, because an exclusive declaration may "throw a shadow" on declarations after it.
Consider a database that have a special table RDF_TYPE that caches all RDF types of all subjects in all graphs.
Consider two declarations: all triples from graph <emphasis><http://myhost/sys></emphasis> and all triples with <emphasis>rdf:type</emphasis> predicate, both exclusive:
</para>
<programlisting><![CDATA[
graph <http://myhost/sys> option (exclusive)
{
. . . # mapping of DB.DBA.SYS_USERS as in previous examples.
}
graph rdfdf:default-iid-nonblank (DB.DBA.RDF_TYPE.G)
subject rdfdf:default-iid (DB.DBA.RDF_TYPE.S)
predicate rdf:type
object rdfdf:default (DB.DBA.RDF_TYPE.O)
option (exclusive)
]]></programlisting>
<para>
The order of these declarations dictates that triple pattern
</para>
<programlisting><![CDATA[
graph <http://myhost/sys> {?s rdf:type ?o}
]]></programlisting>
<para>
is compiled using only quad map patterns of the graph declaration, ignoring second declaration (and of course ignoring default mapping rule, if any).
An explicit <emphasis>option (order N)</emphasis> at the end of quad map pattern will tweak the priority.
By default, order will grow from 1000 for the first declaration in the statement to 1999 for the last, explicit configuration is especially useful to make order persistent to <emphasis>alter storage</emphasis> statements.
</para>
<para>
The <emphasis>option (exclusive)</emphasis> trick is ugly, low-level and prone to cause compilation errors after altering storage declarations.
When misused, it is as bad as "red cut" in PROLOG, but one must use this trick to build scalable storages.
</para>
<para>The <emphasis>option (exclusive)</emphasis> helps the SPARQL compiler to prepare better SQL queries, but sometimes it is "too exclusive". For instance, if a grouping quad map pattern specify only quad map value for graph and no other fields then making it exclusive prohibits the use of all declarations of the storage after that one. Sometimes it is better to notify compiler that quads made by the given quad map pattern are supposed to be different from all quads made by declarations listed after the given one.</para>
<para>Consider an application that exports users' personal data
as graphs whose IRIs looks like
<emphasis>http://www.example.com/DAV/home/</emphasis>username<emphasis>/RDF/personal/</emphasis>;
the application makes a query and a triple pattern is proven to be
restrictive enough to filter out all quads that are not similar to
quads generated by the given quad map pattern (say, the graph is
constant
<emphasis>http://www.example.com/DAV/home/JohnSmith/RDF/personal/</emphasis>). The
application do not hope to find any quads that match the pattern but
made by other applications, because graphs named like in the pattern
are supposed to be solely for this single purpose; if, say,
DB.DBA.RDF_QUAD occasionally contains some quads with graph equal to
<emphasis>http://www.example.com/DAV/home/JohnSmith/RDF/personal/</emphasis>
then they can be ignored.</para>
<para>Under this circumstances, the quad map pattern may have <emphasis>option (soft exclusive)</emphasis>. That grants a permission to the compiler to ignore rest of storage as soon as it is proven that the triple pattern can not access quads that does not match the pattern. So if that is proven then the pattern is exclusive and it makes the query faster; when unsure, the compiler work like there is no option at all.</para>
<note><para>The <emphasis>option (exclusive)</emphasis> can be used as
a security measure, <emphasis>option (soft exclusive)</emphasis> can
not. Say, if an financial application exports its data as a single
graph <emphasis>http://www.example.com/front-office/cash/</emphasis>
using <emphasis>exclusive</emphasis> then the query that explicitly
refers to that graph will never access any quads written by the
attacker into DB.DBA.RDF_QUAD using same graph IRI. The use of
<emphasis>soft exclusive</emphasis> gives no such protection. From the
compiler's perspective, the <emphasis>option (soft
exclusive)</emphasis> is a hint that may be ignored, not an
unambiguous order.</para></note>
<para>
There is one exception from the rules described above.
This exception is for <emphasis>virtrdf:DefaultQuadStorage</emphasis> only.
If a graph variable of a quad map pattern is not bound and no source graph specified by <emphasis>FROM</emphasis> clauses then quad maps for specific constant graphs are ignored.
In other words, if a default quad storage contains quad maps for specific graphs then the query in that storage should explicitly specify the graph in order to use a map for graph.
This rule will not work if the default quad map is removed from the <emphasis>virtrdf:DefaultQuadStorage</emphasis>.
This rule relates to the default storage itself, not to the containing patterns; copying some or all patterns into other storage will not reproduce there this special effect.
</para>
</sect3>
<sect3 id="rdfviewdescribingsourcerelationaltables"><title>Describing Source Relational Tables</title>
<para>Quad map patterns of an application usually share a common set of source tables and quad map values of one pattern usually share either a single table or very small number of joined tables.
Join and filtering conditions are also usually repeated in different patterns.
It is not necessary to type table descriptions multiple times, they are declare once in the beginning of storage declaration statement and shared between all quad map declarations inside the statement.
Names of aliases can be used instead of table names in quad map values.
</para>
<programlisting><![CDATA[
FROM DB.DBA.SYS_USERS as user WHERE (^{user.}^.U_IS_ROLE = 0)
FROM DB.DBA.SYS_USERS as group WHERE (^{group.}^.U_IS_ROLE = 1)
FROM DB.DBA.SYS_USERS as account
FROM user as active_user
WHERE (^{active_user.}^.U_ACCOUNT_DISABLED = 0)
FROM DB.DBA.SYS_ROLE_GRANTS as grant
WHERE (^{grant.}^.GI_SUPER = ^{account.}^.U_ID)
WHERE (^{grant.}^.GI_SUB = ^{group.}^.U_ID)
WHERE (^{grant.}^.GI_SUPER = ^{user.}^.U_ID)
]]></programlisting>
<para>
This declares five distinct aliases for two distinct tables, and six filtering conditions.
Every condition is an SQL expression with placeholders where a reference to the table should be printed.
The SPARQL compiler will not try to parse texts of these expressions (except dummy search for placeholders), so any logical expressions are acceptable.
When a quad map pattern declaration refers to some aliases, the <emphasis>WHERE</emphasis> clause of the generated SQL code will contain a conjunction of all distinct texts of "relevant" conditions.
A condition is relevant if every alias inside the condition is used in some quad map value of the map pattern, either directly or via clause like <emphasis>from user as active_user</emphasis>.
(<emphasis>user</emphasis> is a "<emphasis>base alias</emphasis>" for <emphasis>active_user</emphasis>).
</para><para>
Consider a group of four declarations.
</para>
<programlisting><![CDATA[
graph <http://myhost/sys>
{
oplsioc:user_iri (active_user.U_ID)
a oplsioc:active-user .
oplsioc:membership_iri (grant.GI_SUPER, grant.GI_SUB).
oplsioc:is_direct
grant.GI_DIRECT ;
oplsioc:member-e-mail
active_user.U_E_MAIL
where (^{active_user.}^.U_E_MAIL like 'mailto:%').
ldap:account-ref (account.U_NAME)
ldap:belongs-to
ldap:account-ref (group.U_NAME) option (using grant).
}
]]></programlisting>
<para>
The first declaration will extend <emphasis><http://myhost/sys></emphasis> graph with one imaginary triples <emphasis>{ user a oplsioc:active-user }</emphasis> for every account record that is not a role and not disabled.
The second declaration deals with membership records.
A membership is a pair of a grantee ("super") and a granted role ("sub") stored as a row in <emphasis>DB.DBA.SYS_ROLE_GRANTS</emphasis>).
</para><para>
The second declaration states that every membership has <emphasis>oplsioc:is_direct</emphasis> property with value from <emphasis>GI_DIRECT</emphasis> column of that table (roles may be granted to other roles and users, so permissions are "direct" or "recursive").
</para><para>
The third declaration declares <emphasis>oplsioc:member-e-mail</emphasis> property of memberships.
The value is a literal string from <emphasis>DB.DBA.SYS_USERS.U_E_MAIL</emphasis>, if the grantee is active (not disabled) and is not a role and its e-mail address starts with <emphasis>'mailto:'</emphasis>.
The join between <emphasis>DB.DBA.SYS_ROLE_GRANTS</emphasis> and <emphasis>DB.DBA.SYS_USERS</emphasis> is made by equality <emphasis>(GI_SUPER = U_ID)</emphasis> because the alias <emphasis>active_user</emphasis> in the declaration "inherits" all conditions specified for <emphasis>user</emphasis>.
In addition, the SPARQL compiler will add one more condition to check if the <emphasis>U_E_MAIL</emphasis> is not null because the NULL value is not a valid object and it knows that <emphasis>U_E_MAIL</emphasis> is not declared as <emphasis>NOT NULL</emphasis>.
</para><para>
The last declaration contains an <emphasis>option</emphasis> clause.
As usual, this indicates that the basic functionality is good for many tasks but not for all.
In this declaration, the <emphasis>ldap:belongs-to</emphasis> property establishes a relation between grantee (subject) and a granted role (object).
Both subject and object IRIs are based on account name, <emphasis>DB.DBA.SYS_USERS.U_NAME</emphasis>, so the quad map pattern contains two references to different aliases of <emphasis>DB.DBA.SYS_USERS</emphasis> but no alias for <emphasis>DB.DBA.SYS_ROLE_GRANTS</emphasis>.
Hence the declaration could produce a triple for every row of the Cartesian product of the <emphasis>DB.DBA.SYS_USERS</emphasis>.
To fix the problem, <emphasis>option (using alias-name)</emphasis> tells the compiler to process the alias-name as if it's used in some quad map value of the pattern.
</para><para>
It is an error to use an alias only in <emphasis>where</emphasis> clause of the quad map pattern but neither in values or in <emphasis>option (using alias-name)</emphasis>.
To detect more typos, an alias used in quad map values can not appear in <emphasis>option (using alias-name)</emphasis> clause.
</para>
</sect3>
<sect3 id="rdfviewiriusingfunction"><title>Function-Based IRI Classes</title>
<para>Most of IRI classes can be declared by a sprintf format string, but sophisticated cases may require calculations, not only printing the string. <emphasis>create IRI class using function</emphasis> allows the application transform relational values to IRIs by any custom routines.</para>
<para>
Let us extend the previous example about users and groups by a new class for grantees. Both users and groups are grantees and we have defined two IRI classes for them. Classes <emphasis>oplsioc:user_iri</emphasis> and <emphasis>oplsioc:group_iri</emphasis> work fine for quad maps of <emphasis>U_ID</emphasis> if and only if the value of <emphasis>U_IS_ROLE</emphasis> is accordingly restricted to FALSE or TRUE, otherwise one may occasionally generate, say, user IRI for a group.
To create and parse IRIs that correspond to any U_IDs, two functions should be created:
</para>
<programlisting><![CDATA[
create function DB.DBA.GRANTEE_URI (in id integer)
returns varchar
{
declare isrole integer;
isrole := coalesce ((SELECT top 1 U_IS_ROLE
FROM DB.DBA.SYS_USERS WHERE U_ID = id ) );
if (isrole is null)
return NULL;
else if (isrole)
return sprintf ('http://%s/sys/group?id=%d', id);
else
return sprintf ('http://%s/sys/user?id=%d', id);
};
]]></programlisting>
<programlisting><![CDATA[
create function DB.DBA.GRANTEE_URI_INVERSE (in id_iri varchar)
returns integer
{
declare parts any;
parts := sprintf_inverse (id_iri,
'http://myhost/sys/user?id=%d', 1 );
if (parts is not null)
{
if (exists (SELECT top 1 1 FROM DB.DBA.SYS_USERS
WHERE U_ID = parts[0] and not U_IS_ROLE ) )
return parts[0];
}
parts := sprintf_inverse (id_iri,
'http://myhost/sys/group?id=%d', 1 );
if (parts is not null)
{
if (exists (SELECT top 1 1 FROM DB.DBA.SYS_USERS
WHERE U_ID = parts[0] and U_IS_ROLE ) )
return parts[0];
}
return NULL;
};
]]></programlisting>
<para>These functions may be more useful if the SPARQL web service endpoint is allowed to use them:</para>
<programlisting><![CDATA[
grant execute on DB.DBA.GRANTEE_URI to "SPARQL";
grant execute on DB.DBA.GRANTEE_URI_INVERSE to "SPARQL";
]]></programlisting>
<para>
The next declaration creates an IRI class based on these two functions:
</para>
<programlisting><![CDATA[
create iri class oplsioc:grantee_iri using
function DB.DBA.GRANTEE_URI (in id integer)
returns varchar,
function DB.DBA.GRANTEE_URI_INVERSE (in id_iri varchar)
returns integer .
]]></programlisting>
<para>
In common case, IRI class declaration contains an N-array function that composes IRIs and N inverse functions that gets an IRI as an argument and extracts the Nth SQL value.
IRI composing function should silently return NULL on incorrect arguments instead of error signal.
Inverse functions should return NULL if the argument has an incorrect type or value.
</para>
<para>
It is possible to specify only composing function without any of inverse functions. However <emphasis>option (bijection)</emphasis> can not be used in that case, obviously.
</para>
</sect3>
<sect3 id="rdfconnvarsiniriclasses"><title>Connection Variables in IRI Classes</title>
<para>Writing function-based IRI class is overkill when the IRI can in principle be made by a <link linkend="fn_sprintf_iri"><function>sprintf_iri</function></link> but the format should contain some context-specific data, such as host name used for the <link linked="rdfdynamiclocal">dynamic renaming of local IRIs</link>.
Format strings offer a special syntax for that cases.
<emphasis>%{varname}U</emphasis> acts as <emphasis>%U</emphasis> but the function <link linkend="fn_sprintf"><function>sprintf</function></link> will take the value from client connection variable <emphasis>varname</emphasis>, not from list of arguments.
Similarly, <link linkend="fn_sprintf_inverse"><function>sprintf_inverse</function></link> will not return fragment that match to <emphasis>%{varname}U</emphasis> in the vector of other fragments; instead it will get the value from connection environment and ensure that it matches the fragment of input; mismatch between printed and actual value of variable will means that the whole string do not match the format.</para>
<para>SPARQL optimizer knows about this formatting feature and sometimes it makes more deductions from occurrence of <emphasis>%{varname}U</emphasis> than from occurrence of plain <emphasis>%U</emphasis>, so this notation may be used in <emphasis>option ( returns ...)</emphasis> when appropriate.
Of course, the optimizer has no access to the actual value of connection variable because it may vary from run to run or may change between the compilation and the run, but the value is supposed to be persistent during any single query run so <emphasis>%{myvariable}U</emphasis> in one place is equal to <emphasis>%{myvariable}U</emphasis> in other.</para>
<para>Connection variables are set by <link linkend="fn_connection_set"><function>connection_set</function></link> and some of them have default values that are used if not overridden by application:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem><emphasis>URIQADefaultHost</emphasis> is for default host as it is specified in Virtuoso configuration file.
Note, however, that it will be escaped when printed so if it contains colon and port number then the colon is escaped.
In addition, there are special variables that match dynamic renaming of local IRIs more accurately.</listitem>
<listitem><emphasis>WSHost</emphasis> is for host and port as it is used by current client connection for dynamic renaming.
The colon before port will be escaped.</listitem>
<listitem><emphasis>WSHostName</emphasis> is for host name only, without port, as it is used by current client connection for dynamic renaming.</listitem>
<listitem><emphasis>WSHostPort</emphasis> is for port part of host IRI. That is string, not integer. The only real use of the variable is in formats like <emphasis>http://%{WSHostName}U:%{WSHostPort}U/...</emphasis>.</listitem>
</itemizedlist>
<para>It is inconvenient to write different format strings for
different cases. Two most common policies are different host names
for default HTTP port of a publicly available service and different
non-default ports for one or more host names of an intranet
installation; these two approaches are almost never used in a mix. So
declaration of IRI classes may use shorthand
<emphasis>^{DynamicLocalFormat}^</emphasis> in format strings that is
expanded either to <emphasis>http://%{WSHost}U</emphasis> or to
<emphasis>http://%{WSHostName}U:%{WSHostPort}U/...</emphasis>,
depending on absence or presence of port number in the value of
<emphasis>DefaultHost</emphasis> parameter of
<emphasis>URIQA</emphasis> section of configuration file.</para>
<note><para><emphasis>^{DynamicLocalFormat}^</emphasis> is for IRI class declarations only and is not expanded in any other place, so it is useful sometimes to create an IRI class with empty argument list in order to get "almost constant" IRIs calculated without writing special procedures.</para></note>
</sect3>
<sect3 id="rdfviewbijandreturns"><title>Lookup Optimization -- BIJECTION and RETURNS Options</title>
<para>
There is one subtle problem with IRI class declarations.
To get benefit from a relational index, SPARQL optimizer should compose equality between table column and some known SQL value, not between return value of IRI class and a known composed IRI.
In addition, redundant calculations of IRIs takes time.
To enable this optimization, an IRI class declaration should end with <emphasis>option (bijection)</emphasis> clause. For some simple format strings the compiler may recognize the bijection automatically but an explicit declaration is always a good idea.
</para>
<note><title>Note:</title>
<para>
See also: <ulink url="http://en.wikipedia.org/wiki/One-to-one_correspondence">Wikipedia - Bijection</ulink>.
In mathematics, a bijection, or a bijective function is a function f from a set X to a set Y such that,
for every y in Y, there is exactly one x in X such that f(x) = y.
</para>
<para>
Alternatively, f is bijective if it is a one-to-one correspondence between those sets; i.e.,
both one-to-one (injective) and onto (surjective).
</para>
</note>
<para>
The SPARQL compiler may produce big amounts of SQL code when the query contains equality of two calculated IRIs and these IRIs may come from many different IRI classes.
It is possible to provide hints that will let the compiler check if two IRI classes form disjoint sets of possible IRI values. The more disjoint sets are found the less possible combinations remain so the resulting SQL query will contain fewer unions of joins.
The SPARQL compiler can prove some properties of sprintf format strings. E.g., it can prove that set of all strings printed by "http://example.com/item%d" and the set of strings printed by "http://example.com/item%d/" are disjoint.
It can prove some more complicated statements about unions and intersections of sets of strings.
The IRI or literal class declaration may contain <emphasis>option (returns ...)</emphasis> clause that will specify one or more sprintf patterns that cover the set of generated values.
Consider a better version of IRI class declaration listed above:
</para>
<programlisting><![CDATA[
create iri class oplsioc:grantee_iri using
function DB.DBA.GRANTEE_URI (in id integer)
returns varchar,
function DB.DBA.GRANTEE_URI_INVERSE (in id_iri varchar)
returns integer
option ( bijection,
returns "http://myhost/sys/group?id=%d"
union "http://myhost/sys/user?id=%d" ) .
]]></programlisting>
<para>
It is very important to keep IRI classes easily distinguishable by the text of IRI string and easy to parse.
</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Format <emphasis>%U</emphasis> is better than <emphasis>%s</emphasis>, especially in the middle of IRI, because the <emphasis>%U</emphasis> fragment can not contain characters like "/" or "="; one may prove that <emphasis>/%U/</emphasis> and <emphasis>/abra%d/cadabra/</emphasis> are disjoint but <emphasis>/%s/</emphasis> and <emphasis>/abra%d/cadabra/</emphasis> are not disjoint.
</listitem><listitem>It is better when the variable part like <emphasis>%U</emphasis> or <emphasis>%d</emphasis> is placed between characters that may not occur in the <emphasis>%U</emphasis> or <emphasis>%d</emphasis> output, i.e. <emphasis>%U</emphasis> is placed between "/", "&" or "=" and <emphasis>%d</emphasis> is placed between non-digits; <emphasis>order_line_%d</emphasis> is better than <emphasis>order-line-%d</emphasis> because minus may be part of <emphasis>%d</emphasis> output.
</listitem><listitem>End-of-line is treated as a special character, so placing <emphasis>%U</emphasis> or <emphasis>%d</emphasis> between "/" and end of line is as good as placing it between two "/".
</listitem></itemizedlist>
<para>
In some cases <emphasis>option (returns ...)</emphasis> can be used for IRI classes that are declared using sprintf format, but actual data have more specific format.
Consider a literal class declaration that is used to output strings and the application knows that all these strings are ISBN numbers:
</para>
<programlisting><![CDATA[
create literal class example:isbn_ref "%s" (in isbn varchar not null)
option ( bijection, returns "%u-%u-%u-%u" union "%u-%u-%u-X" )
]]></programlisting>
<para>
Sometimes interoperability restrictions will force you to violate these rules but please try to follow them as often as possible.
</para>
</sect3>
<sect3 id="rdfviewsubclasses"><title>Join Optimization -- Declaring IRI Subclasses</title>
<para>
Additional problem appears when the equality is between two IRIs of two different IRI classes.
Even if both of them are bijections, the compiler does not know if these IRI classes behave identically on the intersection of their domains.
To let the optimizer know this fact, one IRI class can be explicitly declared as a subclass of another:
</para>
<programlisting><![CDATA[
make oplsioc:user_iri subclass of oplsioc:grantee_iri .
make oplsioc:group_iri subclass of oplsioc:grantee_iri .
]]></programlisting>
<para>
The SPARQL compiler can not check the validity of a subclass declaration.
The developer should carefully test functions to ensure that transformations are really subclasses, as well as to ensure that functions of an IRI class declarations are really inverse to each other.
</para><para>
When declaring that a table's primary key is converted into a IRI according to one IRI class, one usually declares that all foreign keys referring to this class also get converted into an IRI as per this same class, or subclass of same class.
</para><para>
Subclasses can be declared for literal classes as well as for IRI classes, but this case is rare. The reason is that most of literals are made by identity literal classes that are disjoint to each other even if values may be equal in SQL sense, such as <emphasis>"2"</emphasis> of type <emphasis>xsd:integer</emphasis> and <emphasis>"2.0"</emphasis> of type <emphasis>xsd:double</emphasis>.
</para>
</sect3>
<sect3 id="rdfmetadatarecovery"><title>RDF Metadata Maintenance and Recovery</title>
<para>
This section refers to checking and backing up RDF view and storage declarations only. The checks and backup/restore do not affect physical quads, relational schema or tables or data therein. For general backup and restore, see server administration.
To detect and fix automatically most popular sorts of RDF metadata corruption use <link linkend="fn_rdf_audit_metadata"><function>DB.DBA.RDF_AUDIT_METADATA</function></link>.
It is also possible to backup RDF data by
<link linkend="fn_rdf_backup_metadata"><function>DB.DBA.RDF_BACKUP_METADATA</function></link>
and restore the saved state later by using
<link linkend="fn_rdf_restore_metadata"><function>DB.DBA.RDF_RESTORE_METADATA</function></link>.
It is convenient to make a backup before any modification of quad storages, quad map patterns or IRI classes, especially during debugging new RDF Views.
</para>
<note><para>In SQL, adding a new view can not break anything. This is because SQL lacks the ability of querying "everything" so data sources are always specified. This is not true for SPARQL, so please treat <emphasis>any</emphasis> metadata manipulation as potentially destructive operation. If an RDF storage is supposed to be used by more than one application then these applications should be tested together, not one after other, and they should be installed/upgraded on live database in the very same order as they were installed/upgraded on instrumental machine during testing. Always remember that these applications share RDF tables so they may interfere.</para></note>
</sect3>
<sect3 id="splitrdfview"><title>Split RDF View</title>
<para>RDF View can be created by two or more "sparql alter storage" statements. In each statement
can be created one quad map that contains mappings for half or a third of all tables. Quad maps
created should have distinct names but may mention same graph. The important fact is that if the
RDF View in question is exclusive for a graph then only the last quad map should be exclusive but
all previous should not have this option. This is because if a map is exclusive on a graph the rest
of maps on that graph will be silently ignored.</para>
<para>The example below shows a sample part of the Virtuoso eCRM Views code,
where the RDF view is split in two parts: with quad map virtrdf:ecrmDemo1 and with
quad map virtrdf:ecrmDemo2:</para>
<programlisting><![CDATA[
SPARQL
prefix ecrm: <http://demo.openlinksw.com/schemas/ecrm#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix cal: <http://www.w3.org/2002/12/cal/ical#>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix product: <http://www.swop-project.eu/ontologies/pmo/product.owl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
drop quad map virtrdf:ecrmDemo1 .
;
SPARQL
prefix ecrm: <http://demo.openlinksw.com/schemas/ecrm#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix cal: <http://www.w3.org/2002/12/cal/ical#>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix product: <http://www.swop-project.eu/ontologies/pmo/product.owl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
drop quad map virtrdf:ecrmDemo2 .
;
...
SPARQL
prefix ecrm: <http://demo.openlinksw.com/schemas/ecrm#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix cal: <http://www.w3.org/2002/12/cal/ical#>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix product: <http://www.swop-project.eu/ontologies/pmo/product.owl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
alter quad storage virtrdf:DefaultQuadStorage
FROM eCRM.DBA.SFA_SALES_QUOTA_VIEW2 as sales_quotas
FROM eCRM.DBA.SFA_COMPANIES_VIEW2 as companies
FROM eCRM.DBA.SFA_COMPANIES as companies_table text literal companies_table.DESCRIPTION of (companies.DESCRIPTION)
FROM eCRM.DBA.SFA_CONTACTS_VIEW2 as contacts
FROM eCRM.DBA.SFA_CONTACTS as contacts_table text literal contacts_table.NAME_FIRST of (contacts.NAME_FIRST)
FROM eCRM.DBA.SFA_EMPLOYMENTS_VIEW2 as employments
FROM eCRM.DBA.SFA_LEADS_VIEW2 as leads
FROM eCRM.DBA.SFA_LEADS as leads_table text literal leads_table.SUBJECT of (leads.SUBJECT)
FROM eCRM.DBA.SFA_OPPORTUNITIES_VIEW2 as opportunities
FROM eCRM.DBA.SFA_OPPORTUNITIES as opportunities_table text literal opportunities_table.OPPORTUNITY_NAME of (opportunities.OPPORTUNITY_NAME)
FROM eCRM.DBA.SFA_ACTIVITIES as activities
FROM eCRM.DBA.SFA_MAIL_MESSAGES as messages
FROM eCRM.DBA.SFA_DOCUMENTS_VIEW2 as documents
FROM eCRM.DBA.SFA_INFLUENCERS_VIEW2 as influencers
FROM eCRM.DBA.SFA_TEAMS_VIEW2 as teams
FROM eCRM.DBA.SFA_NOTES_VIEW2 as notes
FROM eCRM.DBA.SFA_NOTES as notes_table text literal notes_table.DESCRIPTION of (notes.DESCRIPTION)
FROM eCRM.DBA.SFA_COMPETITORS_VIEW2 as competitors
FROM eCRM.DBA.SFA_ISSUES_VIEW2 as issues
FROM eCRM.DBA.SFA_CUSTOM_FIELD_DEFS_VIEW2 as custom_field_defs
FROM eCRM.DBA.SFA_CUSTOM_FIELDS_VIEW2 as custom_fields
FROM eCRM.DBA.SFA_CASES_VIEW2 as cases
FROM eCRM.DBA.SFA_CASES as cases_table text literal cases_table.SUMMARY of (cases.SUMMARY)
FROM eCRM.DBA.SFA_ORDERS_VIEW2 as orders
FROM eCRM.DBA.SFA_ORDERS as orders_table text literal orders_table.EMAIL of (orders.EMAIL)
FROM eCRM.DBA.SFA_ORDER_ITEMS_VIEW2 as order_items
FROM eCRM.DBA.PM_CATEGORIES_VIEW2 as categories
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTE_DEFS_VIEW2 as product_attribute_defs
FROM eCRM.DBA.PM_PRODUCTS_VIEW2 as products
FROM eCRM.DBA.PM_PRODUCTS as products_table text literal products_table.DESCRIPTION of (products.DESCRIPTION)
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTES_VIEW2 as product_attributes
FROM eCRM.DBA.PM_CATALOGS_VIEW2 as catalogs
FROM eCRM.DBA.PM_CATALOG_PRODUCTS_VIEW2 as catalog_products
FROM eCRM.DBA.XSYS_MODULES as modules
FROM eCRM.DBA.XSYS_REGISTRY as registries
FROM eCRM.DBA.XSYS_ORGANIZATIONS_DATA as organizations_data
FROM eCRM.DBA.XSYS_MESSAGES as xsysmessages
FROM eCRM.DBA.XSYS_COUNTRIES_VIEW2 as countries
FROM eCRM.DBA.XSYS_PROVINCES_VIEW2 as provinces
FROM eCRM.DBA.XSYS_TIMEZONES as timezones
FROM eCRM.DBA.XSYS_MIME_TYPES as mimetypes
FROM eCRM.DBA.XSYS_MIME_EXTENSIONS as mimeexts
FROM eCRM.DBA.XSYS_CNAMES as cnames
FROM eCRM.DBA.XSYS_QUOTAS as quotas
FROM eCRM.DBA.XSYS_ROLES as roles
FROM eCRM.DBA.XSYS_ACCOUNTS as accounts
FROM eCRM.DBA.XSYS_USERDATA as userdatas
FROM eCRM.DBA.XSYS_GROUPDATA as groupdatas
FROM eCRM.DBA.XSYS_MEMBERS as members
FROM eCRM.DBA.XSYS_SESSIONS_DATA as sessionsdatas
FROM eCRM.DBA.XSYS_SESSION_DATA as sessiondatas
FROM eCRM.DBA.XSYS_LIST_MEMBERS_DEFS as list_members_defs
FROM eCRM.DBA.XSYS_CLASSES as classes
FROM eCRM.DBA.XSYS_ORG_CLASSES as org_classes
FROM eCRM.DBA.XSYS_CLASS_METHODS as class_methods
FROM eCRM.DBA.XSYS_CLASS_VIEWS as class_views
FROM eCRM.DBA.XSYS_ROLE_PRIVILEGES as role_priveleges
FROM eCRM.DBA.XSYS_USER_PRIVILEGES as user_priveleges
FROM eCRM.DBA.XSYS_HISTORY as history
FROM eCRM.DBA.XSYS_USERS as xsys_users
FROM eCRM.DBA.AP_PROCESSES_VIEW2 as ap_processes
FROM eCRM.DBA.AP_RULES_VIEW2 as ap_rules
FROM eCRM.DBA.AP_QUEUE as ap_queues
WHERE (^{companies.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{contacts.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{products.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{orders.}^.SHIP_COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads_table.}^.FREETEXT_ID = ^{leads.}^.FREETEXT_ID)
WHERE (^{contacts_table.}^.FREETEXT_ID = ^{contacts.}^.FREETEXT_ID)
WHERE (^{companies_table.}^.FREETEXT_ID = ^{companies.}^.FREETEXT_ID)
WHERE (^{opportunities_table.}^.FREETEXT_ID = ^{opportunities.}^.FREETEXT_ID)
WHERE (^{cases_table.}^.FREETEXT_ID = ^{cases.}^.FREETEXT_ID)
WHERE (^{notes_table.}^.FREETEXT_ID = ^{notes.}^.FREETEXT_ID)
WHERE (^{orders_table.}^.FREETEXT_ID = ^{orders.}^.FREETEXT_ID)
WHERE (^{products_table.}^.FREETEXT_ID = ^{products.}^.FREETEXT_ID)
{
create virtrdf:ecrmDemo1 as graph iri ("http://^{URIQADefaultHost}^/ecrm") option (order 1501)
{
ecrm:Country (countries.COUNTRY_NAME)
a ecrm:Country
as virtrdf:Country-Countrys2 ;
a geo:SpatialThing
as virtrdf:Country-Countrys ;
owl:sameAs ecrm:dbpedia_iri (countries.COUNTRY_NAME) ;
ecrm:countryID countries.COUNTRY_ID
as virtrdf:Country-COUNTRY_ID ;
ecrm:countryID3 countries.COUNTRY_ID3
as virtrdf:Country-COUNTRY_ID3 ;
ecrm:isoCode countries.ISO_CODE
as virtrdf:Country-ISO_CODE ;
ecrm:countryName countries.COUNTRY_NAME
as virtrdf:Country-COUNTRY_NAME .
ecrm:Country (countries.COUNTRY_NAME)
ecrm:has_province
ecrm:Province (provinces.COUNTRY_ID, provinces.PROVINCE_NAME) where
(^{provinces.}^.COUNTRY_ID = ^{countries.}^.COUNTRY_ID) as virtrdf:ecrmCountry-has_province .
...
} .
} .
;
SPARQL
prefix ecrm: <http://demo.openlinksw.com/schemas/ecrm#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix cal: <http://www.w3.org/2002/12/cal/ical#>
prefix product: <http://www.swop-project.eu/ontologies/pmo/product.owl#>
prefix owl: <http://www.w3.org/2002/07/owl#>
alter quad storage virtrdf:DefaultQuadStorage
FROM eCRM.DBA.SFA_SALES_QUOTA_VIEW2 as sales_quotas
FROM eCRM.DBA.SFA_COMPANIES_VIEW2 as companies
FROM eCRM.DBA.SFA_COMPANIES as companies_table text literal companies_table.DESCRIPTION of (companies.DESCRIPTION)
FROM eCRM.DBA.SFA_CONTACTS_VIEW2 as contacts
FROM eCRM.DBA.SFA_CONTACTS as contacts_table text literal contacts_table.NAME_FIRST of (contacts.NAME_FIRST)
FROM eCRM.DBA.SFA_EMPLOYMENTS_VIEW2 as employments
FROM eCRM.DBA.SFA_LEADS_VIEW2 as leads
FROM eCRM.DBA.SFA_LEADS as leads_table text literal leads_table.SUBJECT of (leads.SUBJECT)
FROM eCRM.DBA.SFA_OPPORTUNITIES_VIEW2 as opportunities
FROM eCRM.DBA.SFA_OPPORTUNITIES as opportunities_table text literal opportunities_table.OPPORTUNITY_NAME of (opportunities.OPPORTUNITY_NAME)
FROM eCRM.DBA.SFA_ACTIVITIES as activities
FROM eCRM.DBA.SFA_MAIL_MESSAGES as messages
FROM eCRM.DBA.SFA_DOCUMENTS_VIEW2 as documents
FROM eCRM.DBA.SFA_INFLUENCERS_VIEW2 as influencers
FROM eCRM.DBA.SFA_TEAMS_VIEW2 as teams
FROM eCRM.DBA.SFA_NOTES_VIEW2 as notes
FROM eCRM.DBA.SFA_NOTES as notes_table text literal notes_table.DESCRIPTION of (notes.DESCRIPTION)
FROM eCRM.DBA.SFA_COMPETITORS_VIEW2 as competitors
FROM eCRM.DBA.SFA_ISSUES_VIEW2 as issues
FROM eCRM.DBA.SFA_CUSTOM_FIELD_DEFS_VIEW2 as custom_field_defs
FROM eCRM.DBA.SFA_CUSTOM_FIELDS_VIEW2 as custom_fields
FROM eCRM.DBA.SFA_CASES_VIEW2 as cases
FROM eCRM.DBA.SFA_CASES as cases_table text literal cases_table.SUMMARY of (cases.SUMMARY)
FROM eCRM.DBA.SFA_ORDERS_VIEW2 as orders
FROM eCRM.DBA.SFA_ORDERS as orders_table text literal orders_table.EMAIL of (orders.EMAIL)
FROM eCRM.DBA.SFA_ORDER_ITEMS_VIEW2 as order_items
FROM eCRM.DBA.PM_CATEGORIES_VIEW2 as categories
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTE_DEFS_VIEW2 as product_attribute_defs
FROM eCRM.DBA.PM_PRODUCTS_VIEW2 as products
FROM eCRM.DBA.PM_PRODUCTS as products_table text literal products_table.DESCRIPTION of (products.DESCRIPTION)
FROM eCRM.DBA.PM_PRODUCT_ATTRIBUTES_VIEW2 as product_attributes
FROM eCRM.DBA.PM_CATALOGS_VIEW2 as catalogs
FROM eCRM.DBA.PM_CATALOG_PRODUCTS_VIEW2 as catalog_products
FROM eCRM.DBA.XSYS_MODULES as modules
FROM eCRM.DBA.XSYS_REGISTRY as registries
FROM eCRM.DBA.XSYS_ORGANIZATIONS_DATA as organizations_data
FROM eCRM.DBA.XSYS_MESSAGES as xsysmessages
FROM eCRM.DBA.XSYS_COUNTRIES_VIEW2 as countries
FROM eCRM.DBA.XSYS_PROVINCES_VIEW2 as provinces
FROM eCRM.DBA.XSYS_TIMEZONES as timezones
FROM eCRM.DBA.XSYS_MIME_TYPES as mimetypes
FROM eCRM.DBA.XSYS_MIME_EXTENSIONS as mimeexts
FROM eCRM.DBA.XSYS_CNAMES as cnames
FROM eCRM.DBA.XSYS_QUOTAS as quotas
FROM eCRM.DBA.XSYS_ROLES as roles
FROM eCRM.DBA.XSYS_ACCOUNTS as accounts
FROM eCRM.DBA.XSYS_USERDATA as userdatas
FROM eCRM.DBA.XSYS_GROUPDATA as groupdatas
FROM eCRM.DBA.XSYS_MEMBERS as members
FROM eCRM.DBA.XSYS_SESSIONS_DATA as sessionsdatas
FROM eCRM.DBA.XSYS_SESSION_DATA as sessiondatas
FROM eCRM.DBA.XSYS_LIST_MEMBERS_DEFS as list_members_defs
FROM eCRM.DBA.XSYS_CLASSES as classes
FROM eCRM.DBA.XSYS_ORG_CLASSES as org_classes
FROM eCRM.DBA.XSYS_CLASS_METHODS as class_methods
FROM eCRM.DBA.XSYS_CLASS_VIEWS as class_views
FROM eCRM.DBA.XSYS_ROLE_PRIVILEGES as role_priveleges
FROM eCRM.DBA.XSYS_USER_PRIVILEGES as user_priveleges
FROM eCRM.DBA.XSYS_HISTORY as history
FROM eCRM.DBA.XSYS_USERS as xsys_users
FROM eCRM.DBA.AP_PROCESSES_VIEW2 as ap_processes
FROM eCRM.DBA.AP_RULES_VIEW2 as ap_rules
FROM eCRM.DBA.AP_QUEUE as ap_queues
WHERE (^{companies.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{contacts.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{products.}^.COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{orders.}^.SHIP_COUNTRY_NAME = ^{countries.}^.COUNTRY_NAME)
WHERE (^{leads_table.}^.FREETEXT_ID = ^{leads.}^.FREETEXT_ID)
WHERE (^{contacts_table.}^.FREETEXT_ID = ^{contacts.}^.FREETEXT_ID)
WHERE (^{companies_table.}^.FREETEXT_ID = ^{companies.}^.FREETEXT_ID)
WHERE (^{opportunities_table.}^.FREETEXT_ID = ^{opportunities.}^.FREETEXT_ID)
WHERE (^{cases_table.}^.FREETEXT_ID = ^{cases.}^.FREETEXT_ID)
WHERE (^{notes_table.}^.FREETEXT_ID = ^{notes.}^.FREETEXT_ID)
WHERE (^{orders_table.}^.FREETEXT_ID = ^{orders.}^.FREETEXT_ID)
WHERE (^{products_table.}^.FREETEXT_ID = ^{products.}^.FREETEXT_ID)
{
create virtrdf:ecrmDemo2 as graph iri ("http://^{URIQADefaultHost}^/ecrm") option (exclusive, order 1502)
{
ecrm:Order (orders.ORG_ID, orders.ORDER_ID)
a ecrm:Order
as virtrdf:Order-Orders ;
ecrm:has_ecrm_organization ecrm:OrganizationsData(orders.ORG_ID, organizations_data.DNS_ZONE) where (^{orders.}^.ORG_ID = ^{organizations_data.}^.ORG_ID)
as virtrdf:Order-ORG_ID ;
ecrm:owner ecrm:XSys_User(orders.ORG_ID, xsys_users.ACCOUNT_NAME, orders.OWNER_ID)
where (^{orders.}^.OWNER_ID = ^{xsys_users.}^.ACCOUNT_ID and ^{orders.}^.ORG_ID = ^{xsys_users.}^.ORG_ID)
as virtrdf:Order-OWNER_ID ;
ecrm:FREETEXT_ID orders.FREETEXT_ID
as virtrdf:Order-FREETEXT_ID ;
ecrm:has_company ecrm:Company(orders.COMPANY_NAME, orders.COMPANY_ID, orders.ORG_ID)
as virtrdf:Order-COMPANY_ID ;
ecrm:companyName orders.COMPANY_NAME
as virtrdf:Order-COMPANY_NAME ;
ecrm:has_contact ecrm:Contact(contacts.NAME_FIRST, contacts.NAME_MIDDLE, contacts.NAME_LAST, orders.CONTACT_ID, orders.ORG_ID)
where (^{orders.}^.CONTACT_ID = ^{contacts.}^.CONTACT_ID and ^{orders.}^.ORG_ID = ^{contacts.}^.ORG_ID)
as virtrdf:Order-CONTACT_ID ;
ecrm:contactName orders.CONTACT_NAME
as virtrdf:Order-CONTACT_NAME ;
ecrm:orderNo orders.ORDER_NO
as virtrdf:Order-ORDER_NO ;
ecrm:shipFirstName orders.SHIP_FNAME
as virtrdf:Order-SHIP_FNAME ;
ecrm:shipSecondName orders.SHIP_SNAME
as virtrdf:Order-SHIP_SNAME ;
ecrm:phoneNumber orders.PHONE_NUMBER
as virtrdf:Order-PHONE_NUMBER ;
ecrm:phoneExtension orders.PHONE_EXTENSION
as virtrdf:Order-PHONE_EXTENSION ;
ecrm:email orders.EMAIL
as virtrdf:Order-EMAIL ;
ecrm:shipCountry ecrm:Country(orders.SHIP_COUNTRY_NAME)
as virtrdf:Order-SHIP_COUNTRY_NAME ;
ecrm:shipCountryCode ecrm:Country (countries.COUNTRY_NAME) where (^{countries.}^.COUNTRY_NAME = ^{orders.}^.SHIP_COUNTRY_NAME)
as virtrdf:Order-SHIP_COUNTRY_CODE ;
ecrm:shipProvince orders.SHIP_PROVINCE
as virtrdf:Order-SHIP_PROVINCE ;
ecrm:shipCity orders.SHIP_CITY
as virtrdf:Order-SHIP_CITY ;
ecrm:dbpedia_shipCity ecrm:dbpedia_iri (orders.SHIP_CITY)
as virtrdf:Order-SHIP_dbpedia_CITY ;
ecrm:shipPostalCode orders.SHIP_POSTAL_CODE
as virtrdf:Order-SHIP_POSTAL_CODE ;
ecrm:shipAddress1 orders.SHIP_ADDRESS1
as virtrdf:Order-SHIP_ADDRESS1 ;
ecrm:shipAddress2 orders.SHIP_ADDRESS2
as virtrdf:Order-SHIP_ADDRESS2 ;
ecrm:salesRep orders.SALESREP
as virtrdf:Order-SALESREP ;
ecrm:orderDate orders.ORDER_DATE
as virtrdf:Order-ORDER_DATE ;
ecrm:orderValue orders.ORDER_VALUE
as virtrdf:Order-ORDER_VALUE ;
ecrm:refund orders.REFUND
as virtrdf:Order-REFUND ;
ecrm:year orders.YEAR
as virtrdf:Order-YEAR ;
ecrm:month orders.MONTH
as virtrdf:Order-MONTH ;
ecrm:quarter orders.QUARTER
as virtrdf:Order-QUARTER ;
ecrm:financialYear orders.FINANCIAL_YEAR
as virtrdf:Order-FINANCIAL_YEAR ;
ecrm:CONTACT_REL_ID orders.CONTACT_REL_ID
as virtrdf:Order-CONTACT_REL_ID ;
ecrm:COMPANY_REL_ID orders.COMPANY_REL_ID
as virtrdf:Order-COMPANY_REL_ID .
...
} .
} .
;
]]></programlisting>
</sect3>
<sect3 id="rdfviewsrcur"><title>RDF views and recursive FK relationships</title>
<para>Here is sample example of a script to include an additional table alias for a table:</para>
<programlisting><![CDATA[
alter quad storage virtrdf:DefaultQuadStorage
:
FROM isports_rdf.prs10_isports_rdf.VRef_Call as Ref_Call_tbl
FROM isports_rdf.prs10_isports_rdf.VRef_Call as Ref_Call_tbl_1
:
{
:
refcall:ref-call_iri (Ref_Call_tbl.Call_Num) a refcall:Ref-Call as
virtrdf:ref-call_pk ;
:
refcall:has_parent refcall:ref-call_iri (Ref_Call_tbl_1.Call_Num)
where ( ^{Ref_Call_tbl.}^.Parent = ^{Ref_Call_tbl_1.}^.Call_Num ) as
virtrdf:Ref-Call_has_parent .
]]></programlisting>
<para>This demonstrates the way to self-join the table VRef_Call with itself. Like in SQL,
are needed two different aliases for one table if you want to join it with itself.
</para>
</sect3>
<sect3 id="rdfviewsbusint"><title>Business Intelligence</title>
<sect4 id="rdfviewsbusinttpc">
<title>TPCH to RDF</title>
<programlisting><![CDATA[
use DB;
GRANT SELECT ON TPCH.DBA.PARTSUPP TO "SPARQL";
GRANT SELECT ON TPCH.DBA.SUPPLIER TO "SPARQL";
GRANT SELECT ON TPCH.DBA.CUSTOMER TO "SPARQL";
GRANT SELECT ON TPCH.DBA.HISTORY TO "SPARQL";
GRANT SELECT ON TPCH.DBA.PART TO "SPARQL";
GRANT SELECT ON TPCH.DBA.LINEITEM TO "SPARQL";
GRANT SELECT ON TPCH.DBA.ORDERS TO "SPARQL";
GRANT SELECT ON TPCH.DBA.NATION TO "SPARQL";
GRANT SELECT ON TPCH.DBA.REGION TO "SPARQL";
SPARQL
drop quad map virtrdf:TPCH
;
SPARQL
prefix tpch: <http://www.openlinksw.com/schemas/tpch#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
create iri class tpch:customer "http://^{URIQADefaultHost}^/tpch/customer/%U%d#this" (in custname varchar, in c_custkey integer not null) option (bijection, deref) .
create iri class tpch:lineitem "http://^{URIQADefaultHost}^/tpch/lineitem/%d/%d#this" (in l_orderkey integer not null, in l_linenumber integer not null) option (bijection, deref) .
create iri class tpch:nation "http://^{URIQADefaultHost}^/tpch/nation/%U%d#this" (in name varchar, in l_nationkey integer not null) option (bijection, deref) .
create iri class tpch:order "http://^{URIQADefaultHost}^/tpch/order/%d#this" (in o_orderkey integer not null) option (bijection, deref) .
create iri class tpch:part "http://^{URIQADefaultHost}^/tpch/part/%U%d#this" (in p_partname varchar, in p_partkey integer not null) option (bijection, deref) .
create iri class tpch:partsupp "http://^{URIQADefaultHost}^/tpch/partsupp/%d/%d#this" (in ps_partkey integer not null, in ps_suppkey integer not null) option (bijection, deref) .
create iri class tpch:region "http://^{URIQADefaultHost}^/tpch/region/%U%d#this" (in name varchar, in r_regionkey integer not null) option (bijection, deref) .
create iri class tpch:supplier "http://^{URIQADefaultHost}^/tpch/supplier/%U%d#this" (in name varchar, in s_supplierkey integer not null) option (bijection, deref) .
;
SPARQL
prefix tpch: <http://www.openlinksw.com/schemas/tpch#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
alter quad storage virtrdf:DefaultQuadStorage
FROM TPCH.DBA.LINEITEM as lineitems
FROM TPCH.DBA.CUSTOMER as customers
FROM TPCH.DBA.NATION as nations
FROM TPCH.DBA.ORDERS as orders
FROM TPCH.DBA.PART as parts
FROM TPCH.DBA.PARTSUPP as partsupps
FROM TPCH.DBA.REGION as regions
FROM TPCH.DBA.SUPPLIER as suppliers
where (^{suppliers.}^.S_NATIONKEY = ^{nations.}^.N_NATIONKEY)
where (^{customers.}^.C_NATIONKEY = ^{nations.}^.N_NATIONKEY)
{
create virtrdf:TPCH as graph iri ("http://^{URIQADefaultHost}^/tpch") option (exclusive)
{
# Customers
tpch:customer (customers.C_NAME, customers.C_CUSTKEY)
a tpch:customer
as virtrdf:customer-tpch-type ;
a foaf:Organization
as virtrdf:customer-foaf-type ;
tpch:custkey customers.C_CUSTKEY
as virtrdf:customer-c_custkey ;
foaf:name customers.C_NAME
as virtrdf:customer-foaf_name ;
tpch:companyName customers.C_NAME
as virtrdf:customer-c_name ;
tpch:has_nation tpch:nation (nations.N_NAME, customers.C_NATIONKEY)
as virtrdf:customer-c_nationkey ;
tpch:address customers.C_ADDRESS
as virtrdf:customer-c_address ;
foaf:phone customers.C_PHONE
as virtrdf:customer-foaf_phone ;
tpch:phone customers.C_PHONE
as virtrdf:customer-phone ;
tpch:acctbal customers.C_ACCTBAL
as virtrdf:customer-acctbal ;
tpch:mktsegment customers.C_MKTSEGMENT
as virtrdf:customer-c_mktsegment ;
tpch:comment customers.C_COMMENT
as virtrdf:customer-c_comment .
# Nations
tpch:nation (nations.N_NAME, customers.C_NATIONKEY)
tpch:nation_of tpch:customer (customers.C_NAME, customers.C_CUSTKEY)
as virtrdf:customer-nation_of .
tpch:lineitem (lineitems.L_ORDERKEY, lineitems.L_LINENUMBER)
a tpch:lineitem
as virtrdf:lineitem-lineitems ;
tpch:has_order tpch:order (lineitems.L_ORDERKEY)
as virtrdf:lineitem-l_orderkey ;
tpch:has_part tpch:part (parts.P_NAME, lineitems.L_PARTKEY)
where (^{parts.}^.P_PARTKEY = ^{lineitems.}^.L_PARTKEY)
as virtrdf:lineitem-l_partkey ;
tpch:has_supplier tpch:supplier (suppliers.S_NAME, lineitems.L_SUPPKEY)
where (^{suppliers.}^.S_SUPPKEY = ^{lineitems.}^.L_SUPPKEY)
as virtrdf:lineitem-l_suppkey ;
tpch:linenumber lineitems.L_LINENUMBER
as virtrdf:lineitem-l_linenumber ;
tpch:linequantity lineitems.L_QUANTITY
as virtrdf:lineitem-l_linequantity ;
tpch:lineextendedprice lineitems.L_EXTENDEDPRICE
as virtrdf:lineitem-l_lineextendedprice ;
tpch:linediscount lineitems.L_DISCOUNT
as virtrdf:lineitem-l_linediscount ;
tpch:linetax lineitems.L_TAX
as virtrdf:lineitem-l_linetax ;
tpch:returnflag lineitems.L_RETURNFLAG
as virtrdf:lineitem-l_returnflag ;
tpch:linestatus lineitems.L_LINESTATUS
as virtrdf:lineitem-l_linestatus ;
tpch:shipdate lineitems.L_SHIPDATE
as virtrdf:lineitem-l_shipdate ;
tpch:commitdate lineitems.L_COMMITDATE
as virtrdf:lineitem-l_commitdate ;
tpch:receiptdate lineitems.L_RECEIPTDATE
as virtrdf:lineitem-l_receiptdate ;
tpch:shipinstruct lineitems.L_SHIPINSTRUCT
as virtrdf:lineitem-l_shipinstruct ;
tpch:shipmode lineitems.L_SHIPMODE
as virtrdf:lineitem-l_shipmode ;
tpch:comment lineitems.L_COMMENT
as virtrdf:lineitem-l_comment .
tpch:part (parts.P_NAME, lineitems.L_PARTKEY)
tpch:part_of tpch:lineitem (lineitems.L_ORDERKEY, lineitems.L_LINENUMBER)
where (^{parts.}^.P_PARTKEY = ^{lineitems.}^.L_PARTKEY)
as virtrdf:lineitem-part_of .
tpch:order (lineitems.L_ORDERKEY)
tpch:order_of tpch:lineitem (lineitems.L_ORDERKEY, lineitems.L_LINENUMBER) as virtrdf:lineitem-order_of .
tpch:supplier (suppliers.S_NAME, lineitems.L_SUPPKEY)
tpch:supplier_of tpch:lineitem (lineitems.L_ORDERKEY, lineitems.L_LINENUMBER)
where (^{suppliers.}^.S_SUPPKEY = ^{lineitems.}^.L_SUPPKEY)
as virtrdf:lineitem-supplier_of .
# Nation
tpch:nation (nations.N_NAME, nations.N_NATIONKEY)
a tpch:nation
as virtrdf:nation-nations ;
tpch:name nations.N_NAME
as virtrdf:nation-n_name ;
tpch:has_region tpch:region (regions.R_NAME, nations.N_REGIONKEY)
where (^{regions.}^.R_REGIONKEY = ^{nations.}^.N_REGIONKEY)
as virtrdf:nation-n_regionkey ;
tpch:comment nations.N_COMMENT
as virtrdf:nation-n_comment .
tpch:region (regions.R_NAME, nations.N_REGIONKEY)
tpch:region_of tpch:nation (nations.N_NAME, nations.N_NATIONKEY)
where (^{regions.}^.R_REGIONKEY = ^{nations.}^.N_REGIONKEY)
as virtrdf:nation-region_of .
# Order
tpch:order (orders.O_ORDERKEY)
a tpch:order
as virtrdf:order-orders ;
tpch:orderkey orders.O_ORDERKEY
as virtrdf:order-o_orderkey ;
tpch:has_customer tpch:customer (customers.C_NAME, orders.O_CUSTKEY)
where (^{orders.}^.O_CUSTKEY = ^{customers.}^.C_CUSTKEY)
as virtrdf:order-o_custkey ;
tpch:orderstatus orders.O_ORDERSTATUS
as virtrdf:order-o_orderstatus ;
tpch:ordertotalprice orders.O_TOTALPRICE
as virtrdf:order-o_totalprice ;
tpch:orderdate orders.O_ORDERDATE
as virtrdf:order-o_orderdate ;
tpch:orderpriority orders.O_ORDERPRIORITY
as virtrdf:order-o_orderpriority ;
tpch:clerk orders.O_CLERK
as virtrdf:order-o_clerk ;
tpch:shippriority orders.O_SHIPPRIORITY
as virtrdf:order-o_shippriority ;
tpch:comment orders.O_COMMENT
as virtrdf:order-o_comment .
tpch:customer (customers.C_CUSTKEY, orders.O_CUSTKEY)
tpch:customer_of tpch:order (orders.O_ORDERKEY)
where (^{orders.}^.O_CUSTKEY = ^{customers.}^.C_CUSTKEY)
as virtrdf:order-customer_of .
# Part
tpch:part (parts.P_NAME, parts.P_PARTKEY)
a tpch:part
as virtrdf:part-parts ;
tpch:partkey parts.P_PARTKEY
as virtrdf:part-p_partkey ;
tpch:name parts.P_NAME
as virtrdf:part-p_name ;
tpch:mfgr parts.P_MFGR
as virtrdf:part-p_mfgr ;
tpch:brand parts.P_BRAND
as virtrdf:part-p_brand ;
tpch:type parts.P_TYPE
as virtrdf:part-p_type ;
tpch:size parts.P_SIZE
as virtrdf:part-p_size ;
tpch:container parts.P_CONTAINER
as virtrdf:part-p_container ;
tpch:comment parts.P_COMMENT
as virtrdf:part-p_comment .
# Partsupp
tpch:partsupp (partsupps.PS_PARTKEY, partsupps.PS_SUPPKEY)
a tpch:partsupp
as virtrdf:partsupp-partsupps ;
tpch:has_part tpch:part (parts.P_NAME, partsupps.PS_PARTKEY)
where (^{parts.}^.P_PARTKEY = ^{partsupps.}^.PS_PARTKEY)
as virtrdf:partsupp-ps_partkey ;
tpch:has_supplier tpch:supplier (suppliers.S_NAME, partsupps.PS_SUPPKEY)
where (^{suppliers.}^.S_SUPPKEY = ^{partsupps.}^.PS_SUPPKEY)
as virtrdf:partsupp-ps_suppkey ;
tpch:availqty partsupps.PS_AVAILQTY
as virtrdf:partsupp-ps_availqty ;
tpch:supplycost partsupps.PS_SUPPLYCOST
as virtrdf:partsupp-ps_supplycost ;
tpch:comment partsupps.PS_COMMENT
as virtrdf:partsupp-ps_comment .
tpch:part (parts.P_NAME, partsupps.PS_PARTKEY)
tpch:part_of tpch:partsupp (partsupps.PS_PARTKEY, partsupps.PS_SUPPKEY)
where (^{parts.}^.P_PARTKEY = ^{partsupps.}^.PS_PARTKEY)
as virtrdf:partsupp-part_of .
tpch:supplier (suppliers.S_NAME, partsupps.PS_SUPPKEY)
tpch:supplier_of tpch:partsupp (partsupps.PS_PARTKEY, partsupps.PS_SUPPKEY)
where (^{suppliers.}^.S_SUPPKEY = ^{partsupps.}^.PS_SUPPKEY)
as virtrdf:partsupp-supplier_of .
# Region
tpch:region (regions.R_NAME, regions.R_REGIONKEY)
a tpch:region
as virtrdf:region-regions ;
tpch:name regions.R_NAME
as virtrdf:region-r_name ;
tpch:comment regions.R_COMMENT
as virtrdf:region-r_comment .
# Supplier
tpch:supplier (suppliers.S_NAME, suppliers.S_SUPPKEY)
a tpch:supplier
as virtrdf:supplier-suppliers ;
tpch:name suppliers.S_NAME
as virtrdf:supplier-s_name ;
tpch:address suppliers.S_ADDRESS
as virtrdf:supplier-s_address ;
tpch:has_nation tpch:nation (nations.N_NAME, suppliers.S_NATIONKEY)
where (^{nations.}^.N_NATIONKEY = ^{suppliers.}^.S_NATIONKEY)
as virtrdf:supplier-s_nationkey ;
foaf:phone suppliers.S_PHONE
as virtrdf:supplier-foaf_phone ;
tpch:phone suppliers.S_PHONE
as virtrdf:supplier-s_phone ;
tpch:acctbal suppliers.S_ACCTBAL
as virtrdf:supplier-s_acctbal ;
tpch:comment suppliers.S_COMMENT
as virtrdf:supplier-s_comment .
tpch:nation (nations.N_NAME, suppliers.S_NATIONKEY)
tpch:nation_of tpch:supplier (suppliers.S_NAME, suppliers.S_SUPPKEY)
where (^{nations.}^.N_NATIONKEY = ^{suppliers.}^.S_NATIONKEY)
as virtrdf:supplier-nation_of .
} .
} .
;
DELETE FROM db.dba.url_rewrite_rule_list WHERE urrl_list like 'tpch_rule%';
DELETE FROM db.dba.url_rewrite_rule WHERE urr_rule like 'tpch_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tpch_rule2',
1,
'([^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/tpch%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tpch_rule1',
1,
'([^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s%%23this',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tpch_rule3',
1,
'(/[^#]*)/\x24',
vector('path'),
1,
'%s',
vector('path'),
null,
null,
0,
null
);
create procedure DB.DBA.REMOVE_TPCH_RDF_DET()
{
declare colid int;
colid := DAV_SEARCH_ID('/DAV/home/demo/tpch', 'C');
if (colid < 0)
return;
update WS.WS.SYS_DAV_COL set COL_DET=null where COL_ID = colid;
}
;
DB.DBA.REMOVE_TPCH_RDF_DET();
drop procedure DB.DBA.REMOVE_TPCH_RDF_DET;
create procedure DB.DBA.TPCH_MAKE_RDF_DET()
{
declare uriqa_str varchar;
uriqa_str := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
uriqa_str := 'http://' || uriqa_str || '/tpch';
DB.DBA."RDFData_MAKE_DET_COL" ('/DAV/home/demo/tpch/RDFData/', uriqa_str, NULL);
VHOST_REMOVE (lpath=>'/tpch/data/rdf');
DB.DBA.VHOST_DEFINE (lpath=>'/tpch/data/rdf', ppath=>'/DAV/home/demo/tpch/RDFData/All/', is_dav=>1, vsp_user=>'dba');
}
;
DB.DBA.TPCH_MAKE_RDF_DET();
drop procedure DB.DBA.TPCH_MAKE_RDF_DET;
create procedure DB.DBA.TPCH_DET_REF (in par varchar, in fmt varchar, in val varchar)
{
declare res, iri any;
declare uriqa_str varchar;
uriqa_str := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
uriqa_str := 'http://' || uriqa_str || '/tpch';
iri := uriqa_str || val;
res := sprintf ('iid (%d).rdf', iri_id_num (iri_to_id (iri)));
return sprintf (fmt, res);
}
;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('tpch_rdf', 1,
'/tpch/(.*)', vector('path'), 1,
'/tpch/data/rdf/%U', vector('path'),
'DB.DBA.TPCH_DET_REF',
'application/rdf.xml',
2,
303);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'tpch_rule_list1',
1,
vector (
'tpch_rule1',
'tpch_rule2',
'tpch_rule3',
'tpch_rdf'
));
DB.DBA.VHOST_REMOVE (lpath=>'/tpch');
DB.DBA.VHOST_DEFINE (lpath=>'/tpch', ppath=>'/DAV/home/demo/tpch/', vsp_user=>'dba', is_dav=>1,
is_brws=>0, opts=>vector ('url_rewrite', 'tpch_rule_list1'));
DB.DBA.VHOST_REMOVE (lpath=>'/tpch/linkeddata');
DB.DBA.VHOST_DEFINE (lpath=>'/tpch/linkeddata', ppath=>'/DAV/home/demo/tpch/', vsp_user=>'dba', is_dav=>1,
is_brws=>1);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsbusinttpcd">
<title>TPCD to RDF</title>
<para>Please load ~\binsrc\dav\DET_RDFData.sql before loadding this script (tpc-d has no vad to do this automatic)</para>
<programlisting><![CDATA[
use DB;
create procedure DB.DBA.exec_no_error (in expr varchar) {
declare state, message, meta, result any;
exec(expr, state, message, vector(), 0, meta, result);
}
;
DB.DBA.exec_no_error('GRANT \"SPARQL_UPDATE\" TO \"SPARQL\"')
;
GRANT SELECT ON tpcd.DBA.partsupp TO "SPARQL";
GRANT SELECT ON tpcd.DBA.supplier TO "SPARQL";
GRANT SELECT ON tpcd.DBA.customer TO "SPARQL";
GRANT SELECT ON tpcd.DBA.history TO "SPARQL";
GRANT SELECT ON tpcd.DBA.part TO "SPARQL";
GRANT SELECT ON tpcd.DBA.lineitem TO "SPARQL";
GRANT SELECT ON tpcd.DBA.orders TO "SPARQL";
GRANT SELECT ON tpcd.DBA.nation TO "SPARQL";
GRANT SELECT ON tpcd.DBA.region TO "SPARQL";
--SPARQL
--prefix tpcd: <http://demo.openlinksw.com/schemas/tpcd#>
--prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
--prefix sioc: <http://rdfs.org/sioc/ns#>
--prefix foaf: <http://xmlns.com/foaf/0.1/>
--prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
--drop quad map graph iri("http://^{URIQADefaultHost}^/tpcd") .
--;
SPARQL
prefix tpcd: <http://demo.openlinksw.com/schemas/tpcd#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
drop silent quad map virtrdf:TpcdDemo .
;
SPARQL
prefix tpcd: <http://demo.openlinksw.com/schemas/tpcd#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
create iri class tpcd:customer "http://^{URIQADefaultHost}^/tpcd/customer/%d#this" (in c_custkey integer not null) .
create iri class tpcd:lineitem "http://^{URIQADefaultHost}^/tpcd/lineitem/%d/%d#this" (in l_orderkey integer not null, in l_linenumber integer not null) .
create iri class tpcd:nation "http://^{URIQADefaultHost}^/tpcd/nation/%d#this" (in l_nationkey integer not null) .
create iri class tpcd:order "http://^{URIQADefaultHost}^/tpcd/order/%d#this" (in o_orderkey integer not null) .
create iri class tpcd:part "http://^{URIQADefaultHost}^/tpcd/part/%d#this" (in p_partkey integer not null) .
create iri class tpcd:partsupp "http://^{URIQADefaultHost}^/tpcd/partsupp/%d/%d#this" (in ps_partkey integer not null, in ps_suppkey integer not null) .
create iri class tpcd:region "http://^{URIQADefaultHost}^/tpcd/region/%d#this" (in r_regionkey integer not null) .
create iri class tpcd:supplier "http://^{URIQADefaultHost}^/tpcd/supplier/%d#this" (in s_supplierkey integer not null) .
;
SPARQL
prefix tpcd: <http://demo.openlinksw.com/schemas/tpcd#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
alter quad storage virtrdf:DefaultQuadStorage
from tpcd.DBA.lineitem as lineitems
from tpcd.DBA.customer as customers
from tpcd.DBA.nation as nations
from tpcd.DBA.orders as orders
from tpcd.DBA.part as parts
from tpcd.DBA.partsupp as partsupps
from tpcd.DBA.region as regions
from tpcd.DBA.supplier as suppliers
where (^{suppliers.}^.s_nationkey = ^{nations.}^.n_nationkey)
where (^{customers.}^.c_nationkey = ^{nations.}^.n_nationkey)
{
create virtrdf:TpcdDemo as graph iri ("http://^{URIQADefaultHost}^/tpcd") option (exclusive)
{
# Customers
tpcd:customer (customers.c_custkey)
a tpcd:customer
as virtrdf:tpcdcustomer-type ;
a foaf:Organization
as virtrdf:tpcdcustomer-foaf-type ;
tpcd:custkey customers.c_custkey
as virtrdf:tpcdcustomer-c_custkey ;
foaf:name customers.c_name
as virtrdf:tpcdcustomer-foaf_name ;
tpcd:companyName customers.c_name
as virtrdf:tpcdcustomer-c_name ;
tpcd:has_nation tpcd:nation (customers.c_nationkey)
as virtrdf:tpcdcustomer-c_nationkey ;
tpcd:address customers.c_address
as virtrdf:tpcdcustomer-c_address ;
foaf:phone customers.c_phone
as virtrdf:tpcdcustomer-foaf_phone ;
tpcd:phone customers.c_phone
as virtrdf:tpcdcustomer-phone ;
tpcd:acctbal customers.c_acctbal
as virtrdf:tpcdcustomer-acctbal ;
tpcd:mktsegment customers.c_mktsegment
as virtrdf:tpcdcustomer-c_mktsegment ;
tpcd:comment customers.c_comment
as virtrdf:tpcdcustomer-c_comment .
# Nations
tpcd:nation (customers.c_nationkey)
tpcd:nation_of tpcd:customer (customers.c_custkey) as virtrdf:tpcdcustomer-nation_of .
# Lineitems
tpcd:lineitem (lineitems.l_orderkey, lineitems.l_linenumber)
a tpcd:lineitem
as virtrdf:tpcdlineitem-lineitems ;
tpcd:has_order tpcd:order (lineitems.l_orderkey)
as virtrdf:tpcdlineitem-l_orderkey ;
tpcd:has_part tpcd:part (lineitems.l_partkey)
as virtrdf:tpcdlineitem-l_partkey ;
tpcd:has_supplier tpcd:supplier (lineitems.l_suppkey)
as virtrdf:tpcdlineitem-l_suppkey ;
tpcd:linenumber lineitems.l_linenumber
as virtrdf:tpcdlineitem-l_linenumber ;
tpcd:linequantity lineitems.l_quantity
as virtrdf:tpcdlineitem-l_linequantity ;
tpcd:lineextendedprice lineitems.l_extendedprice
as virtrdf:tpcdlineitem-l_lineextendedprice ;
tpcd:linediscount lineitems.l_discount
as virtrdf:tpcdlineitem-l_linediscount ;
tpcd:linetax lineitems.l_tax
as virtrdf:tpcdlineitem-l_linetax ;
tpcd:returnflag lineitems.l_returnflag
as virtrdf:tpcdlineitem-l_returnflag ;
tpcd:linestatus lineitems.l_linestatus
as virtrdf:tpcdlineitem-l_linestatus ;
tpcd:shipdate lineitems.l_shipdate
as virtrdf:tpcdlineitem-l_shipdate ;
tpcd:commitdate lineitems.l_commitdate
as virtrdf:tpcdlineitem-l_commitdate ;
tpcd:receiptdate lineitems.l_receiptdate
as virtrdf:tpcdlineitem-l_receiptdate ;
tpcd:shipinstruct lineitems.l_shipinstruct
as virtrdf:tpcdlineitem-l_shipinstruct ;
tpcd:shipmode lineitems.l_shipmode
as virtrdf:tpcdlineitem-l_shipmode ;
tpcd:comment lineitems.l_comment
as virtrdf:tpcdlineitem-l_comment .
tpcd:part (lineitems.l_partkey)
tpcd:part_of tpcd:lineitem (lineitems.l_orderkey, lineitems.l_linenumber) as virtrdf:tpcdlineitem-part_of .
tpcd:order (lineitems.l_orderkey)
tpcd:order_of tpcd:lineitem (lineitems.l_orderkey, lineitems.l_linenumber) as virtrdf:tpcdlineitem-order_of .
tpcd:supplier (lineitems.l_suppkey)
tpcd:supplier_of tpcd:lineitem (lineitems.l_orderkey, lineitems.l_linenumber) as virtrdf:tpcdlineitem-supplier_of .
# Nation
tpcd:nation (nations.n_nationkey)
a tpcd:nation
as virtrdf:tpcdnation-nations ;
tpcd:name nations.n_name
as virtrdf:tpcdnation-n_name ;
tpcd:has_region tpcd:region (nations.n_regionkey)
as virtrdf:tpcdnation-n_regionkey ;
tpcd:comment nations.n_comment
as virtrdf:tpcdnation-n_comment .
tpcd:region (nations.n_regionkey)
tpcd:region_of tpcd:nation (nations.n_nationkey) as virtrdf:tpcdnation-region_of .
# Order
tpcd:order (orders.o_orderkey)
a tpcd:order
as virtrdf:tpcdorder-orders ;
tpcd:orderkey orders.o_orderkey
as virtrdf:tpcdorder-o_orderkey ;
tpcd:has_customer tpcd:customer (orders.o_custkey)
as virtrdf:tpcdorder-o_custkey ;
tpcd:orderstatus orders.o_orderstatus
as virtrdf:tpcdorder-o_orderstatus ;
tpcd:ordertotalprice orders.o_totalprice
as virtrdf:tpcdorder-o_totalprice ;
tpcd:orderdate orders.o_orderdate
as virtrdf:tpcdorder-o_orderdate ;
tpcd:orderpriority orders.o_orderpriority
as virtrdf:tpcdorder-o_orderpriority ;
tpcd:clerk orders.o_clerk
as virtrdf:tpcdorder-o_clerk ;
tpcd:shippriority orders.o_shippriority
as virtrdf:tpcdorder-o_shippriority ;
tpcd:comment orders.o_comment
as virtrdf:tpcdorder-o_comment .
tpcd:customer (orders.o_custkey)
tpcd:customer_of tpcd:order (orders.o_orderkey) as virtrdf:tpcdorder-customer_of .
# Part
tpcd:part (parts.p_partkey)
a tpcd:part
as virtrdf:tpcdpart-parts ;
tpcd:partkey parts.p_partkey
as virtrdf:tpcdpart-p_partkey ;
tpcd:name parts.p_name
as virtrdf:tpcdpart-p_name ;
tpcd:mfgr parts.p_mfgr
as virtrdf:tpcdpart-p_mfgr ;
tpcd:brand parts.p_brand
as virtrdf:tpcdpart-p_brand ;
tpcd:type parts.p_type
as virtrdf:tpcdpart-p_type ;
tpcd:size parts.p_size
as virtrdf:tpcdpart-p_size ;
tpcd:container parts.p_container
as virtrdf:tpcdpart-p_container ;
tpcd:comment parts.p_comment
as virtrdf:tpcdpart-p_comment .
# Partsupp
tpcd:partsupp (partsupps.ps_partkey, partsupps.ps_suppkey)
a tpcd:partsupp
as virtrdf:tpcdpartsupp-partsupps ;
tpcd:has_part tpcd:part (partsupps.ps_partkey)
as virtrdf:tpcdpartsupp-ps_partkey ;
tpcd:has_supplier tpcd:supplier (partsupps.ps_suppkey)
as virtrdf:tpcdpartsupp-ps_suppkey ;
tpcd:availqty partsupps.ps_availqty
as virtrdf:tpcdpartsupp-ps_availqty ;
tpcd:supplycost partsupps.ps_supplycost
as virtrdf:tpcdpartsupp-ps_supplycost ;
tpcd:comment partsupps.ps_comment
as virtrdf:tpcdpartsupp-ps_comment .
tpcd:part (partsupps.ps_partkey)
tpcd:part_of tpcd:partsupp (partsupps.ps_partkey, partsupps.ps_suppkey) as virtrdf:tpcdpartsupp-part_of .
tpcd:supplier (partsupps.ps_suppkey)
tpcd:supplier_of tpcd:partsupp (partsupps.ps_partkey, partsupps.ps_suppkey) as virtrdf:tpcdpartsupp-supplier_of .
# Region
tpcd:region (regions.r_regionkey)
a tpcd:region
as virtrdf:tpcdregion-regions ;
tpcd:name regions.r_name
as virtrdf:tpcdregion-r_name ;
tpcd:comment regions.r_comment
as virtrdf:tpcdregion-r_comment .
# Supplier
tpcd:supplier (suppliers.s_suppkey)
a tpcd:supplier
as virtrdf:tpcdsupplier-suppliers ;
tpcd:name suppliers.s_name
as virtrdf:tpcdsupplier-s_name ;
tpcd:address suppliers.s_address
as virtrdf:tpcdsupplier-s_address ;
tpcd:has_nation tpcd:nation (suppliers.s_nationkey)
as virtrdf:tpcdsupplier-s_nationkey ;
foaf:phone suppliers.s_phone
as virtrdf:tpcdsupplier-foaf_phone ;
tpcd:phone suppliers.s_phone
as virtrdf:tpcdsupplier-s_phone ;
tpcd:acctbal suppliers.s_acctbal
as virtrdf:tpcdsupplier-s_acctbal ;
tpcd:comment suppliers.s_comment
as virtrdf:tpcdsupplier-s_comment .
tpcd:nation (suppliers.s_nationkey)
tpcd:nation_of tpcd:supplier (suppliers.s_suppkey) as virtrdf:tpcdsupplier-nation_of .
}
}
;
create procedure tcpd_rdf_doc (in path varchar)
{
declare r any;
r := regexp_match ('[^/]*\x24', path);
return r||'#this';
};
create procedure tcpd_html_doc (in path varchar)
{
declare r any;
r := regexp_match ('[^/]*#', path);
return subseq (r, 0, length (r)-1);
};
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tcpd_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/tpcd%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tcpd_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/rdfbrowser/index.html?uri=http%%3A//^{URIQADefaultHost}^%U%%23this',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tcpd_rule3',
1,
'(/[^#]*)/\x24',
vector('path'),
1,
'%s',
vector('path'),
null,
null,
0,
null
);
DB.DBA."RDFData_MAKE_DET_COL" ('/DAV/home/tpcd/RDFData/', 'http://^{URIQADefaultHost}^/tpcd', NULL);
VHOST_REMOVE (lpath=>'/tpcd/data/rdf');
DB.DBA.VHOST_DEFINE (lpath=>'/tpcd/data/rdf', ppath=>'/DAV/home/tpcd/RDFData/All/', is_dav=>1, vsp_user=>'dba');
-- procedure to convert path to DET resource name
create procedure DB.DBA.TPCD_DET_REF (in par varchar, in fmt varchar, in val varchar)
{
declare res, iri any;
iri := 'http://^{URIQADefaultHost}^/tpcd' || val;
res := sprintf ('iid (%d).rdf', iri_id_num (iri_to_id (iri)));
return sprintf (fmt, res);
}
;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('tpcd_rdf', 1,
'/tpcd/(.*)', vector('path'), 1,
'/tpcd/data/rdf/%U', vector('path'),
'DB.DBA.TPCD_DET_REF',
'application/rdf.xml',
2,
303);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'tpcd_rule_list1',
1,
vector (
'tcpd_rule1',
'tcpd_rule2',
'tcpd_rule3',
'tpcd_rdf'
));
VHOST_REMOVE (lpath=>'/tpcd');
DB.DBA.VHOST_DEFINE (lpath=>'/tpcd', ppath=>'/DAV/home/', vsp_user=>'dba', is_dav=>1, def_page=>'sfront.vspx',
is_brws=>0, opts=>vector ('url_rewrite', 'tpcd_rule_list1'));
create procedure DB.DBA.LOAD_TPCD_ONTOLOGY_FROM_DAV()
{
declare content, urihost varchar;
select cast (RES_CONTENT as varchar) into content from WS.WS.SYS_DAV_RES where RES_FULL_PATH = '/DAV/VAD/tpcd/tpcd.owl';
DB.DBA.RDF_LOAD_RDFXML (content, 'http://demo.openlinksw.com/schemas/tpcd#', 'http://demo.openlinksw.com/schemas/TPCDOntology/1.0/');
urihost := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
if (urihost = 'demo.openlinksw.com')
{
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/tpcd');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/tpcd', ppath=>'/DAV/VAD/tpcd/tpcd.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
}
}
;
DB.DBA.LOAD_TPCD_ONTOLOGY_FROM_DAV()
;
drop procedure DB.DBA.LOAD_TPCD_ONTOLOGY_FROM_DAV
;
XML_SET_NS_DECL ('virt-tpcd', 'http://demo.openlinksw.com/schemas/tpcd#', 2)
;
]]></programlisting>
</sect4>
<sect4 id="rdfviewsbusintthalia">
<title>Thalia to RDF</title>
<programlisting><![CDATA[
use DB
;
SPARQL drop quad map virtrdf:ThaliaDemo
;
create procedure DB.DBA.SPARQL_THALIA_RUN (in txt varchar)
{
declare REPORT, stat, msg, sqltext varchar;
declare metas, rowset any;
result_names (REPORT);
sqltext := string_output_string (sparql_to_sql_text (txt));
stat := '00000';
msg := '';
rowset := null;
exec (sqltext, stat, msg, vector (), 1000, metas, rowset);
}
;
create procedure DB.DBA.exec_no_error(in expr varchar)
{
declare state, message, meta, result any;
exec(expr, state, message, vector(), 0, meta, result);
}
;
DB.DBA.exec_no_error('drop View thalia.Demo.asu_v');
DB.DBA.exec_no_error('create View thalia.Demo.asu_v as select left(Title,3) code,* from thalia.Demo.asu');
DB.DBA.exec_no_error('drop View thalia.Demo.gatech_v');
DB.DBA.exec_no_error('create View thalia.Demo.gatech_v as select *, Room||\' \'||Building Place from thalia.Demo.gatech');
DB.DBA.SPARQL_THALIA_RUN('drop quad map graph iri("http://^{URIQADefaultHost}^/Thalia") .
')
;
GRANT SELECT ON thalia.Demo.asu TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.asu_v TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.brown TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.cmu TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.gatech TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.gatech_v TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.toronto TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.ucsd TO "SPARQL"
;
GRANT SELECT ON thalia.Demo.umd TO "SPARQL"
;
DB.DBA.SPARQL_THALIA_RUN('drop quad map graph iri("http://^{URIQADefaultHost}^/thalia") .
');
DB.DBA.SPARQL_THALIA_RUN('drop quad map virtrdf:ThaliaDemo .
');
DB.DBA.SPARQL_THALIA_RUN('
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix dc: <http://purl.org/dc/elements/1.1/>
prefix time: <http://www.w3.org/2006/time#>
prefix event: <http://purl.org/NET/c4dm/event.owl#>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix skos: <http://www.w3.org/2004/02/skos/core#>
prefix th: <http://demo.openlinksw.com/schemas/thalia#>
create iri class th:Asu "http://^{URIQADefaultHost}^/thalia/asu/course/%U#this" (in code varchar not null) .
create iri class th:Brown "http://^{URIQADefaultHost}^/thalia/brown/course/%U#this" (in Code varchar not null) .
create iri class th:BrownInstructor "http://^{URIQADefaultHost}^/thalia/brown/instructor/%U#this" (in Code varchar not null) .
create iri class th:BrownLecture "http://^{URIQADefaultHost}^/thalia/brown/lecture/%U#this" (in Code varchar not null) .
create iri class th:BrownPlace "http://^{URIQADefaultHost}^/thalia/brown/place/%U#this" (in Code varchar not null) .
create iri class th:Cmu "http://^{URIQADefaultHost}^/thalia/cmu/course/%U/%U#this" (in Code varchar not null, in Sec varchar) .
create iri class th:CmuInstructor "http://^{URIQADefaultHost}^/thalia/cmu/instructor/%U/%U#this" (in Code varchar not null, in Sec varchar) .
create iri class th:CmuLecture "http://^{URIQADefaultHost}^/thalia/cmu/lecture/%U/%U#this" (in Code varchar not null, in Sec varchar) .
create iri class th:CmuPlace "http://^{URIQADefaultHost}^/thalia/cmu/place/%U/%U#this" (in Code varchar not null, in Sec varchar) .
create iri class th:CmuEventTime "http://^{URIQADefaultHost}^/thalia/cmu/eventtime/%U/%U#this" (in Code varchar not null, in Sec varchar) .
create iri class th:CmuDatetime "http://^{URIQADefaultHost}^/thalia/cmu/datetime/%U/%U#this" (in Code varchar not null, in Sec varchar) .
create iri class th:Gatech "http://^{URIQADefaultHost}^/thalia/gatech/course/%U/%d/%U#this" (in Department varchar, in Code integer, in Section varchar) .
create iri class th:GatechInstructor "http://^{URIQADefaultHost}^/thalia/gatech/instructor/%U/%d/%U#this" (in Department varchar, in Code integer, in Section varchar) .
create iri class th:GatechLecture "http://^{URIQADefaultHost}^/thalia/gatech/lecture/%U/%d/%U#this" (in Department varchar, in Code integer, in Section varchar) .
create iri class th:GatechEventTime "http://^{URIQADefaultHost}^/thalia/gatech/eventtime/%U/%d/%U#this" (in Department varchar, in Code integer, in Section varchar) .
create iri class th:GatechDatetime "http://^{URIQADefaultHost}^/thalia/gatech/datetime/%U/%d/%U#this" (in Department varchar, in Code integer, in Section varchar) .
create iri class th:GatechPlace "http://^{URIQADefaultHost}^/thalia/gatech/place/%U/%d/%U#this" (in Department varchar, in Code integer, in Section varchar) .
create iri class th:Toronto "http://^{URIQADefaultHost}^/thalia/toronto/course/%U#this" (in No_ varchar) .
create iri class th:TorontoInstructor "http://^{URIQADefaultHost}^/thalia/toronto/instructor/%U#this" (in No_ varchar) .
create iri class th:TorontoLecture "http://^{URIQADefaultHost}^/thalia/toronto/lecture/%U#this" (in No_ varchar) .
create iri class th:TorontoPlace "http://^{URIQADefaultHost}^/thalia/toronto/place/%U#this" (in No_ varchar) .
create iri class th:Ucsd "http://^{URIQADefaultHost}^/thalia/ucsd/course/%U#this" (in Number varchar) .
create iri class th:UcsdInstructor1 "http://^{URIQADefaultHost}^/thalia/ucsd/instructor1/%U#this" (in Number varchar) .
create iri class th:UcsdInstructor2 "http://^{URIQADefaultHost}^/thalia/ucsd/instructor2/%U#this" (in Number varchar) .
create iri class th:UcsdInstructor3 "http://^{URIQADefaultHost}^/thalia/ucsd/instructor3/%U#this" (in Number varchar) .
create iri class th:Umd "http://^{URIQADefaultHost}^/thalia/umd/course/%U#this" (in Code varchar) .
create iri class th:UmdLecture "http://^{URIQADefaultHost}^/thalia/umd/lecture/%U#this" (in Code varchar) .
create iri class th:UmdEventTime "http://^{URIQADefaultHost}^/thalia/umd/eventtime/%U#this" (in Code varchar) .
create iri class th:UmdDatetime "http://^{URIQADefaultHost}^/thalia/umd/datetime/%U#this" (in Code varchar) .
')
;
DB.DBA.SPARQL_THALIA_RUN('prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix xsd: <http://www.w3.org/2001/XMLSchema#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix dc: <http://purl.org/dc/elements/1.1/>
prefix time: <http://www.w3.org/2006/time#>
prefix event: <http://purl.org/NET/c4dm/event.owl#>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix skos: <http://www.w3.org/2004/02/skos/core#>
prefix th: <http://demo.openlinksw.com/schemas/thalia#>
alter quad storage virtrdf:DefaultQuadStorage
from thalia.demo.asu_v as asus
from thalia.demo.brown as browns
from thalia.demo.cmu as cmus
from thalia.demo.gatech_v as gatechs
from thalia.demo.toronto as torontos
from thalia.demo.ucsd as ucsds
from thalia.demo.umd as umds
{
create virtrdf:ThaliaDemo as graph iri ("http://^{URIQADefaultHost}^/thalia") option (exclusive)
{
th:Asu (asus.code)
a th:Course
as virtrdf:Asu-Course ;
dc:title asus.Title
as virtrdf:Asu-Title ;
dc:description asus.Description
as virtrdf:Asu-Description ;
rdfs:seeAlso asus.MoreInfoURL
as virtrdf:Asu-MoreInfoURL ;
th:forUniversity "http://purl.org/thalia/university/asu/university/asu"
as virtrdf:Asu-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Asu-Subject
.
th:Brown (browns.Code)
a th:Course
as virtrdf:Brown-Course ;
dc:title browns.Title
as virtrdf:Brown-Title ;
th:hasInstructor th:BrownInstructor (browns.Code)
as virtrdf:Brown-hasInstructor ;
th:hasLecture th:BrownLecture(browns.Code)
as virtrdf:Brown-hasLecture ;
th:forUniversity "http://purl.org/thalia/university/brown"
as virtrdf:Brown-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Brown-Subject
.
th:BrownInstructor (browns.Code)
a th:Instructor
as virtrdf:Brown-Instructor ;
dc:homepage browns.Instructor
as virtrdf:Brown-Instructor-Homepage
.
th:BrownLecture (browns.Code)
a event:Event
as virtrdf:Brown-Lecture ;
event:place th:BrownPlace(browns.Code)
as virtrdf:Brown-hasPlace
.
th:BrownPlace (browns.Code)
a geo:Point
as virtrdf:Brown-Place;
dc:title browns.Room
as virtrdf:Brown-Room
.
th:Cmu (cmus.Code, cmus.Sec)
a th:Course
as virtrdf:Cmu-Course ;
dc:title cmus.CourseTitle
as virtrdf:Cmu-CourseTitle ;
th:hasInstructor th:CmuInstructor (cmus.Code, cmus.Sec)
as virtrdf:Cmu-hasInstructor ;
th:hasLecture th:CmuLecture(cmus.Code, cmus.Sec)
as virtrdf:Cmu-hasLecture ;
th:hasUnits cmus.Units
as virtrdf:Cmu-hasUnits ;
th:forUniversity "http://purl.org/thalia/university/cmu"
as virtrdf:Cmu-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Cmu-Subject
.
th:CmuInstructor (cmus.Code, cmus.Sec)
a th:Instructor
as virtrdf:Cmu-Instructor ;
foaf:name cmus.Lecturer
as virtrdf:Cmu-Lecturer
.
th:CmuLecture (cmus.Code, cmus.Sec)
a event:Event
as virtrdf:Cmu-Lecture ;
event:time th:CmuEventTime(cmus.Code, cmus.Sec)
as virtrdf:Cmu-hasEventTime ;
event:place th:CmuPlace(cmus.Code, cmus.Sec)
as virtrdf:Cmu-hasPlace
.
th:CmuPlace (cmus.Code, cmus.Sec)
a geo:Point
as virtrdf:Cmu-Place;
dc:title cmus.Room
as virtrdf:Cmu-Room
.
th:CmuEventTime (cmus.Code, cmus.Sec)
a time:Interval
as virtrdf:Cmu-EventTime;
time:inDateTime th:CmuDatetime(cmus.Code, cmus.Sec)
as virtrdf:Cmu-inDateTime
.
th:CmuDatetime (cmus.Code, cmus.Sec)
a time:DateTimeDescription
as virtrdf:Cmu-Datetime;
time:dayOfWeek cmus.Day_
as virtrdf:Cmu-Day ;
time:hour cmus.Time_
as virtrdf:Cmu-Time
.
th:Gatech (gatechs.Department, gatechs.Code, gatechs.Section)
a th:Course
as virtrdf:Gatech-Course ;
dc:title gatechs.Title
as virtrdf:Gatech-Title ;
th:hasInstructor th:GatechInstructor(gatechs.Department, gatechs.Code, gatechs.Section)
as virtrdf:Gatech-hasInstructor ;
dc:description gatechs.Description
as virtrdf:Gatech-Description ;
th:hasLecture th:GatechLecture(gatechs.Department, gatechs.Code, gatechs.Section)
as virtrdf:Gatech-hasLecture ;
th:forUniversity "http://purl.org/thalia/university/gatech"
as virtrdf:Gatech-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Gatech-Subject
.
th:GatechInstructor (gatechs.Department, gatechs.Code, gatechs.Section)
a th:Instructor
as virtrdf:Gatech-Instructor ;
foaf:name gatechs.Instructor
as virtrdf:Gatech-InstructorName
.
th:GatechLecture (gatechs.Department, gatechs.Code, gatechs.Section)
a event:Event
as virtrdf:Gatech-Lecture ;
event:time th:GatechEventTime(gatechs.Department, gatechs.Code, gatechs.Section)
as virtrdf:Gatech-hasEventTime ;
event:place th:GatechPlace(gatechs.Department, gatechs.Code, gatechs.Section)
as virtrdf:Gatech-hasPlace
.
th:GatechEventTime (gatechs.Department, gatechs.Code, gatechs.Section)
a time:Interval
as virtrdf:Gatech-EventTime ;
time:inDateTime th:GatechDatetime(gatechs.Department, gatechs.Code, gatechs.Section)
as virtrdf:Gatech-inDateTime
.
th:GatechDatetime (gatechs.Department, gatechs.Code, gatechs.Section)
a time:DateTimeDescription
as virtrdf:Gatech-Datetime ;
time:dayOfWeek gatechs.Days
as virtrdf:Gatech-Days ;
time:hour gatechs.Time_
as virtrdf:Gatech-Time_
.
th:GatechPlace (gatechs.Department, gatechs.Code, gatechs.Section)
a geo:Point
as virtrdf:Gatech-Place ;
dc:title gatechs.Place
as virtrdf:Gatech-RoomBuilding
.
th:Toronto (torontos.No_)
a th:Course
as virtrdf:Toronto-Course ;
dc:title torontos.title
as virtrdf:Toronto-Title ;
dc:description torontos.text_
as virtrdf:Toronto-Description ;
th:hasInstructor th:TorontoInstructor(torontos.No_)
as virtrdf:Toronto-hasInstructor ;
th:hasLecture th:TorontoLecture(torontos.No_)
as virtrdf:Toronto-hasLecture ;
rdfs:seeAlso torontos.coursewebsite
as virtrdf:Toronto-CourseWebSite ;
th:hasPrerequisite torontos.prereq
as virtrdf:Toronto-prereq ;
th:text torontos.text_
as virtrdf:Toronto-text;
th:forUniversity "http://purl.org/thalia/university/toronto"
as virtrdf:Toronto-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Toronto-Subject
.
th:TorontoInstructor (torontos.No_)
a th:Instructor
as virtrdf:Toronto-Instructor ;
foaf:name torontos.instructorName
as virtrdf:Toronto-InstructorName ;
foaf:mbox torontos.instructorEmail
as virtrdf:Toronto-InstructorEmail
.
th:TorontoLecture (torontos.No_)
a event:Event
as virtrdf:Toronto-Lecture ;
event:place th:TorontoPlace(torontos.No_)
as virtrdf:Toronto-hasPlace
.
th:TorontoPlace (torontos.No_)
a geo:Point
as virtrdf:Toronto-Place ;
dc:title torontos.location
as virtrdf:Toronto-Location
.
th:Ucsd (ucsds.Number)
a th:Course
as virtrdf:Ucsd-Course ;
dc:title ucsds.Title
as virtrdf:Ucsd-Title ;
th:hasInstructor1 th:UcsdInstructor1 (ucsds.Number)
as virtrdf:Ucsd-hasInstructor1 ;
th:hasInstructor2 th:UcsdInstructor2 (ucsds.Number)
as virtrdf:Ucsd-hasInstructor2 ;
th:hasInstructor3 th:UcsdInstructor3 (ucsds.Number)
as virtrdf:Ucsd-hasInstructor3 ;
th:forUniversity "http://purl.org/thalia/university/ucsd"
as virtrdf:Ucsd-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Ucsd-Subject
.
th:UcsdInstructor1 (ucsds.Number)
a th:Instructor
as virtrdf:Ucsd-Instructor1 ;
foaf:name ucsds.Fall2003
as virtrdf:Ucsd-Instructor-Fall2003
.
th:UcsdInstructor2 (ucsds.Number)
a th:Instructor
as virtrdf:Ucsd-Instructor2 ;
foaf:name ucsds.Winter2004
as virtrdf:Ucsd-Instructor-Winter2004
.
th:UcsdInstructor3 (ucsds.Number)
a th:Instructor
as virtrdf:Ucsd-Instructor3 ;
foaf:name ucsds.Spring2004
as virtrdf:Ucsd-Instructor-Spring2004
.
th:Umd (umds.Code)
a th:Course
as virtrdf:Umd-Course ;
dc:title umds.CourseName
as virtrdf:Umd-Title ;
th:hasSection th:SectionTitle
as virtrdf:Umd-hasSection ;
th:hasLecture th:UmdLecture(umds.Code)
as virtrdf:Umd-hasLecture ;
th:forUniversity "http://purl.org/thalia/university/umd"
as virtrdf:Umd-University ;
skos:subject "http://purl.org/subject/thalia/ComputerScience"
as virtrdf:Umd-Subject
.
th:UmdLecture (umds.Code)
a event:Event
as virtrdf:Umd-Lecture ;
event:time th:UmdEventTime(umds.Code)
as virtrdf:Umd-hasEventTime
.
th:UmdEventTime (umds.Code)
a time:Interval
as virtrdf:Umd-EventTime ;
time:inDateTime th:UmdDatetime(umds.Code)
as virtrdf:Umd-inDateTime
.
th:UmdDatetime (umds.Code)
a time:DateTimeDescription
as virtrdf:Umd-Datetime ;
time:hour umds.SectionTime
as virtrdf:Umd-SectionTime
.
}
}
')
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'tut_th_%';
delete from db.dba.url_rewrite_rule where urr_rule like 'tut_th_%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tut_th_rule1',
1,
'([^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s%%01this',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tut_th_rule2',
1,
'([^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/thalia%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tut_th_rule3',
1,
'(/[^#]*)/\x24',
vector('path'),
1,
'%U',
vector('path'),
null,
null,
0,
null
);
create procedure DB.DBA.REMOVE_THALIA_RDF_DET()
{
declare colid int;
colid := DAV_SEARCH_ID('/DAV/Thalia', 'C');
if (colid < 0)
return;
update WS.WS.SYS_DAV_COL set COL_DET=null where COL_ID = colid;
}
;
DB.DBA.REMOVE_THALIA_RDF_DET();
drop procedure DB.DBA.REMOVE_THALIA_RDF_DET;
create procedure DB.DBA.THALIA_MAKE_RDF_DET()
{
declare uriqa_str varchar;
uriqa_str := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
uriqa_str := 'http://' || uriqa_str || '/thalia';
DB.DBA."RDFData_MAKE_DET_COL" ('/DAV/Thalia/RDFData/', uriqa_str, NULL);
VHOST_REMOVE (lpath=>'/thalia/data/rdf');
DB.DBA.VHOST_DEFINE (lpath=>'/thalia/data/rdf', ppath=>'/DAV/Thalia/RDFData/All/', is_dav=>1, vsp_user=>'dba');
}
;
DB.DBA.THALIA_MAKE_RDF_DET();
drop procedure DB.DBA.THALIA_MAKE_RDF_DET;
-- procedure to convert path to DET resource name
create procedure DB.DBA.THALIA_DET_REF (in par varchar, in fmt varchar, in val varchar)
{
declare res, iri any;
declare uriqa_str varchar;
uriqa_str := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
uriqa_str := 'http://' || uriqa_str || '/thalia';
iri := uriqa_str || replace(val, '/', '_');
res := sprintf ('iid (%d).rdf', iri_id_num (iri_to_id (iri)));
return sprintf (fmt, res);
}
;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('tut_th_rdf', 1,
'/thalia/(.*)', vector('path'), 1,
'/thalia/data/rdf/%U', vector('path'),
'DB.DBA.THALIA_DET_REF',
'application/rdf.xml',
2,
303);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'tut_th_rule_list1',
1,
vector (
'tut_th_rule1',
'tut_th_rule2',
'tut_th_rule3',
'tut_th_rdf'
));
DB.DBA.VHOST_REMOVE (lpath=>'/thalia');
DB.DBA.VHOST_DEFINE (lpath=>'/thalia', ppath=>'/DAV/Thalia/', vsp_user=>'dba', is_dav=>1,
is_brws=>0, opts=>vector ('url_rewrite', 'tut_th_rule_list1'));
create procedure DB.DBA.LOAD_THALIA_ONTOLOGY_FROM_DAV()
{
declare content, urihost varchar;
select cast (RES_CONTENT as varchar) into content from WS.WS.SYS_DAV_RES where RES_FULL_PATH = '/DAV/Thalia/thalia.owl';
DB.DBA.RDF_LOAD_RDFXML (content, 'http://demo.openlinksw.com/schemas/thalia#', 'http://demo.openlinksw.com/schemas/ThaliaOntology/1.0/');
urihost := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
if (urihost = 'demo.openlinksw.com')
{
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/thalia');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/thalia', ppath=>'/DAV/Thalia/thalia.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
}
}
;
DB.DBA.LOAD_THALIA_ONTOLOGY_FROM_DAV()
;
drop procedure DB.DBA.LOAD_THALIA_ONTOLOGY_FROM_DAV
;
DB.DBA.XML_SET_NS_DECL ('thalia', 'http://demo.openlinksw.com/schemas/thalia#', 2)
;
* Demo : Thalia test queries
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?room
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?title;
th:hasLecture ?lecture.
?lecture event:place [dc:title ?room].
FILTER regex(?title, "Software Engineering")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT ?day, ?hour ?course
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
th:hasLecture [event:time ?time];
dc:title ?title.
?time time:inDateTime [time:dayOfWeek ?day];
time:inDateTime [time:hour ?hour].
FILTER regex(?title, "Computer Networks")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?course
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?Title;
th:hasLecture ?lecture.
?lecture event:time [time:inDateTime ?dateTime].
?dateTime time:hour ?hour.
FILTER regex(?Title, "Database System")
FILTER regex(?hour, "1:30 - 2:50")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?course ?instructor ?name
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
th:hasInstructor ?instructor.
?instructor foaf:name ?name.
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?instructor
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
th:hasInstructor ?instructor;
dc:title ?title.
FILTER regex(?title, "Database")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?instructor
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?title;
th:hasInstructor ?instructor.
FILTER regex(?title, "Software")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT DISTINCT ?course
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?title;
th:forUniversity 'http://purl.org/thalia/university/umd'.
FILTER regex(?title, "Data Structures")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?course
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?Title;
th:hasUnits ?credits.
FILTER (xsd:integer(?credits) > 10)
FILTER regex(?Title, "Database")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?course
FORM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?title;
th:forUniversity 'http://purl.org/thalia/university/umd'.
FILTER regex(?title, "Database")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?course
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?Title;
th:hasUnits ?credits.
FILTER (xsd:integer(?credits) > 10)
FILTER regex(?Title, "Database")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX th: <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?text_
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:title ?title;
th:text ?text_.
FILTER regex(?title, "Verification")
}
#service:/sparql
#should-sponge:soft
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX event: <http://purl.org/NET/c4dm/event.owl#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX : <http://purl.org/ontology/thalia/1.0/>
SELECT distinct ?course
FROM <http://demo.openlinksw.com/thalia>
WHERE
{
?course a th:Course;
dc:description ?description;
th:forUniversity 'http://purl.org/thalia/university/gatech'.
FILTER regex(?description, "JR")
}
]]></programlisting>
</sect4>
<sect4 id="rdfviewsbusintmbr">
<title>Musicbrainz to RDF</title>
<para>The following code creates the Musicbrainz RDF Views Deployment and Demo Scripts:</para>
<programlisting><![CDATA[
create text index on ZITGIST.MO.artist ("name") with key id;
create text index on ZITGIST.MO.artistalias ("name") with key id;
create text index on ZITGIST.MO.album ("name") with key id;
create text index on ZITGIST.MO.track ("name") with key id;
vt_batch_update (fix_identifier_case ('ZITGIST.MO.artist'), 'ON', NULL);
vt_batch_update (fix_identifier_case ('ZITGIST.MO.artistalias'), 'ON', NULL);
vt_batch_update (fix_identifier_case ('ZITGIST.MO.album'), 'ON', NULL);
vt_batch_update (fix_identifier_case ('ZITGIST.MO.track'), 'ON', NULL);
VT_INC_INDEX_DB_MO_artist ();
VT_INC_INDEX_DB_MO_artistalias ();
VT_INC_INDEX_DB_MO_album ();
VT_INC_INDEX_DB_MO_track ();
]]></programlisting>
<para>Note: Making sure that the graphs and views are deleting to clean Virtuoso from the old definitions</para>
<programlisting><![CDATA[
SPARQL
drop quad storage virtrdf:MBZROOT.
;
SPARQL
prefix mbz: <http://musibrainz.org/schemas/mbz#>
drop literal class mbz:duration
;
SPARQL
prefix mbz: <http://musibrainz.org/schemas/mbz#>
drop literal class mbz:created.
drop literal class mbz:official_iri.
drop literal class mbz:bootleg_iri.
drop literal class mbz:promotion_iri.
drop literal class mbz:album_iri.
drop literal class mbz:single_iri.
drop literal class mbz:ep_iri.
drop literal class mbz:compilation_iri.
drop literal class mbz:soundtrack_iri.
drop literal class mbz:spokenword_iri.
drop literal class mbz:interview_iri.
drop literal class mbz:audiobook_iri.
drop literal class mbz:live_iri.
drop literal class mbz:remix_iri.
;
]]></programlisting>
<para>The following SPARQL query will fix an issue Virtuoso has with its JSO system. Perform this query for now, the issue should be fixed in a future release</para>
<programlisting><![CDATA[
SPARQL define input:storage ""
DELETE FROM GRAPH (iri(bif:JSO_SYS_GRAPH NIL)) { ?s virtrdf:version ?o }
WHERE { graph `iri(bif:JSO_SYS_GRAPH NIL)` {?s virtrdf:version ?o}};
SPARQL_RELOAD_QM_GRAPH();
]]></programlisting>
<para>Creation of IRIs classes.</para>
<programlisting><![CDATA[
SPARQL
prefix mbz: <http://musibrainz.org/schemas/mbz#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix dc: <http://purl.org/dc/elements/1.1/>
prefix bio: <http://vocab.org/bio/0.1/#>
prefix rel: <http://vocab.org/relationship/#>
prefix mo: <http://purl.org/ontology/mo/>
prefix timeline: <http://purl.org/NET/c4dm/timeline.owl#>
prefix event: <http://purl.org/NET/c4dm/event.owl#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix sim: <http://purl.org/ontology/sim/>
create iri class mbz:artist_iri "http://zitgist.com/music/artist/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:artist_birth_event_iri "http://zitgist.com/music/artist/birth/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:artist_death_event_iri "http://zitgist.com/music/artist/death/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:sim_link_iri "http://zitgist.com/music/artist/simlink/%U" (in gid varchar not null) option (bijection) .
#create iri class mbz:band_iri "http://zitgist.com/music/band/%U" (in gid varchar not null) option (bijection) .
#create iri class mbz:band_birth_event_iri "http://zitgist.com/music/band/birth/%U" (in gid varchar not null) option (bijection) .
#create iri class mbz:band_death_event_iri "http://zitgist.com/music/band/death/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:record_iri "http://zitgist.com/music/record/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:performance_iri "http://zitgist.com/music/performance/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:composition_iri "http://zitgist.com/music/composition/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:musicalwork_iri "http://zitgist.com/music/musicalwork/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:sound_iri "http://zitgist.com/music/sound/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:recording_iri "http://zitgist.com/music/recording/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:signal_iri "http://zitgist.com/music/signal/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:track_iri "http://zitgist.com/music/track/%U" (in gid varchar not null) option (bijection) .
create iri class mbz:image_iri "http://ec1.images-amazon.com/images/P/%U.01.MZZZZZZZ.jpg" (in image varchar not null) option (bijection) .
create iri class mbz:amazon_asin_iri "http://amazon.com/exec/obidos/ASIN/%U/searchcom07-20" (in gid varchar not null) option (bijection) .
create literal class mbz:created using
function ZITGIST.MO.RECORD_CREATION_DATE (in datestring varchar) returns varchar,
function ZITGIST.MO.RECORD_CREATION_DATE_INVERSE (in datestring varchar) returns varchar .
create iri class mbz:official_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_OFFICIAL (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/official') .
create iri class mbz:promotion_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_PROMOTION (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/promotion') .
create iri class mbz:bootleg_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_BOOTLEG (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/bootleg') .
create iri class mbz:album_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_ALBUM (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/album') .
create iri class mbz:single_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_SINGLE (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/single') .
create iri class mbz:ep_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_EP (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/ep') .
create iri class mbz:compilation_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_COMPILATION (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/compilation') .
create iri class mbz:soundtrack_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_SOUNDTRACK (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/soundtrack') .
create iri class mbz:spokenword_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_SPOKENWORD (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/spokenword') .
create iri class mbz:interview_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_INTERVIEW (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/interview') .
create iri class mbz:audiobook_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_AUDIOBOOK (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/audiobook') .
create iri class mbz:live_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_LIVE (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/live') .
create iri class mbz:remix_iri using
function ZITGIST.MO.RECORD_ATTRIBUTE_REMIX (in attributes varchar) returns varchar
option (returns 'http://purl.org/ontology/mo/remix') .
create iri class mbz:duration_iri "http://zitgist.com/music/track/duration/%U" (in gid varchar not null) .
create literal class mbz:duration using
function ZITGIST.MO.TRACK_DURATION (in duration integer) returns varchar ,
function ZITGIST.MO.TRACK_DURATION_INVERSE (in durationXSD varchar) returns integer .
create iri class mbz:geoname_country_iri "http://www.geonames.org/countries/#%U" (in country varchar not null) .
create iri class mbz:url_iri "%s" (in url varchar not null) .
create iri class mbz:mbz_release_url_iri "http://musicbrainz.org/release/%s.html" (in mbz_gid varchar not null) .
create iri class mbz:mbz_track_url_iri "http://musicbrainz.org/track/%s.html" (in mbz_gid varchar not null) .
create iri class mbz:mbz_artist_url_iri "http://musicbrainz.org/artist/%s.html" (in mbz_gid varchar not null) .
;
]]></programlisting>
<para><emphasis>List of functions used to compute some IRI classes:</emphasis></para>
<para>Note:These functions have been developed to handle some weird user cases of the Musicbrainz data model (like the Attribute column of the album table, etc).</para>
<programlisting><![CDATA[
create function ZITGIST.MO.TRACK_DURATION_INVERSE(in durationXSD varchar)
{
return null;
};
create function ZITGIST.MO.TRACK_DURATION(in duration integer)
{
declare minutes, seconds, milliseconds integer;
minutes := ((duration / 1000) / 60);
if(minutes >= 1)
{
minutes := cast(minutes as integer);
}
else
{
minutes := 0;
}
seconds := (duration / 1000) - (minutes * 60);
if(seconds >= 1)
{
seconds := cast(seconds as integer);
}
milliseconds := duration - (seconds * 1000) - (minutes * 60000);
return sprintf('PT%dM%dS', minutes, seconds);
}
;
create function ZITGIST.MO.RECORD_CREATION_DATE(in datestring varchar)
{
return sprintf('%sT00:00:00Z', datestring);
};
create function ZITGIST.MO.RECORD_CREATION_DATE_INVERSE(in datestring varchar)
{
declare pos integer;
pos := locate('T00:00:00Z', datestring) - 1;
return substring(datestring, 1, pos);
};
create function ZITGIST.MO.RECORD_ATTRIBUTE(in attribute integer, in attributes varchar)
{
declare attributes_array any;
attributes_array := split_and_decode(ltrim(rtrim(attributes, '}'), '{'), 0, '\0\0,');
foreach(int attr in attributes_array) do
{
attr := cast(attr as integer);
if(attr = attribute)
{
if(attr = 100) return 'http://purl.org/ontology/mo/official';
if(attr = 101) return 'http://purl.org/ontology/mo/promotion';
if(attr = 102) return 'http://purl.org/ontology/mo/bootleg';
if(attr = 1) return 'http://purl.org/ontology/mo/album';
if(attr = 2) return 'http://purl.org/ontology/mo/single';
if(attr = 3) return 'http://purl.org/ontology/mo/ep';
if(attr = 4) return 'http://purl.org/ontology/mo/compilation';
if(attr = 5) return 'http://purl.org/ontology/mo/soundtrack';
if(attr = 6) return 'http://purl.org/ontology/mo/spokenword';
if(attr = 7) return 'http://purl.org/ontology/mo/interview';
if(attr = 8) return 'http://purl.org/ontology/mo/audiobook';
if(attr = 9) return 'http://purl.org/ontology/mo/live';
if(attr = 10) return 'http://purl.org/ontology/mo/remix';
}
}
return null;
}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_OFFICIAL(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(100, attributes); }
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_PROMOTION(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(101, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_BOOTLEG(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(102, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_ALBUM(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(1, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_SINGLE(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(2, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_EP(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(3, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_COMPILATION(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(4, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_SOUNDTRACK(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(5, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_SPOKENWORD(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(6, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_INTERVIEW(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(7, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_AUDIOBOOK(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(8, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_LIVE(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(9, attributes);}
;
create function ZITGIST.MO.RECORD_ATTRIBUTE_REMIX(in attributes varchar)
{ return ZITGIST.MO.RECORD_ATTRIBUTE(10, attributes);}
;
]]></programlisting>
<para><emphasis>Definition of the quad map patterns</emphasis></para>
<para>This what creates the RDF triples from the musicbrainz relational database schema.</para>
<programlisting><![CDATA[
SPARQL
prefix mbz: <http://musibrainz.org/schemas/mbz#>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix dc: <http://purl.org/dc/elements/1.1/>
prefix dcterms: <http://purl.org/dc/terms/>
prefix bio: <http://vocab.org/bio/0.1/#>
prefix rel: <http://vocab.org/relationship/#>
prefix mo: <http://purl.org/ontology/mo/>
prefix timeline: <http://purl.org/NET/c4dm/timeline.owl#>
prefix event: <http://purl.org/NET/c4dm/event.owl#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix sim: <http://purl.org/ontology/sim/>
create quad storage virtrdf:MBZROOT
#
# Definition of the source tables from the mbz relational database and their joints.
#########
FROM ZITGIST.MO.track as track text literal name
FROM ZITGIST.MO.artist as track_artist
FROM ZITGIST.MO.puid as track_puid
FROM ZITGIST.MO.track as track_track
FROM ZITGIST.MO.url as track_url
FROM ZITGIST.MO.artist as track_artist_creator where (^{track.}^.artist = ^{track_artist_creator.}^.id)
FROM ZITGIST.MO.albumjoin as track_albumjoin where (^{track.}^.id = ^{track_albumjoin.}^.track)
FROM ZITGIST.MO.l_artist_track as l_artist_track2 where (^{track.}^.id = ^{l_artist_track2.}^.link1)
where (^{track_artist.}^.id = ^{l_artist_track2.}^.link0)
FROM ZITGIST.MO.puidjoin as puidjoin where (^{track.}^.id = ^{puidjoin.}^.track)
where (^{puidjoin.}^.puid = ^{track_puid.}^.id)
FROM ZITGIST.MO.l_track_track as l_track_track where (^{track.}^.id = ^{l_track_track.}^.link0)
where (^{track_track.}^.id = ^{l_track_track.}^.link1)
FROM ZITGIST.MO.l_track_url as l_track_url where (^{track.}^.id = ^{l_track_url.}^.link0)
where (^{track_url.}^.id = ^{l_track_url.}^.link1)
FROM ZITGIST.MO.album as album text literal name
FROM ZITGIST.MO.artist as album_artist
FROM ZITGIST.MO.album as album_album
FROM ZITGIST.MO.url as album_url
FROM ZITGIST.MO.country as album_release_country
FROM ZITGIST.MO.track as album_albumjoin_track
FROM ZITGIST.MO.artist as album_artist_creator where (^{album.}^.artist = ^{album_artist_creator.}^.id)
FROM ZITGIST.MO.album_amazon_asin as album_amazon_asin where (^{album.}^.id = ^{album_amazon_asin.}^.album)
FROM ZITGIST.MO.albumjoin as album_albumjoin where (^{album.}^.id = ^{album_albumjoin.}^.album)
where (^{album_albumjoin.}^.track = ^{album_albumjoin_track.}^.id)
FROM ZITGIST.MO.l_album_artist as l_album_artist2 where (^{album.}^.id = ^{l_album_artist2.}^.link0)
where (^{album_artist.}^.id = ^{l_album_artist2.}^.link1)
FROM ZITGIST.MO.l_album_album as l_album_album where (^{album.}^.id = ^{l_album_album.}^.link0)
where (^{album_album.}^.id = ^{l_album_album.}^.link1)
FROM ZITGIST.MO.l_album_url as l_album_url where (^{album.}^.id = ^{l_album_url.}^.link0)
where (^{album_url.}^.id = ^{l_album_url.}^.link1)
FROM ZITGIST.MO.release as album_release where (^{album.}^.id = ^{album_release.}^.album)
where (^{album_release.}^.country = ^{album_release_country.}^.id)
FROM ZITGIST.MO.artist as sim_band
FROM ZITGIST.MO.artist as sim_artist
FROM ZITGIST.MO.url as band_url
FROM ZITGIST.MO.artist as band_member
FROM ZITGIST.MO.album as band_album
FROM ZITGIST.MO.track as band_track
FROM ZITGIST.MO.artist as band text literal name where (^{band.}^.type = 2)
#FROM ZITGIST.MO.artist as artist text literal name where (^{artist.}^.type <> 2)
FROM ZITGIST.MO.artist as artist text literal name where (__or (neq(^{artist.}^.type, 2), isnull (^{artist.}^.type)))
FROM ZITGIST.MO.artist as artist_untyped text literal name where (^{artist_untyped.}^.type <> 2)
where (^{artist.}^.gid = ^{artist_untyped.}^.gid)
FROM ZITGIST.MO.album as band_album_creatorOf where (^{band_album_creatorOf.}^.artist = ^{band.}^.id)
FROM ZITGIST.MO.track as band_track_creatorOf where (^{band_track_creatorOf.}^.artist = ^{band.}^.id)
FROM ZITGIST.MO.artistalias as bandalias text literal name where (^{band.}^.id = ^{bandalias.}^."ref")
FROM ZITGIST.MO.l_artist_artist as band_l_artist_artist where (^{band_member.}^.id = ^{band_l_artist_artist.}^.link0)
where (^{band.}^.id = ^{band_l_artist_artist.}^.link1)
where (^{band_l_artist_artist.}^.link_type = 2)
FROM ZITGIST.MO.artist_relation as band_relation
where (^{artist.}^.id = ^{band_relation.}^.artist)
where (^{band.}^.id = ^{band_relation.}^.artist)
where (^{sim_band.}^.id = ^{band_relation.}^."ref")
FROM ZITGIST.MO.artist_relation as artist_relation
where (^{artist.}^.id = ^{artist_relation.}^.artist)
where (^{band.}^.id = ^{artist_relation.}^.artist)
where (^{sim_artist.}^.id = ^{artist_relation.}^."ref")
FROM ZITGIST.MO.l_artist_url as l_artist_url3 where (^{band.}^.id = ^{l_artist_url3.}^.link0)
where (^{band_url.}^.id = ^{l_artist_url3.}^.link1)
FROM ZITGIST.MO.l_album_artist as l_album_artist3 where (^{band.}^.id = ^{l_album_artist3.}^.link1)
where (^{band_album.}^.id = ^{l_album_artist3.}^.link0)
FROM ZITGIST.MO.l_artist_track as l_artist_track3 where (^{band.}^.id = ^{l_artist_track3.}^.link0)
where (^{band_track.}^.id = ^{l_artist_track3.}^.link1)
FROM ZITGIST.MO.url as artist_url
FROM ZITGIST.MO.artist as artist_artist
FROM ZITGIST.MO.track as artist_track
FROM ZITGIST.MO.album as artist_album
FROM ZITGIST.MO.album as artist_album_creatorOf where (^{artist_album_creatorOf.}^.artist = ^{artist.}^.id)
FROM ZITGIST.MO.track as artist_track_creatorOf where (^{artist_track_creatorOf.}^.artist = ^{artist.}^.id)
FROM ZITGIST.MO.artistalias as artistalias text literal name where (^{artist.}^.id = ^{artistalias.}^."ref")
FROM ZITGIST.MO.l_artist_url as l_artist_url where (^{artist.}^.id = ^{l_artist_url.}^.link0)
where (^{artist_url.}^.id = ^{l_artist_url.}^.link1)
FROM ZITGIST.MO.l_artist_artist as l_artist_artist where (^{artist.}^.id = ^{l_artist_artist.}^.link0)
where (^{artist_artist.}^.id = ^{l_artist_artist.}^.link1)
FROM ZITGIST.MO.l_artist_track as l_artist_track where (^{artist.}^.id = ^{l_artist_track.}^.link0)
where (^{artist_track.}^.id = ^{l_artist_track.}^.link1)
FROM ZITGIST.MO.l_album_artist as l_album_artist where (^{artist.}^.id = ^{l_album_artist.}^.link1)
where (^{artist_album.}^.id = ^{l_album_artist.}^.link0)
{
create virtrdf:MBZ as graph iri ("http://musicbrainz.org/") option (exclusive)
{
# Track Composition Event
mbz:composition_iri (track.gid)
a mo:Composition as mbz:track_is_composition;
dc:title track.name as mbz:title_of_track;
mo:composer mbz:artist_iri (track_artist_creator.gid) as mbz:creator_composer_of_track;
mo:composer mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 14) option (using l_artist_track2) as mbz:composer14_of_track;
mo:producesWork mbz:musicalwork_iri (track.gid) as mbz:track_producesWork.
# Track Musical Work
mbz:musicalwork_iri (track.gid)
a mo:MusicalWork as mbz:track_is_mw;
dc:title track.name as mbz:name_of_mw;
mo:productOfComposition mbz:composition_iri(track.gid) as mbz:mw_is_productOfComposition_of;
mo:usedInPerformance mbz:performance_iri(track.gid) as mbz:mw_usedInPerformance.
# Track Performance Event
mbz:performance_iri (track.gid)
a mo:Performance;
dc:title track.name;
mo:performer mbz:artist_iri (track_artist_creator.gid);
mo:performer mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 2) option (using l_artist_track2);
mo:conductor mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 9) option (using l_artist_track2);
mo:usesWork mbz:musicalwork_iri (track.gid);
mo:producesSound mbz:sound_iri (track.gid);
mo:recordedAs mbz:signal_iri(track.gid).
# Track Sound
mbz:sound_iri (track.gid)
a mo:Sound;
dc:title track.name;
mo:productOfPerformance mbz:performance_iri (track.gid);
mo:usedInRecording mbz:recording_iri (track.gid).
# Track Recording Event
mbz:recording_iri (track.gid)
a mo:Recording;
dc:title track.name;
mo:recordsSound mbz:sound_iri (track.gid);
mo:producesSignal mbz:signal_iri (track.gid).
# Track Signal (Musical Expression)
mbz:signal_iri (track.gid)
a mo:Signal;
dc:title track.name;
mo:remixer mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 11) option (using l_artist_track2);
mo:sampler mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 12) option (using l_artist_track2);
mo:djmixed mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 40) option (using l_artist_track2);
mo:djmix_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 13) option (using l_track_track);
mo:remix_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 6) option (using l_track_track);
mo:remix_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 11) option (using l_track_track);
mo:mashup_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 8) option (using l_track_track);
mo:mashup_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 4) option (using l_track_track);
mo:remaster_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 3) option (using l_track_track);
mo:compilation_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 10) option (using l_track_track);
mo:compilation_of mbz:track_iri (track_track.gid) where (^{l_track_track.}^.link_type = 12) option (using l_track_track);
mo:medley_of mbz:record_iri (track_track.gid) where (^{l_track_track.}^.link_type = 14) option (using l_track_track);
mo:published_as mbz:track_iri (track.gid);
mo:signalTime mbz:duration_iri(track.gid);
mo:puid track_puid.puid option (using puidjoin).
# Track duration
mbz:duration_iri(track.gid)
a timeline:Interval;
timeline:durationXSD mbz:duration(track.length).
mbz:track_iri(track.gid)
a mo:Track;
dc:title track.name;
mo:trackNum track_albumjoin.sequence;
dc:creator mbz:artist_iri (track_artist_creator.gid);
dc:creator mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 14) option (using l_artist_track2);
mo:compiler mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 39) option (using l_artist_track2);
mo:producer mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 18) option (using l_artist_track2);
mo:publisher mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 35) option (using l_artist_track2);
mo:engineer mbz:artist_iri (track_artist.gid) where (^{l_artist_track2.}^.link_type = 19) option (using l_artist_track2);
mo:licence mbz:url_iri(track_url.url) where (^{l_track_url.}^.link_type = 21) option (using l_track_url);
mo:paiddownload mbz:url_iri(track_url.url) where (^{l_track_url.}^.link_type = 16) option (using l_track_url);
mo:freedownload mbz:url_iri(track_url.url) where (^{l_track_url.}^.link_type = 17) option (using l_track_url);
mo:olga mbz:url_iri(track_url.url) where (^{l_track_url.}^.link_type = 19) option (using l_track_url);
mo:musicbrainz mbz:mbz_track_url_iri(track.gid);
mo:duration track.length.
# Record Composition Event
mbz:composition_iri (album.gid)
a mo:Composition;
dc:title album.name;
mo:composer mbz:artist_iri (album_artist_creator.gid);
mo:composer mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 14) option (using l_album_artist2);
mo:producesWork mbz:musicalwork_iri (album.gid).
# Record Musical Work
mbz:musicalwork_iri (album.gid)
a mo:MusicalWork;
dc:title album.name;
mo:productOfComposition mbz:composition_iri(album.gid);
mo:usedInPerformance mbz:performance_iri(album.gid).
# Record Performance Event
mbz:performance_iri (album.gid)
a mo:Performance;
dc:title album.name;
mo:performer mbz:artist_iri (album_artist_creator.gid);
mo:performer mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 2) option (using l_album_artist2);
mo:conductor mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 9) option (using l_album_artist2);
mo:usesWork mbz:musicalwork_iri (album.gid);
mo:producesSound mbz:sound_iri (album.gid);
mo:recordedAs mbz:record_iri(album.gid).
# Record Sound
mbz:sound_iri (album.gid)
a mo:Sound;
dc:title album.name;
mo:productOfPerformance mbz:performance_iri (album.gid);
mo:usedInRecording mbz:recording_iri (album.gid).
# Record Recording Event
mbz:recording_iri (album.gid)
a mo:Recording;
dc:title album.name;
mo:recordsSound mbz:sound_iri (album.gid);
mo:producesSignal mbz:signal_iri (album.gid).
# Record Signal (Musical Expression)
mbz:signal_iri (album.gid)
a mo:Signal;
dc:title album.name;
mo:djmix_of mbz:record_iri (album_album.gid) where (^{l_album_album.}^.link_type = 9) option (using l_album_album);
mo:remix_of mbz:record_iri (album_album.gid) where (^{l_album_album.}^.link_type = 7) option (using l_album_album);
mo:remix_of mbz:record_iri (album_album.gid) where (^{l_album_album.}^.link_type = 4) option (using l_album_album);
mo:mashup_of mbz:record_iri (album_album.gid) where (^{l_album_album.}^.link_type = 5) option (using l_album_album);
mo:remaster_of mbz:record_iri (album_album.gid) where (^{l_album_album.}^.link_type = 3) option (using l_album_album);
mo:tribute_to mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 44) option (using l_album_artist2);
mo:remixer mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 11) option (using l_album_artist2);
mo:djmixed mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 38) option (using l_album_artist2);
mo:sampler mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 12) option (using l_album_artist2);
mo:published_as mbz:record_iri (album.gid).
# Record (Musical Manifestation)
mbz:record_iri (album.gid)
a mo:Record;
dc:title album.name;
dc:date mbz:created(album_release.releasedate);
mo:image mbz:image_iri(album_amazon_asin.asin);
#Empty for now.
mo:compilation_of mbz:record_iri (album_album.gid) where (^{l_album_album.}^.link_type = 8) option (using l_album_album);
mo:releaseStatus mbz:official_iri(album.attributes);
mo:releaseStatus mbz:promotion_iri(album.attributes);
mo:releaseStatus mbz:bootleg_iri(album.attributes);
mo:releaseType mbz:album_iri(album.attributes);
mo:releaseType mbz:single_iri(album.attributes);
mo:releaseType mbz:ep_iri(album.attributes);
mo:releaseType mbz:compilation_iri(album.attributes);
mo:releaseType mbz:soundtrack_iri(album.attributes);
mo:releaseType mbz:spokenword_iri(album.attributes);
mo:releaseType mbz:interview_iri(album.attributes);
mo:releaseType mbz:audiobook_iri(album.attributes);
mo:releaseType mbz:live_iri(album.attributes);
mo:releaseType mbz:remix_iri(album.attributes);
dc:creator mbz:artist_iri (album_artist_creator.gid);
dc:creator mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 14) option (using l_album_artist2);
mo:compiler mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 41) option (using l_album_artist2);
mo:producer mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 18) option (using l_album_artist2);
mo:publisher mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 35) option (using l_album_artist2);
mo:engineer mbz:artist_iri (album_artist.gid) where (^{l_album_artist2.}^.link_type = 19) option (using l_album_artist2);
mo:musicbrainz mbz:mbz_release_url_iri(album.gid);
mo:musicmoz mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 25) option (using l_album_url);
mo:discogs mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 24) option (using l_album_url);
mo:wikipedia mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 23) option (using l_album_url);
mo:discography mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 1) option (using l_album_url);
mo:freedownload mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 21) option (using l_album_url);
mo:discography mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 16) option (using l_album_url);
mo:mailorder mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 19) option (using l_album_url);
mo:imdb mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 27) option (using l_album_url);
mo:paiddownload mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 20) option (using l_album_url);
mo:licence mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 32) option (using l_album_url);
mo:review mbz:url_iri(album_url.url) where (^{l_album_url.}^.link_type = 17) option (using l_album_url);
mo:amazon_asin mbz:amazon_asin_iri(album_amazon_asin.asin);
mo:has_track mbz:track_iri (album_albumjoin_track.gid) option (using album_albumjoin).
# Music Group (Band)
# mbz:band_iri(band.gid)
mbz:artist_iri(band.gid)
a mo:MusicArtist;
a mo:MusicGroup;
a foaf:Group;
foaf:name band.name;
foaf:nick bandalias.name;
# bio:event mbz:band_birth_event_iri(band.gid);
# bio:event mbz:band_death_event_iri(band.gid);
bio:event mbz:artist_birth_event_iri(band.gid);
bio:event mbz:artist_death_event_iri(band.gid);
# mo:similar_to mbz:band_iri(sim_band.gid) option (using band_relation);
mo:similar_to mbz:artist_iri(sim_band.gid) option (using band_relation);
mo:similar_to mbz:artist_iri(sim_artist.gid) option (using artist_relation);
# sim:link mbz:sim_link_iri(sim_band.gid) option (using band_relation);
# sim:link mbz:sim_link_iri(sim_artist.gid) option (using artist_relation);
foaf:member mbz:artist_iri(band_member.gid) option (using band_l_artist_artist);
# l_artist_url
mo:myspace mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 19) option (using l_artist_url3);
mo:musicmoz mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 12) option (using l_artist_url3);
mo:discogs mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 11) option (using l_artist_url3);
mo:wikipedia mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 10) option (using l_artist_url3);
mo:discography mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 1) option (using l_artist_url3);
mo:freedownload mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 8) option (using l_artist_url3);
mo:fanpage mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 3) option (using l_artist_url3);
mo:biography mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 4) option (using l_artist_url3);
mo:discography mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 5) option (using l_artist_url3);
mo:mailorder mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 15) option (using l_artist_url3);
mo:imdb mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 17) option (using l_artist_url3);
mo:paiddownload mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 7) option (using l_artist_url3);
foaf:depiction mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 14) option (using l_artist_url3);
foaf:homepage mbz:url_iri(band_url.url) where (^{l_artist_url3.}^.link_type = 2) option (using l_artist_url3);
mo:musicbrainz mbz:mbz_artist_url_iri(band.gid);
# l_album_artist
mo:composed mbz:composition_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 14) option (using l_album_artist3);
mo:performed mbz:performance_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 14) option (using l_album_artist3);
mo:performed mbz:performance_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 2) option (using l_album_artist3);
mo:conducted mbz:performance_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 9) option (using l_album_artist3);
mo:compiled mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 41) option (using l_album_artist3);
mo:djmixed mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 38) option (using l_album_artist3);
mo:remixed mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 11) option (using l_album_artist3);
mo:sampled mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 12) option (using l_album_artist3);
mo:produced mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 18) option (using l_album_artist3);
mo:published mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 35) option (using l_album_artist3);
mo:engineered mbz:record_iri (band_album.gid) where (^{l_album_artist3.}^.link_type = 19) option (using l_album_artist3);
# # mo:creatorOfRecord mbz:record_iri(band_album_creatorOf.gid);
foaf:made mbz:record_iri(band_album_creatorOf.gid);
# l_artist_track
mo:composed mbz:composition_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 14) option (using l_artist_track3);
mo:performed mbz:performance_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 14) option (using l_artist_track3);
mo:performed mbz:performance_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 2) option (using l_artist_track3);
mo:conducted mbz:performance_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 9) option (using l_artist_track3);
mo:compiled mbz:record_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 39) option (using l_artist_track3);
mo:djmixed mbz:track_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 40) option (using l_artist_track3);
mo:remixed mbz:track_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 11) option (using l_artist_track3);
mo:sampled mbz:track_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 12) option (using l_artist_track3);
mo:produced mbz:track_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 18) option (using l_artist_track3);
mo:published mbz:track_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 35) option (using l_artist_track3);
mo:engineered mbz:track_iri (band_track.gid) where (^{l_artist_track3.}^.link_type = 19) option (using l_artist_track3).
# # mo:creatorOfTrack mbz:track_iri(band_track_creatorOf.gid).
# Music Group (Band)'s Birth Event
# mbz:band_birth_event_iri(band.gid)
mbz:artist_birth_event_iri(band.gid)
a bio:Birth;
bio:date band.begindate.
# Music Group (Band)'s Death Event
# mbz:band_death_event_iri(band.gid)
mbz:artist_death_event_iri(band.gid)
a bio:Death;
bio:date band.enddate.
# Similarity link
#mbz:sim_link_iri(sim_band.gid)
# sim:relation mo:similar_to;
# sim:level band_relation.weight;
# sim:to sim_band.gid.
# Music Artist
mbz:artist_iri (artist.gid)
# artist
a mo:MusicArtist;
a mo:SoloMusicArtist where (^{artist_untyped.}^.gid is not null) option (using artist_untyped);
a foaf:Person where (^{artist_untyped.}^.gid is not null) option (using artist_untyped);
foaf:name artist.name;
foaf:nick artistalias.name;
bio:event mbz:artist_birth_event_iri(artist.gid);
bio:event mbz:artist_death_event_iri(artist.gid);
mo:member_of mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 2) option (using l_artist_artist);
# l_artist_artist
rel:siblingOf mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 7) option (using l_artist_artist);
rel:friendOf mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 5) option (using l_artist_artist);
rel:parentOf mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 6) option (using l_artist_artist);
rel:collaborated_with mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 11) option (using l_artist_artist);
rel:engagedTo mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 9) option (using l_artist_artist);
rel:spouseOf mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 8) option (using l_artist_artist);
mo:supporting_musician mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 13) option (using l_artist_artist);
mo:supporting_musician mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 14) option (using l_artist_artist);
mo:supporting_musician mbz:artist_iri(artist_artist.gid) where (^{l_artist_artist.}^.link_type = 15) option (using l_artist_artist);
mo:similar_to mbz:artist_iri(sim_artist.gid) option (using artist_relation);
# mo:similar_to mbz:band_iri(sim_band.gid) option (using band_relation);
mo:similar_to mbz:artist_iri(sim_band.gid) option (using band_relation);
# sim:link mbz:sim_link_iri(sim_band.gid) option (using band_relation);
# sim:link mbz:sim_link_iri(sim_artist.gid) option (using artist_relation);
# l_artist_url
mo:myspace mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 19) option (using l_artist_url);
mo:musicmoz mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 12) option (using l_artist_url);
mo:discogs mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 11) option (using l_artist_url);
mo:wikipedia mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 10) option (using l_artist_url);
mo:discography mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 1) option (using l_artist_url);
mo:freedownload mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 8) option (using l_artist_url);
mo:fanpage mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 3) option (using l_artist_url);
mo:biography mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 4) option (using l_artist_url);
mo:discography mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 5) option (using l_artist_url);
mo:mailorder mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 15) option (using l_artist_url);
mo:imdb mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 17) option (using l_artist_url);
mo:paiddownload mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 7) option (using l_artist_url);
foaf:depiction mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 14) option (using l_artist_url);
foaf:homepage mbz:url_iri(artist_url.url) where (^{l_artist_url.}^.link_type = 2) option (using l_artist_url);
mo:musicbrainz mbz:mbz_artist_url_iri(artist.gid);
# l_album_artist
mo:composed mbz:composition_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 14) option (using l_album_artist);
mo:performed mbz:performance_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 14) option (using l_album_artist);
mo:performed mbz:performance_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 2) option (using l_album_artist);
mo:conducted mbz:performance_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 9) option (using l_album_artist);
mo:compiled mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 41) option (using l_album_artist);
mo:djmixed mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 38) option (using l_album_artist);
mo:remixed mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 11) option (using l_album_artist);
mo:sampled mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 12) option (using l_album_artist);
mo:produced mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 18) option (using l_album_artist);
mo:published mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 35) option (using l_album_artist);
mo:engineered mbz:record_iri (artist_album.gid) where (^{l_album_artist.}^.link_type = 19) option (using l_album_artist);
# mo:creatorOfRecord mbz:record_iri(artist_album_creatorOf.gid);
foaf:made mbz:record_iri(artist_album_creatorOf.gid);
# l_artist_track
mo:composed mbz:composition_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 14) option (using l_artist_track);
mo:performed mbz:performance_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 14) option (using l_artist_track);
mo:performed mbz:performance_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 2) option (using l_artist_track);
mo:conducted mbz:performance_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 9) option (using l_artist_track);
mo:compiled mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 39) option (using l_artist_track);
mo:djmixed mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 40) option (using l_artist_track);
mo:remixed mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 11) option (using l_artist_track);
mo:sampled mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 12) option (using l_artist_track);
mo:produced mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 18) option (using l_artist_track);
mo:published mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 35) option (using l_artist_track);
mo:engineered mbz:track_iri (artist_track.gid) where (^{l_artist_track.}^.link_type = 19) option (using l_artist_track).
# mo:creatorOfTrack mbz:track_iri(artist_track_creatorOf.gid).
# Music Artist''s Birth Event
mbz:artist_birth_event_iri(artist.gid)
a bio:Birth;
bio:date artist.begindate.
# Music Artist''s Death Event
mbz:artist_death_event_iri(artist.gid)
a bio:Death;
bio:date artist.enddate.
# Similarity link
#mbz:sim_link_iri(sim_artist.gid)
# sim:relation mo:similar_to;
# sim:level artist_relation.weight;
# sim:to sim_artist.gid.
}
}
;
grant execute on ZITGIST.MO.RECORD_CREATION_DATE to "SPARQL";
grant execute on ZITGIST.MO.RECORD_CREATION_DATE_INVERSE to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_OFFICIAL to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_PROMOTION to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_BOOTLEG to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_ALBUM to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_SINGLE to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_EP to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_COMPILATION to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_SOUNDTRACK to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_SPOKENWORD to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_INTERVIEW to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_AUDIOBOOK to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_LIVE to "SPARQL";
grant execute on ZITGIST.MO.RECORD_ATTRIBUTE_REMIX to "SPARQL";
grant execute on ZITGIST.MO.TRACK_DURATION to "SPARQL";
grant execute on ZITGIST.MO.TRACK_DURATION_INVERSE to "SPARQL";
grant execute on ZITGIST.MO.album_amazon_asin to "SPARQL";
grant execute on ZITGIST.MO.album_name_WORDS to "SPARQL";
grant execute on ZITGIST.MO.albumjoin to "SPARQL";
grant execute on ZITGIST.MO.albummeta to "SPARQL";
grant execute on ZITGIST.MO.artist to "SPARQL";
grant execute on ZITGIST.MO.artist_name_WORDS to "SPARQL";
grant execute on ZITGIST.MO.artist_relation to "SPARQL";
grant execute on ZITGIST.MO.artistalias to "SPARQL";
grant execute on ZITGIST.MO.artistalias_name_WORDS to "SPARQL";
grant execute on ZITGIST.MO.country to "SPARQL";
grant execute on ZITGIST.MO.l_album_album to "SPARQL";
grant execute on ZITGIST.MO.l_album_artist to "SPARQL";
grant execute on ZITGIST.MO.l_album_url to "SPARQL";
grant execute on ZITGIST.MO.l_artist_artist to "SPARQL";
grant execute on ZITGIST.MO.l_artist_track to "SPARQL";
grant execute on ZITGIST.MO.l_artist_url to "SPARQL";
grant execute on ZITGIST.MO.l_track_track to "SPARQL";
grant execute on ZITGIST.MO.l_track_url to "SPARQL";
grant execute on ZITGIST.MO."language" to "SPARQL";
grant execute on ZITGIST.MO.puid to "SPARQL";
grant execute on ZITGIST.MO.puidjoin to "SPARQL";
grant execute on ZITGIST.MO.release to "SPARQL";
grant execute on ZITGIST.MO.track to "SPARQL";
grant execute on ZITGIST.MO.track_name_WORDS to "SPARQL";
grant execute on ZITGIST.MO.url to "SPARQL";
DB.DBA.XML_SET_NS_DECL ('mbz', 'http://musibrainz.org/schemas/mbz#', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsbusintods">
<title>Virtuoso ODS to RDF</title>
<para><emphasis>RDF View for ODS (the consolidated Graph)</emphasis></para>
<programlisting><![CDATA[
SPARQL drop quad map virtrdf:ODS_DS . ;
SPARQL prefix ods: <http://www.openlinksw.com/virtuoso/ods/>
create iri class ods:graph "http://^{URIQADefaultHost}^/dataspace/%U" (in uname varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U") .
create iri class ods:user "http://^{URIQADefaultHost}^/dataspace/%U#user" (in uname varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U#user") .
create iri class ods:user_group "http://^{URIQADefaultHost}^/dataspace/%U#group" (in uname varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U#group") .
create iri class ods:person "http://^{URIQADefaultHost}^/dataspace/%U#this" (in uname varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U#this") .
create iri class ods:mbox "mailto:%s" (in email varchar not null)
option (returns "mailto:%s") .
create iri class ods:phone "tel:%s" (in tel varchar not null)
option (returns "tel:%s") .
create iri class ods:geo_point "http://^{URIQADefaultHost}^/dataspace/%U#geo" (in uname varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U#geo") .
create iri class ods:forum "http://^{URIQADefaultHost}^/dataspace/%U/%U/%U"
( in uname varchar not null, in forum_type varchar not null, in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/%U/%U") .
create iri class ods:proxy "http://^{URIQADefaultHost}^/proxy/%U" (in url varchar not null)
option (returns "http://^{URIQADefaultHost}^/proxy/%U") .
create iri class ods:site "http://^{URIQADefaultHost}^/dataspace/%U#site" (in uname varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U#site") .
create iri class ods:role "http://^{URIQADefaultHost}^/dataspace/%U/%U/%U#%U"
(in uname varchar not null, in tp varchar not null, in inst varchar not null, in role_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/%U/%U#%U" ) .
# Blog
create iri class ods:blog_forum "http://^{URIQADefaultHost}^/dataspace/%U/weblog/%U"
(in uname varchar not null, in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/weblog/%U") .
create iri class ods:blog_post "http://^{URIQADefaultHost}^/dataspace/%U/weblog/%U/%U"
(in uname varchar not null, in forum_name varchar not null, in postid varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/weblog/%U/%U" ) .
create iri class ods:blog_comment "http://^{URIQADefaultHost}^/dataspace/%U/weblog/%U/%U/%d"
(in uname varchar not null, in forum_name varchar not null, in postid varchar not null, in comment_id int not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/weblog/%U/%U/%d" ) .
create iri class ods:tag "http://^{URIQADefaultHost}^/dataspace/%U/concept#%U"
(in uname varchar not null, in tag varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/concept#%U") .
create iri class ods:blog_post_text "http://^{URIQADefaultHost}^/dataspace/%U/weblog-text/%U/%U"
(in uname varchar not null, in forum_name varchar not null, in postid varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/weblog-text/%U/%U" ) .
#Feeds
create iri class ods:feed "http://^{URIQADefaultHost}^/dataspace/feed/%d" (in feed_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/feed/%d" ) .
create iri class ods:feed_item "http://^{URIQADefaultHost}^/dataspace/feed/%d/%d" (in feed_id integer not null, in item_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/feed/%d/%d" ) .
create iri class ods:feed_item_text "http://^{URIQADefaultHost}^/dataspace/feed/%d/%d/text" (in feed_id integer not null, in item_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/feed/%d/%d/text" ) .
create iri class ods:feed_mgr "http://^{URIQADefaultHost}^/dataspace/%U/feeds/%U" (in uname varchar not null, in inst_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/feeds/%U" ) .
create iri class ods:feed_comment "http://^{URIQADefaultHost}^/dataspace/%U/feeds/%U/%d/%d"
(in uname varchar not null, in inst_name varchar not null, in item_id integer not null, in comment_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/feeds/%U/%d/%d" ) .
#Bookmark
create iri class ods:bmk_post "http://^{URIQADefaultHost}^/dataspace/%U/bookmark/%U/%d"
(in uname varchar not null, in inst_name varchar not null, in bmk_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/bookmark/%U/%d") .
create iri class ods:bmk_post_text "http://^{URIQADefaultHost}^/dataspace/%U/bookmark/%U/%d/text"
(in uname varchar not null, in inst_name varchar not null, in bmk_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/bookmark/%U/%d/text" ) .
create iri class ods:bmk_forum "http://^{URIQADefaultHost}^/dataspace/%U/bookmark/%U"
( in uname varchar not null, in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/bookmark/%U") .
#Photo
create iri class ods:photo_forum "http://^{URIQADefaultHost}^/dataspace/%U/photos/%U"
(in uname varchar not null, in inst_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/photos/%U") .
create iri class ods:photo_post "http://^{URIQADefaultHost}^%s"
(in path varchar not null) option (returns "http://^{URIQADefaultHost}^/DAV/%s") .
create iri class ods:photo_post_text "http://^{URIQADefaultHost}^%s/text"
(in path varchar not null) option (returns "http://^{URIQADefaultHost}^/DAV/%s/text") .
create iri class ods:photo_comment "http://^{URIQADefaultHost}^%s:comment_%d"
(in path varchar not null, in comment_id int not null)
option (returns "http://^{URIQADefaultHost}^/DAV/%s:comment_%d") .
# Community
create iri class ods:community_forum "http://^{URIQADefaultHost}^/dataspace/%U/community/%U"
(in uname varchar not null, in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/community/%U") .
# Briefcase
create iri class ods:odrive_forum "http://^{URIQADefaultHost}^/dataspace/%U/briefcase/%U"
(in uname varchar not null, in inst_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/briefcase/%U" ) .
create iri class ods:odrive_post "http://^{URIQADefaultHost}^%s"
(in path varchar not null) option (returns "http://^{URIQADefaultHost}^/DAV/%s") .
create iri class ods:odrive_post_text "http://^{URIQADefaultHost}^%s/text"
(in path varchar not null) option (returns "http://^{URIQADefaultHost}^/DAV/%s/text") .
# Wiki
create iri class ods:wiki_post "http://^{URIQADefaultHost}^/dataspace/%U/wiki/%U/%U"
(in uname varchar not null, in inst_name varchar not null, in topic_id varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/wiki/%U/%U") .
create iri class ods:wiki_post_text "http://^{URIQADefaultHost}^/dataspace/%U/wiki/%U/%U/text"
(in uname varchar not null, in inst_name varchar not null, in topic_id varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/wiki/%U/%U/text" ) .
create iri class ods:wiki_forum "http://^{URIQADefaultHost}^/dataspace/%U/wiki/%U"
( in uname varchar not null, in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/wiki/%U" ) .
#Calendar
create iri class ods:calendar_event "http://^{URIQADefaultHost}^/dataspace/%U/calendar/%U/%d"
(in uname varchar not null, in inst_name varchar not null, in calendar_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/calendar/%U/%d" ) .
create iri class ods:calendar_event_text "http://^{URIQADefaultHost}^/dataspace/%U/calendar/%U/%d/text"
(in uname varchar not null, in inst_name varchar not null, in calendar_id integer not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/calendar/%U/%d/text" ) .
create iri class ods:calendar_forum "http://^{URIQADefaultHost}^/dataspace/%U/calendar/%U"
( in uname varchar not null, in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/%U/calendar/%U") .
# NNTPF
create iri class ods:nntp_forum "http://^{URIQADefaultHost}^/dataspace/discussion/%U"
( in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/discussion/%U").
create iri class ods:nntp_post "http://^{URIQADefaultHost}^/dataspace/discussion/%U/%U"
( in group_name varchar not null, in message_id varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/discussion/%U/%U" ) .
create iri class ods:nntp_post_text "http://^{URIQADefaultHost}^/dataspace/discussion/%U/%U/text"
( in group_name varchar not null, in message_id varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/discussion/%U/%U/text") .
create iri class ods:nntp_role "http://^{URIQADefaultHost}^/dataspace/discussion/%U#reader"
(in forum_name varchar not null)
option (returns "http://^{URIQADefaultHost}^/dataspace/discussion/%U#reader") .
;
SPARQL
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix sioct: <http://rdfs.org/sioc/types#>
prefix atom: <http://atomowl.org/ontologies/atomrdf#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix dc: <http://purl.org/dc/elements/1.1/>
prefix dct: <http://purl.org/dc/terms/>
prefix skos: <http://www.w3.org/2004/02/skos/core#>
prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix bm: <http://www.w3.org/2002/01/bookmark#>
prefix exif: <http://www.w3.org/2003/12/exif/ns/>
prefix ann: <http://www.w3.org/2000/10/annotation-ns#>
prefix wikiont: <http://sw.deri.org/2005/04/wikipedia/wikiont.owl#>
prefix calendar: <http://www.w3.org/2002/12/cal#>
prefix ods: <http://www.openlinksw.com/virtuoso/ods/>
alter quad storage virtrdf:DefaultQuadStorage
FROM DB.DBA.SIOC_USERS as users
FROM DB.DBA.SIOC_ODS_FORUMS as forums
FROM DB.DBA.SIOC_ROLES as roles
FROM DB.DBA.SIOC_ROLE_GRANTS as grants
FROM DB.DBA.SIOC_KNOWS as knows
FROM DB.DBA.ODS_FOAF_PERSON as person
where (^{person.}^.U_NAME = ^{users.}^.U_NAME)
where (^{forums.}^.U_NAME = ^{users.}^.U_NAME)
where (^{knows.}^.TO_NAME = ^{users.}^.U_NAME)
where (^{knows.}^.FROM_NAME = ^{users.}^.U_NAME)
where (^{grants.}^.U_NAME = ^{users.}^.U_NAME)
where (^{roles.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BLOG_POSTS as blog_posts
where (^{blog_posts.}^.B_OWNER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BLOG_POST_LINKS as blog_links
where (^{blog_links.}^.B_OWNER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BLOG_POST_ATTS as blog_atts
where (^{blog_atts.}^.B_OWNER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BLOG_POST_TAGS as blog_tags
where (^{blog_tags.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BLOG_COMMENTS as blog_comms
where (^{blog_comms.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BMK_POSTS as bmk_posts
where (^{bmk_posts.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_BMK_TAGS as bmk_tags
where (^{bmk_tags.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_ODRIVE_POSTS as odrv_posts
where (^{odrv_posts.}^.U_MEMBER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_ODRIVE_TAGS as odrv_tags
where (^{odrv_tags.}^.U_OWNER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_FEED_FEED_DOMAIN as feed_domain
where (^{feed_domain.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_FEED_POSTS as feed_posts
where (^{feed_posts.}^.EFI_FEED_ID = ^{feed_domain.}^.EF_ID)
FROM DB.DBA.ODS_FEED_COMMENTS as feed_comments
where (^{feed_comments.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_FEED_TAGS as feed_tags
where (^{feed_tags.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_FEED_LINKS as feed_links
where (^{feed_links.}^.EFI_FEED_ID = ^{feed_domain.}^.EF_ID)
FROM DB.DBA.ODS_FEED_ATTS as feed_atts
where (^{feed_atts.}^.EFI_FEED_ID = ^{feed_domain.}^.EF_ID)
FROM DB.DBA.ODS_PHOTO_POSTS as photo_posts
where (^{photo_posts.}^.U_MEMBER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_PHOTO_COMMENTS as photo_comments
where (^{photo_comments.}^.U_MEMBER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_PHOTO_TAGS as photo_tags
where (^{photo_tags.}^.U_MEMBER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_WIKI_POSTS as wiki_posts
where (^{wiki_posts.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_COMMUNITIES as community
where (^{community.}^.C_OWNER = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_NNTP_GROUPS as nntp_groups
FROM DB.DBA.ODS_NNTP_POSTS as nntp_posts
FROM DB.DBA.ODS_NNTP_USERS as nntp_users
where (^{nntp_users.}^.U_NAME = ^{users.}^.U_NAME)
FROM DB.DBA.ODS_NNTP_LINKS as nntp_links
{
create virtrdf:ODS_DS as graph ods:graph (users.U_NAME) option (exclusive)
{
ods:user (users.U_NAME) a sioc:User ;
sioc:id users.U_NAME ;
sioc:name users.U_FULL_NAME ;
sioc:email ods:mbox (users.E_MAIL) ;
sioc:email_sha1 users.E_MAIL_SHA1 ;
sioc:account_of ods:person (users.U_NAME) .
ods:person (person.U_NAME) a foaf:Person ;
foaf:nick person.U_NAME ;
foaf:name person.U_FULL_NAME ;
foaf:mbox ods:mbox (person.E_MAIL) ;
foaf:mbox_sha1sum person.E_MAIL_SHA1 ;
foaf:holdsAccount ods:user (person.U_NAME) ;
foaf:firstName person.FIRST_NAME ;
foaf:family_name person.LAST_NAME ;
foaf:gender person.GENDER ;
foaf:icqChatID person.ICQ ;
foaf:msnChatID person.MSN ;
foaf:aimChatID person.AIM ;
foaf:yahooChatID person.YAHOO ;
foaf:birthday person.BIRTHDAY ;
foaf:organization person.ORG ;
foaf:phone ods:phone (person.PHONE) ;
foaf:based_near ods:geo_point (person.U_NAME)
.
ods:geo_point (person.U_NAME) a geo:Point ;
geo:lat person.LAT ;
geo:lng person.LNG .
ods:person (knows.FROM_NAME) foaf:knows ods:person (knows.TO_NAME) .
ods:person (knows.TO_NAME) foaf:knows ods:person (knows.FROM_NAME) .
ods:user_group (grants.G_NAME) a sioc:Usergroup ;
sioc:id grants.G_NAME ;
sioc:has_member ods:user (grants.U_NAME) .
ods:user (grants.U_NAME) sioc:member_of ods:user_group (grants.G_NAME) .
ods:role (roles.U_NAME, roles.APP_TYPE, roles.WAM_INST, roles.WMT_NAME)
sioc:has_scope ods:forum (roles.U_NAME, roles.APP_TYPE, roles.WAM_INST) ;
sioc:function_of ods:user (roles.U_NAME) .
ods:forum (roles.U_NAME, roles.APP_TYPE, roles.WAM_INST)
sioc:scope_of ods:role (roles.U_NAME, roles.APP_TYPE, roles.WAM_INST, roles.WMT_NAME) .
ods:user (roles.U_NAME)
sioc:has_function ods:role (roles.U_NAME, roles.APP_TYPE, roles.WAM_INST, roles.WMT_NAME) .
ods:forum (forums.U_NAME, forums.APP_TYPE, forums.WAM_INST) a sioc:Container ;
sioc:id forums.WAM_INST ;
sioc:type forums.APP_TYPE ;
sioc:description forums.WAI_DESCRIPTION ;
sioc:link ods:proxy (forums.LINK) ;
sioc:has_space ods:site (forums.U_NAME) .
# Weblog
ods:blog_post (blog_posts.B_OWNER, blog_posts.B_INST, blog_posts.B_POST_ID) a sioct:BlogPost ;
sioc:link ods:proxy (blog_posts.B_LINK) ;
sioc:has_creator ods:user (blog_posts.B_CREATOR) ;
foaf:maker ods:person (blog_posts.B_CREATOR) ;
sioc:has_container ods:blog_forum (blog_posts.B_OWNER, blog_posts.B_INST) ;
dc:title blog_posts.B_TITLE ;
dct:created blog_posts.B_CREATED ;
dct:modified blog_posts.B_MODIFIED ;
sioc:content blog_posts.B_CONTENT .
ods:blog_forum (blog_posts.B_OWNER, blog_posts.B_INST)
sioc:container_of
ods:blog_post (blog_posts.B_OWNER, blog_posts.B_INST, blog_posts.B_POST_ID) .
ods:user (blog_posts.B_CREATOR)
sioc:creator_of
ods:blog_post (blog_posts.B_OWNER, blog_posts.B_INST, blog_posts.B_POST_ID) .
ods:blog_post (blog_links.B_OWNER, blog_links.B_INST, blog_links.B_POST_ID)
sioc:links_to
ods:proxy (blog_links.PL_LINK) .
# end Weblog
# Bookmark
ods:bmk_post (bmk_posts.U_NAME, bmk_posts.WAI_NAME, bmk_posts.BD_BOOKMARK_ID)
a bm:Bookmark ;
dc:title bmk_posts.BD_NAME;
dct:created bmk_posts.BD_CREATED ;
dct:modified bmk_posts.BD_LAST_UPDATE ;
dc:date bmk_posts.BD_LAST_UPDATE ;
ann:created bmk_posts.BD_CREATED ;
dc:creator bmk_posts.U_NAME ;
bm:recalls ods:proxy (bmk_posts.B_URI) ;
sioc:link ods:proxy (bmk_posts.B_URI) ;
sioc:content bmk_posts.BD_DESCRIPTION ;
sioc:has_creator ods:user (bmk_posts.U_NAME) ;
foaf:maker ods:person (bmk_posts.U_NAME) ;
sioc:has_container ods:bmk_forum (bmk_posts.U_NAME, bmk_posts.WAI_NAME) .
ods:bmk_forum (bmk_posts.U_NAME, bmk_posts.WAI_NAME)
sioc:container_of
ods:bmk_post (bmk_posts.U_NAME, bmk_posts.WAI_NAME, bmk_posts.BD_BOOKMARK_ID) .
ods:user (bmk_posts.U_NAME)
sioc:creator_of
ods:bmk_post (bmk_posts.U_NAME, bmk_posts.WAI_NAME, bmk_posts.BD_BOOKMARK_ID) .
ods:bmk_post (bmk_tags.U_NAME, bmk_tags.WAM_INST, bmk_tags.ITEM_ID)
sioc:topic
ods:tag (bmk_tags.U_NAME, bmk_tags.BD_TAG) .
ods:tag (bmk_tags.U_NAME, bmk_tags.BD_TAG) a skos:Concept ;
skos:prefLabel bmk_tags.BD_TAG ;
skos:isSubjectOf ods:bmk_post (bmk_tags.U_NAME, bmk_tags.WAM_INST, bmk_tags.ITEM_ID) .
# end Bookmark
# Briefcase
ods:odrive_post (odrv_posts.RES_FULL_PATH) a foaf:Document ;
dc:title odrv_posts.RES_NAME ;
dct:created odrv_posts.RES_CREATED ;
dct:modified odrv_posts.RES_MODIFIED ;
sioc:content odrv_posts.RES_DESCRIPTION ;
sioc:has_creator ods:user (odrv_posts.U_OWNER) ;
foaf:maker ods:person (odrv_posts.U_OWNER) ;
sioc:has_container ods:odrive_forum (odrv_posts.U_MEMBER, odrv_posts.WAI_NAME) .
ods:odrive_forum (odrv_posts.U_MEMBER, odrv_posts.WAI_NAME)
sioc:container_of
ods:odrive_post (odrv_posts.RES_FULL_PATH) .
ods:user (odrv_posts.U_OWNER)
sioc:creator_of
ods:odrive_post (odrv_posts.RES_FULL_PATH) .
ods:odrive_post (odrv_tags.RES_FULL_PATH)
sioc:topic
ods:tag (odrv_tags.U_OWNER, odrv_tags.TAG) .
ods:tag (odrv_tags.U_OWNER, odrv_tags.TAG) a skos:Concept ;
skos:prefLabel odrv_tags.TAG ;
skos:isSubjectOf ods:odrive_post (odrv_tags.RES_FULL_PATH) .
# end Briefcase
# Feeds
ods:feed (feed_domain.EF_ID) a atom:Feed ;
sioc:link ods:proxy (feed_domain.EF_URI) ;
atom:link ods:proxy (feed_domain.EF_URI) ;
atom:title feed_domain.EF_TITLE ;
sioc:has_parent ods:feed_mgr (feed_domain.U_NAME, feed_domain.WAI_NAME) .
ods:feed_mgr (feed_domain.U_NAME, feed_domain.WAI_NAME)
sioc:parent_of ods:feed (feed_domain.EF_ID) .
ods:feed_item (feed_tags.EFI_FEED_ID, feed_tags.EFID_ITEM_ID)
sioc:topic
ods:tag (feed_tags.U_NAME, feed_tags.EFID_TAG) .
ods:tag (feed_tags.U_NAME, feed_tags.EFID_TAG) a skos:Concept ;
skos:prefLabel feed_tags.EFID_TAG ;
skos:isSubjectOf ods:feed_item (feed_tags.EFI_FEED_ID, feed_tags.EFID_ITEM_ID) .
ods:feed_comment (feed_comments.U_NAME, feed_comments.WAI_NAME, feed_comments.EFIC_ITEM_ID, feed_comments.EFIC_ID)
a sioct:Comment ;
dc:title feed_comments.EFIC_TITLE ;
sioc:content feed_comments.EFIC_COMMENT ;
dct:modified feed_comments.LAST_UPDATE ;
dct:created feed_comments.LAST_UPDATE ;
sioc:link ods:proxy (feed_comments.LINK) ;
sioc:has_container ods:feed (feed_comments.EFI_FEED_ID) ;
sioc:reply_of ods:feed_item (feed_comments.EFI_FEED_ID, feed_comments.EFIC_ITEM_ID) ;
foaf:maker ods:proxy (feed_comments.EFIC_U_URL) .
ods:proxy (feed_comments.EFIC_U_URL) a foaf:Person ;
foaf:name feed_comments.EFIC_U_NAME;
foaf:mbox ods:mbox (feed_comments.EFIC_U_MAIL) .
ods:feed (feed_comments.EFI_FEED_ID)
sioc:container_of
ods:feed_comment (feed_comments.U_NAME, feed_comments.WAI_NAME, feed_comments.EFIC_ITEM_ID, feed_comments.EFIC_ID) .
ods:feed_item (feed_comments.EFI_FEED_ID, feed_comments.EFIC_ITEM_ID)
sioc:has_reply
ods:feed_comment (feed_comments.U_NAME, feed_comments.WAI_NAME, feed_comments.EFIC_ITEM_ID, feed_comments.EFIC_ID) .
ods:feed_item (feed_links.EFI_FEED_ID, feed_links.EFI_ID)
sioc:links_to
ods:proxy (feed_links.EFIL_LINK) .
ods:feed_item (feed_atts.EFI_FEED_ID, feed_atts.EFI_ID)
sioc:attachment
ods:proxy (feed_atts.EFIE_URL) .
ods:feed_item (feed_posts.EFI_FEED_ID, feed_posts.EFI_ID) a atom:Entry ;
sioc:has_container ods:feed (feed_posts.EFI_FEED_ID) ;
dc:title feed_posts.EFI_TITLE ;
dct:created feed_posts.PUBLISH_DATE ;
dct:modified feed_posts.PUBLISH_DATE ;
sioc:link ods:proxy (feed_posts.EFI_LINK) ;
sioc:content feed_posts.EFI_DESCRIPTION ;
atom:title feed_posts.EFI_TITLE ;
atom:source ods:feed (feed_posts.EFI_FEED_ID) ;
atom:published feed_posts.PUBLISH_DATE ;
atom:updated feed_posts.PUBLISH_DATE ;
atom:content ods:feed_item_text (feed_posts.EFI_FEED_ID, feed_posts.EFI_ID) .
ods:feed (feed_posts.EFI_FEED_ID) sioc:container_of ods:feed_item (feed_posts.EFI_FEED_ID, feed_posts.EFI_ID) .
ods:feed_item_text (feed_posts.EFI_FEED_ID, feed_posts.EFI_ID) a atom:Content ;
atom:type "text/xhtml" ;
atom:lang "en-US" ;
atom:body feed_posts.EFI_DESCRIPTION .
ods:feed (feed_posts.EFI_FEED_ID)
atom:contains
ods:feed_item (feed_posts.EFI_FEED_ID, feed_posts.EFI_ID) .
# end Feeds
# Photo
ods:photo_post (photo_posts.RES_FULL_PATH) a exif:IFD ;
dc:title photo_posts.RES_NAME ;
dct:created photo_posts.RES_CREATED ;
dct:modified photo_posts.RES_MODIFIED ;
sioc:content photo_posts.RES_DESCRIPTION ;
sioc:has_creator ods:user (photo_posts.U_OWNER) ;
foaf:maker ods:person (photo_posts.U_OWNER) ;
sioc:link ods:proxy (photo_posts.RES_LINK) ;
sioc:has_container ods:photo_forum (photo_posts.U_MEMBER, photo_posts.WAI_NAME) .
ods:photo_forum (photo_posts.U_MEMBER, photo_posts.WAI_NAME)
sioc:container_of
ods:photo_post (photo_posts.RES_FULL_PATH) .
ods:user (photo_posts.U_OWNER)
sioc:creator_of
ods:photo_post (photo_posts.RES_FULL_PATH) .
ods:photo_post (photo_tags.RES_FULL_PATH)
sioc:topic
ods:tag (photo_tags.U_MEMBER, photo_tags.RES_TAG) .
ods:tag (photo_tags.U_MEMBER, photo_tags.RES_TAG) a skos:Concept ;
skos:prefLabel photo_tags.RES_TAG ;
skos:isSubjectOf ods:photo_post (photo_tags.RES_FULL_PATH) .
ods:photo_comment (photo_comments.RES_FULL_PATH, photo_comments.COMMENT_ID) a sioct:Comment ;
sioc:reply_of ods:photo_post (photo_comments.RES_FULL_PATH) ;
sioc:has_container ods:photo_forum (photo_comments.U_MEMBER, photo_comments.WAI_NAME) ;
dc:title photo_comments.RES_NAME ;
dct:created photo_comments.CREATE_DATE ;
dct:modified photo_comments.MODIFY_DATE ;
sioc:content photo_comments.TEXT ;
foaf:maker ods:person (photo_comments.U_MAKER) .
ods:photo_post (photo_comments.RES_FULL_PATH)
sioc:has_reply
ods:photo_comment (photo_comments.RES_FULL_PATH, photo_comments.COMMENT_ID) .
# end Photo
# Polls
# end Polls
# Mail
# end Mail
# Wiki
ods:wiki_post (wiki_posts.U_NAME, wiki_posts.CLUSTERNAME, wiki_posts.LOCALNAME) a wikiont:Article ;
dc:title wiki_posts.LOCALNAME ;
dct:created wiki_posts.RES_CREATED ;
dct:modified wiki_posts.RES_MODIFIED ;
sioc:content wiki_posts.RES_CONTENT ;
sioc:has_creator ods:user (wiki_posts.U_NAME) ;
foaf:maker ods:person (wiki_posts.U_NAME) ;
sioc:has_container ods:wiki_forum (wiki_posts.U_NAME, wiki_posts.CLUSTERNAME) .
ods:wiki_forum (wiki_posts.U_NAME, wiki_posts.CLUSTERNAME)
sioc:container_of
ods:wiki_post (wiki_posts.U_NAME, wiki_posts.CLUSTERNAME, wiki_posts.LOCALNAME) .
ods:user (wiki_posts.U_NAME)
sioc:creator_of
ods:wiki_post (wiki_posts.U_NAME, wiki_posts.CLUSTERNAME, wiki_posts.LOCALNAME) .
# end Wiki
# Community
ods:community_forum (community.C_OWNER, community.CM_COMMUNITY_ID) a sioc:Community ;
sioc:has_part ods:forum (community.A_OWNER, community.A_TYPE, community.CM_MEMBER_APP) .
ods:forum (community.A_OWNER, community.A_TYPE, community.CM_MEMBER_APP)
sioc:part_of
ods:community_forum (community.C_OWNER, community.CM_COMMUNITY_ID) .
# end Community
# NNTP
ods:nntp_forum (nntp_groups.NG_NAME) a sioct:MessageBoard ;
sioc:id nntp_groups.NG_NAME ;
sioc:description nntp_groups.NG_DESC .
ods:nntp_post (nntp_posts.NG_NAME, nntp_posts.NM_ID) a sioct:BoardPost ;
sioc:content nntp_posts.NM_BODY ;
dc:title nntp_posts.FTHR_SUBJ ;
dct:created nntp_posts.REC_DATE ;
dct:modified nntp_posts.REC_DATE ;
foaf:maker ods:proxy (nntp_posts.MAKER) ;
sioc:reply_of ods:nntp_post (nntp_posts.NG_NAME, nntp_posts.FTHR_REFER) ;
sioc:has_container ods:nntp_forum (nntp_posts.NG_NAME) .
ods:nntp_post (nntp_posts.NG_NAME, nntp_posts.FTHR_REFER)
sioc:has_reply
ods:nntp_post (nntp_posts.NG_NAME, nntp_posts.NM_ID) .
ods:nntp_forum (nntp_posts.NG_NAME)
sioc:container_of
ods:nntp_post (nntp_posts.NG_NAME, nntp_posts.NM_ID) .
ods:nntp_role (nntp_groups.NG_NAME)
sioc:has_scope
ods:nntp_forum (nntp_groups.NG_NAME) .
ods:nntp_forum (nntp_groups.NG_NAME)
sioc:scope_of
ods:nntp_role (nntp_groups.NG_NAME) .
ods:user (nntp_users.U_NAME)
sioc:has_function
ods:nntp_role (nntp_users.NG_NAME) .
ods:nntp_role (nntp_users.NG_NAME)
sioc:function_of
ods:user (nntp_users.U_NAME) .
ods:nntp_post (nntp_links.NG_NAME, nntp_links.NML_MSG_ID)
sioc:links_to
ods:proxy (nntp_links.NML_URL) .
# end NNTP
} .
} .
;
]]></programlisting>
<para><emphasis>URL Rewrite Rules for ODS</emphasis></para>
<programlisting><![CDATA[
create procedure DB.DBA.URL_REW_ODS_ACCEPT ()
{
declare accept, ret any;
accept := http_request_header (http_request_header (), 'Accept');
if (not isstring (accept))
return null;
ret := null;
if (regexp_match ('(application|text)/rdf.(xml|n3|turtle|ttl)', accept) is not null)
{
if (regexp_match ('application/rdf.xml', accept) is not null)
{
ret := 'rdf';
}
else if (regexp_match ('text/rdf.n3', accept) is not null)
{
ret := 'n3';
}
else if (regexp_match ('application/rdf.turtle', accept) is not null or
regexp_match ('application/rdf.ttl', accept) is not null)
{
ret := 'n3';
}
}
return ret;
};
create procedure DB.DBA.URL_REW_ODS_SPQ (in graph varchar, in iri varchar, in acc varchar)
{
declare q, ret any;
iri := replace (iri, '''', '%27');
iri := replace (iri, '<', '%3C');
iri := replace (iri, '>', '%3E');
q := sprintf ('define input:inference <%s> DESCRIBE <%s> FROM <%s>', graph, iri, graph);
ret := sprintf ('/sparql?query=%U&format=%U', q, acc);
return ret;
};
create procedure DB.DBA.URL_REW_ODS_USER (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (current_proc_name ());
declare acc, ret any;
declare q, iri, graph any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
graph := sioc..get_graph ();
iri := sprintf ('%s/%U', graph, val);
if (val like 'person/%')
{
val := substring (val, 8, length (val));
ret := sprintf ('/ods/foaf.vsp?uname=%U&fmt=%U', val, acc);
}
else
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
}
else
{
http_header (http_header_get ()||sprintf ('X-XRDS-Location: %s\r\n',
DB.DBA.wa_link (1, '/dataspace/'||val||'/yadis.xrds')));
if (val like 'person/%')
val := substring (val, 8, length (val));
ret := sprintf ('/ods/uhome.vspx?page=1&ufname=%s', val);
}
return ret;
};
create procedure DB.DBA.URL_REW_ODS_USER_GEM (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (current_proc_name ());
declare acc, ret any;
declare q, iri, graph, path, is_person any;
path := http_path ();
if (path like '%.rdf')
acc := 'rdf';
else if (path like '%.n3')
acc := 'n3';
else if (path like '%.ttl')
acc := 'n3';
else if (path like '%/yadis.xrds')
acc := 'yadis';
else
acc := 'rdf';
if (acc <> 'yadis')
{
is_person := matches_like (path, '%/about.%');
graph := sioc..get_graph ();
if (is_person)
{
--iri := sprintf ('%s/person/%U', graph, val);
ret := sprintf ('/ods/foaf.vsp?uname=%U&fmt=%U', val, acc);
}
else
{
iri := sprintf ('%s/%U', graph, val);
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
}
}
else
{
ret := sprintf ('/ods/yadis.vsp?uname=%U', val);
}
return ret;
};
create procedure DB.DBA.URL_REW_ODS_GEM (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (current_proc_name ());
declare acc, ret any;
declare q, iri, graph, path, pos any;
path := http_path ();
if (path like '%.rdf')
acc := 'rdf';
else if (path like '%.n3')
acc := 'n3';
else if (path like '%.ttl')
acc := 'n3';
else
acc := 'rdf';
graph := sioc..get_graph ();
pos := strrchr (path, '/');
path := subseq (path, 0, pos);
if (val = 'person')
{
pos := strrchr (path, '/');
val := subseq (path, pos+1, length (path));
ret := sprintf ('/ods/foaf.vsp?uname=%U&fmt=%U', val, acc);
}
else
{
iri := sprintf ('http://%s%s', sioc..get_cname (), path);
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
}
return ret;
};
create procedure DB.DBA.URL_REW_ODS_APP (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (current_proc_name (), val);
if (par = 'app')
return sprintf (fmt, wa_app_to_type (val));
return sprintf (fmt, val);
};
create procedure DB.DBA.URL_REW_ODS_BLOG (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (par, fmt, val);
-- dbg_obj_print (current_proc_name (), val);
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'inst')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'inst')
{
declare url any;
val := split_and_decode (val)[0];
url := (SELECT WAM_HOME_PAGE FROM WA_MEMBER WHERE WAM_INST = val AND WAM_MEMBER_TYPE = 1);
if (url is not null)
val := url;
return sprintf (fmt, val);
}
else if (par = 'id' and val <> '')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
};
create procedure DB.DBA.URL_REW_ODS_NNTP (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (par, fmt, val);
-- dbg_obj_print (current_proc_name (), val);
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
-- dbg_obj_print (iri);
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else if (par = 'grp')
{
declare gid int;
val := split_and_decode (val)[0];
gid := (SELECT NG_GROUP FROM DB.DBA.NEWS_GROUPS WHERE NG_NAME = val);
ret := sprintf ('/nntpf/nntpf_nthread_view.vspx?group=%d', gid);
return ret;
}
else if (par = 'post')
{
ret := sprintf ('/nntpf/nntpf_disp_article.vspx?id=%U', encode_base64 (val));
return ret;
}
}
;
create procedure DB.DBA.URL_REW_ODS_XD (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (par, fmt, val);
-- dbg_obj_print (current_proc_name (), val);
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
-- dbg_obj_print (iri);
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else if (par = 'inst')
{
val := split_and_decode (val)[0];
ret := (SELECT WAM_HOME_PAGE FROM WA_MEMBER WHERE WAM_INST = val and WAM_MEMBER_TYPE = 1);
return ret;
}
}
;
create procedure DB.DBA.URL_REW_ODS_WIKI (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (par, fmt, val);
-- dbg_obj_print (current_proc_name (), val);
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
-- dbg_obj_print (iri);
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else if (par = 'inst')
{
declare _inst DB.DBA.web_app;
_inst := (SELECT WAI_INST FROM WA_INSTANCE WHERE WAI_NAME = val);
ret := _inst.wa_post_url (null, null, val, val);
-- dbg_obj_print ('ret', ret);
return ret;
}
else if (par = 'post')
{
return '/'||val;
}
}
;
create procedure DB.DBA.URL_REW_ODS_PHOTO (in par varchar, in fmt varchar, in val varchar)
{
-- dbg_obj_print (par, fmt, val);
-- dbg_obj_print (current_proc_name (), val);
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
-- dbg_obj_print (iri);
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else if (par = 'inst')
{
val := split_and_decode (val)[0];
ret := (SELECT WAM_HOME_PAGE FROM WA_MEMBER WHERE WAM_INST = val AND WAM_MEMBER_TYPE = 1);
return ret;
}
else if (par = 'post')
{
declare id int;
declare col, nam varchar;
declare exit handler for not found
{
signal ('22023', sprintf ('The resource %d doesn''t exists', id));
};
id := atoi(ltrim(val, '/'));
SELECT RES_FULL_PATH INTO nam FROM WS.WS.SYS_DAV_RES WHERE RES_ID = id;
return nam;
}
}
;
create procedure DB.DBA.URL_REW_ODS_ADDRESSBOOK (in par varchar, in fmt varchar, in val varchar)
{
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'instance')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'instance')
{
declare id, url any;
val := split_and_decode (val)[0];
id := AB.WA.domain_id (val);
if (id is not null) {
url := AB.WA.ab_url (id);
if (url is not null)
val := url;
}
return sprintf (fmt, val);
}
else if (par = 'params')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
}
;
create procedure DB.DBA.URL_REW_ODS_BOOKMARK (in par varchar, in fmt varchar, in val varchar)
{
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'instance')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'instance')
{
declare id, url any;
val := split_and_decode (val)[0];
id := BMK.WA.domain_id (val);
if (id is not null) {
url := BMK.WA.bookmark_url (id);
if (url is not null)
val := url;
}
return sprintf (fmt, val);
}
else if (par = 'params')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
}
;
create procedure DB.DBA.URL_REW_ODS_BRIEFCASE (in par varchar, in fmt varchar, in val varchar)
{
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'instance')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'instance')
{
declare id, url any;
val := split_and_decode (val)[0];
id := ODRIVE.WA.domain_id (val);
if (id is not null) {
url := ODRIVE.WA.odrive_url (id);
if (url is not null)
val := url;
}
return sprintf (fmt, val);
}
else if (par = 'params')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
}
;
create procedure DB.DBA.URL_REW_ODS_CALENDAR (in par varchar, in fmt varchar, in val varchar)
{
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'instance')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'instance')
{
declare id, url any;
val := split_and_decode (val)[0];
id := CAL.WA.domain_id (val);
if (id is not null) {
url := CAL.WA.calendar_url (id);
if (url is not null)
val := url;
}
return sprintf (fmt, val);
}
else if (par = 'params')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
}
;
create procedure DB.DBA.URL_REW_ODS_FEEDS (in par varchar, in fmt varchar, in val varchar)
{
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'instance')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'instance')
{
declare id, url any;
val := split_and_decode (val)[0];
id := ENEWS.WA.domain_id (val);
if (id is not null) {
url := ENEWS.WA.enews_url (id) || 'news.vspx';
if (url is not null)
val := url;
}
return sprintf (fmt, val);
}
else if (par = 'params')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
}
;
create procedure DB.DBA.URL_REW_ODS_POLLS (in par varchar, in fmt varchar, in val varchar)
{
declare acc, ret any;
acc := DB.DBA.URL_REW_ODS_ACCEPT ();
if (acc is not null)
{
if (par = 'instance')
{
declare q, iri, graph any;
graph := sioc..get_graph ();
iri := 'http://' || sioc..get_cname () || http_path ();
ret := DB.DBA.URL_REW_ODS_SPQ (graph, iri, acc);
return ret;
}
else
return '';
}
else if (par = 'instance')
{
declare id, url any;
val := split_and_decode (val)[0];
id := POLLS.WA.domain_id (val);
if (id is not null) {
url := POLLS.WA.polls_url (id);
if (url is not null)
val := url;
}
return sprintf (fmt, val);
}
else if (par = 'params')
{
if (atoi (val) = 0 and val <> '0')
fmt := '%s';
else
fmt := '?id=%s';
return sprintf (fmt, val);
}
}
;
create procedure DB.DBA.URL_REW_ODS_FOAF_EXT (in par varchar, in fmt varchar, in val varchar)
{
if (par = '*accept*')
{
declare ext any;
ext := 'rdf';
if (val = 'text/rdf+n3')
ext := 'n3';
return sprintf (fmt, ext);
}
else
return sprintf (fmt, val);
}
;
create procedure ur_ods_rdf_doc (in path varchar)
{
declare r any;
r := regexp_match ('[^/]*\x24', path);
return r||'#this';
};
create procedure ur_ods_html_doc (in path varchar)
{
declare pos, r any;
if (path like '%/foaf.%')
{
pos := strrchr (path, '/');
}
else if (path like '%#%')
{
pos := strrchr (path, '#');
}
if (pos > 0)
r := subseq (path, 0, pos);
else
r := '/';
return r;
};
-- ODS Rules
-- http://cname/dataspace/uname
-- http://cname/dataspace/person/uname
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule1', 1,
'/dataspace/((person/)?[^/#]*)', vector('ufname'), 1,
'%s', vector('ufname'),
'DB.DBA.URL_REW_ODS_USER');
-- http://cname/dataspace/uname with Accept will do 303 to the /sparql
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule2', 1,
'/dataspace/([^/]*)', vector('ufname'), 1,
'/sparql?query=define+input%%3Ainference+%%3Chttp%%3A//^{URIQADefaultHost}^/dataspace%%3E+DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^/dataspace/%U%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/dataspace%%3E&format=%U', vector('ufname', '*accept*'),
null,
'(application|text)/rdf.(xml|n3|turtle|ttl)',
0,
303);
-- http://cname/dataspace/uname/app_type
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule3', 1,
'/dataspace/((?!person)[^/]*)/([^\\./]*)', vector('ufname', 'app'), 2,
'/ods/app_inst.vspx?app=%s&ufname=%s&l=1', vector('app', 'ufname'),
'DB.DBA.URL_REW_ODS_APP');
-- http://cname/dataspace/uname/file.ext
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule4', 1,
'/dataspace/([^/]*)/(sioc|about|yadis)\\.(rdf|n3|ttl|xrds)', vector('ufname', 'file', 'fmt'), 3,
'%s', vector('ufname'),
'DB.DBA.URL_REW_ODS_USER_GEM');
-- Rules for FOAF profile
-- http://cname/dataspace/person/uname with Accept, do 303 to http://cname/dataspace/person/uname/foaf.ext
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule5', 1,
'/dataspace/person/([^/#]*)/?', vector('ufname'), 1,
'/dataspace/person/%U/foaf.%s', vector('ufname', '*accept*'),
'DB.DBA.URL_REW_ODS_FOAF_EXT',
'(application|text)/rdf.(xml|n3|turtle|ttl)',
2,
303);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule6', 1,
'/dataspace/person/([^/]*)/page/([^/]*)/?', vector('ufname', 'page'), 1,
'/dataspace/person/%U/foaf.%s?page=%s', vector('ufname', '*accept*', 'page'),
'DB.DBA.URL_REW_ODS_FOAF_EXT',
'(application|text)/rdf.(xml|n3|turtle|ttl)',
2,
303);
-- http://cname/dataspace/person/uname/foaf.ext
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_rule7', 1,
'/dataspace/person/([^/]*)/foaf.(rdf|n3|ttl)', vector('ufname', 'fmt'), 1,
'/ods/foaf.vsp?uname=%U&fmt=%U', vector('ufname', 'fmt'),
null,
null,
2,
null);
-- App Instance Gem
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_post_gem_rule', 1,
'/dataspace/([^/]*)/([^/]*)/([^/]*/)?([^/]*/)?(sioc|about)\\.(rdf|n3|ttl)', vector('ufname', 'app', 'inst'), 4,
'%s', vector('ufname'),
'DB.DBA.URL_REW_ODS_GEM');
-- Weblog Rules
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_blog_rule1', 1,
'/dataspace/([^/]*)/weblog/([^/]*)', vector('ufname', 'inst'), 2,
'%s', vector('inst'),
'DB.DBA.URL_REW_ODS_BLOG');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_blog_rule2', 1,
'/dataspace/([^/]*)/weblog/([^/]*)/([^/]*)', vector('ufname', 'inst', 'id'), 3,
'%s%s', vector('inst', 'id'),
'DB.DBA.URL_REW_ODS_BLOG');
-- Discussion rules
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_nntp_rule1', 1,
'/dataspace/discussion/([^/]*)', vector('grp'), 1,
'%s', vector('grp'),
'DB.DBA.URL_REW_ODS_NNTP');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_nntp_rule2', 1,
'/dataspace/discussion/([^/]*)/((?!sioc)(?!about)[^/]*)', vector('grp', 'post'), 2,
'%s', vector('post'),
'DB.DBA.URL_REW_ODS_NNTP');
-- Community
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_xd_rule1', 1,
'/dataspace/([^/]*)/community/([^/]*)', vector('ufname', 'inst'), 2,
'%s', vector('inst'),
'DB.DBA.URL_REW_ODS_XD');
-- Wiki
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_wiki_rule1', 1,
'/dataspace/([^/]*)/wiki/([^/]*)', vector('ufname', 'inst'), 2,
'%s', vector('inst'),
'DB.DBA.URL_REW_ODS_WIKI');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_wiki_rule2', 1,
'/dataspace/([^/]*)/wiki/([^/]*)/([^/]*)', vector('ufname', 'inst', 'post'), 2,
'%s%s', vector('inst', 'post'),
'DB.DBA.URL_REW_ODS_WIKI');
-- Gallery
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_photo_rule1', 1,
'/dataspace/([^/]*)/photos/([^/]*)', vector('ufname', 'inst'), 2,
'%s', vector('inst'),
'DB.DBA.URL_REW_ODS_PHOTO');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('ods_photo_rule2', 1,
'/dataspace/([^/]*)/photos/([^/]*)/([^/]*)', vector('ufname', 'inst', 'post'), 2,
'%s', vector('post'),
'DB.DBA.URL_REW_ODS_PHOTO');
-- AddressBook
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_addressbook_rule1',
1,
'/dataspace/([^/]*)/addressbook/([^/]*)',
vector('uname', 'instance'),
2,
'%s', vector('instance'),
'DB.DBA.URL_REW_ODS_ADDRESSBOOK');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_addressbook_rule2',
1,
'/dataspace/([^/]*)/addressbook/([^/]*)/(.*)',
vector('uname', 'instance', 'params'),
3,
'%s%s',
vector('instance', 'params'),
'DB.DBA.URL_REW_ODS_ADDRESSBOOK');
-- Bookmark
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_bookmark_rule1',
1,
'/dataspace/([^/]*)/bookmark/([^/]*)',
vector('uname', 'instance'),
2,
'%s', vector('instance'),
'DB.DBA.URL_REW_ODS_BOOKMARK');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_bookmark_rule2',
1,
'/dataspace/([^/]*)/bookmark/([^/]*)/(.*)',
vector('uname', 'instance', 'params'),
3,
'%s%s',
vector('instance', 'params'),
'DB.DBA.URL_REW_ODS_BOOKMARK');
-- Briefcase
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_briefcase_rule1',
1,
'/dataspace/([^/]*)/briefcase/([^/]*)',
vector('uname', 'instance'),
2,
'%s', vector('instance'),
'DB.DBA.URL_REW_ODS_BRIEFCASE');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_briefcase_rule2',
1,
'/dataspace/([^/]*)/briefcase/([^/]*)/(.*)',
vector('uname', 'instance', 'params'),
3,
'%s%s',
vector('instance', 'params'),
'DB.DBA.URL_REW_ODS_BRIEFCASE');
-- Calendar
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_calendar_rule1',
1,
'/dataspace/([^/]*)/calendar/([^/]*)',
vector('uname', 'instance'),
2,
'%s', vector('instance'),
'DB.DBA.URL_REW_ODS_CALENDAR');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_calendar_rule2',
1,
'/dataspace/([^/]*)/calendar/([^/]*)/(.*)',
vector('uname', 'instance', 'params'),
3,
'%s%s',
vector('instance', 'params'),
'DB.DBA.URL_REW_ODS_CALENDAR');
-- Feeds
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_feeds_rule1',
1,
'/dataspace/([^/]*)/feeds/([^/]*)',
vector('uname', 'instance'),
2,
'%s', vector('instance'),
'DB.DBA.URL_REW_ODS_FEEDS');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_feeds_rule2',
1,
'/dataspace/([^/]*)/feeds/([^/]*)/(.*)',
vector('uname', 'instance', 'params'),
3,
'%s%s',
vector('instance', 'params'),
'DB.DBA.URL_REW_ODS_FEEDS');
-- Polls
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_polls_rule1',
1,
'/dataspace/([^/]*)/polls/([^/]*)',
vector('uname', 'instance'),
2,
'%s', vector('instance'),
'DB.DBA.URL_REW_ODS_POLLS');
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ods_polls_rule2',
1,
'/dataspace/([^/]*)/polls/([^/]*)/(.*)',
vector('uname', 'instance', 'params'),
3,
'%s%s',
vector('instance', 'params'),
'DB.DBA.URL_REW_ODS_POLLS');
-- ODS Base rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_base_rule_list1', 1,
vector(
'ods_rule1', 'ods_rule2', 'ods_rule3', 'ods_rule4'
));
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_foaf_rule_list1', 1,
vector(
'ods_rule5', 'ods_rule6', 'ods_rule7'
));
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_gems_rule_list1', 1,
vector(
'ods_post_gem_rule'
));
-- ODS Blog rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_blog_rule_list1', 1,
vector(
'ods_blog_rule1', 'ods_blog_rule2'
));
-- ODS Discussion rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_nntp_rule_list1', 1,
vector(
'ods_nntp_rule1', 'ods_nntp_rule2'
));
-- ODS Community rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_xd_rule_list1', 1,
vector(
'ods_xd_rule1'
));
-- ODS Wiki rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_wiki_rule_list1', 1,
vector(
'ods_wiki_rule1', 'ods_wiki_rule2'
));
-- ODS Gallery rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_photo_rule_list1', 1,
vector(
'ods_photo_rule1', 'ods_photo_rule2'
));
-- ODS AddressBook rules
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ods_addressbook_rule_list1',
1,
vector (
'ods_addressbook_rule1',
'ods_addressbook_rule2'
));
-- ODS Bookmark rules
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ods_bookmark_rule_list1',
1,
vector (
'ods_bookmark_rule1',
'ods_bookmark_rule2'
));
-- ODS Briefcase rules
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ods_briefcase_rule_list1',
1,
vector (
'ods_briefcase_rule1',
'ods_briefcase_rule2'
));
-- ODS Calendar rules
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ods_calendar_rule_list1',
1,
vector (
'ods_calendar_rule1',
'ods_calendar_rule2'
));
-- ODS Feeds rules
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ods_feeds_rule_list1',
1,
vector (
'ods_feeds_rule1',
'ods_feeds_rule2'
));
-- ODS Polls rules
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ods_polls_rule_list1',
1,
vector (
'ods_polls_rule1',
'ods_polls_rule2'
));
-- All ODS Rules
DB.DBA.URLREWRITE_CREATE_RULELIST ('ods_rule_list1', 1,
vector(
'ods_base_rule_list1',
'ods_foaf_rule_list1',
'ods_blog_rule_list1',
'ods_nntp_rule_list1',
'ods_xd_rule_list1',
'ods_wiki_rule_list1',
'ods_photo_rule_list1',
'ods_addressbook_rule_list1',
'ods_bookmark_rule_list1',
'ods_briefcase_rule_list1',
'ods_calendar_rule_list1',
'ods_feeds_rule_list1',
'ods_polls_rule_list1',
'ods_gems_rule_list1'
));
DB.DBA.XML_SET_NS_DECL ('ods', 'http://www.openlinksw.com/virtuoso/ods/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsbusintoplweb">
<title>Oplweb to RDF</title>
<programlisting><![CDATA[
-- Setup script for RDF view of OpenLink Product Portfolio version 2
--
/*
* This view is currently designed to SPECIFICALLY load on data.openlinksw.com. We recommend you
* search for `openlinksw.com' (as `http://' is sometimes encoded) and replace with either the default
* URIQA macro or your own hostname as appropriate.
*/
-- views to get the codes out instead of the id's
---- in hindsight these should ALL have been handled with
---- proper IRI functions like the rest, oh well, no harm AFAIK
---- will know for next time or might even replace this later.
DROP VIEW oplweb2.oplweb.product_formats_categories;
CREATE VIEW oplweb2.oplweb.product_formats_categories (
product_cat_code, product_cat_id, product_format_code, product_format_id, product_family_id
) as
SELECT distinct
pc.product_cat_code,
pc.product_cat_id,
pf.product_format_code,
pf.product_format_id,
pc.product_family_id
FROM
oplweb2.oplweb.product_category pc,
oplweb2.oplweb.product_format pf,
oplweb2.oplweb.product p
WHERE
p.product_cat_id = pc.product_cat_id and
p.product_format_id = pf.product_format_id
AND EXISTS (
SELECT 1 FROM oplweb2.oplweb.component_archive ca
WHERE ca.product_id = p.product_id
)
;
DROP VIEW oplweb2.oplweb.product_with_code;
CREATE VIEW oplweb2.oplweb.product_with_code as
SELECT p.*, pc.product_cat_code, pf.product_format_code
FROM
oplweb2.oplweb.product_category pc,
oplweb2.oplweb.product_format pf,
oplweb2.oplweb.product p
WHERE
p.product_cat_id = pc.product_cat_id and
p.product_format_id = pf.product_format_id ;
DROP VIEW oplweb2.oplweb.product_category_with_code;
CREATE VIEW oplweb2.oplweb.product_category_with_code as
SELECT pc.*, pf.product_family_code
from
oplweb2.oplweb.product_category pc,
oplweb2.oplweb.product_family pf
where
pc.product_family_id = pf.product_family_id ;
DROP VIEW oplweb2.oplweb.product_family_features_with_code;
CREATE VIEW oplweb2.oplweb.product_family_features_with_code as
SELECT a.*, b.product_family_code
from
oplweb2.oplweb.product_family_features a,
oplweb2.oplweb.product_family b
where
a.product_family_id = b.product_family_id
;
DROP VIEW oplweb2.oplweb.product_format_features_with_code;
CREATE VIEW oplweb2.oplweb.product_format_features_with_code as
SELECT a.*, b.product_format_code
from
oplweb2.oplweb.product_format_features a,
oplweb2.oplweb.product_format b
where
a.product_format_id = b.product_format_id
;
DROP VIEW oplweb2.oplweb.product_category_features_with_code;
CREATE VIEW oplweb2.oplweb.product_category_features_with_code as
SELECT a.*, b.product_cat_code
from
oplweb2.oplweb.product_category_features a,
oplweb2.oplweb.product_category b
where
a.product_cat_id = b.product_cat_id
;
DROP VIEW oplweb2.oplweb.components_for_rdfs;
CREATE VIEW oplweb2.oplweb.components_for_rdfs as
SELECT *, cast(filesize as varchar) as str_filesize
from
oplweb2.oplweb.components
;
DROP VIEW oplweb2.oplweb.product_release_with_family;
CREATE VIEW oplweb2.oplweb.product_release_with_family as
SELECT a.*, b.opsys_family_id, c.dbms_family_id
from
oplweb2.oplweb.product_release a,
oplweb2.oplweb.opsys b,
oplweb2.oplweb.dbms_engine c
where
a.opsys_name = b.opsys_name and
a.dbms_name = c.dbms_name
;
drop view oplweb2.oplweb.archive_coverage_osdb;
create view oplweb2.oplweb.archive_coverage_osdb as
SELECT distinct
pfam.product_family_id, pfam.product_family_code,
p.product_format_id, pf.product_format_code,
p.product_cat_id, pc.product_cat_code,
p.product_id,
ca.opsys_name,
os.opsys_family_id,
ca.dbms_name,
db.dbms_family_id,
pr.processor_name,
pr.processor_mode_id,
pr.processor_family_id
from
oplweb2.oplweb.product p
join oplweb2.oplweb.product_category pc on (p.product_cat_id = pc.product_cat_id)
join oplweb2.oplweb.product_format pf on (p.product_format_id = pf.product_format_id)
join oplweb2.oplweb.product_family pfam on (pc.product_family_id = pfam.product_family_id)
join oplweb2.oplweb.component_archive ca on (ca.product_id = p.product_id)
join oplweb2.oplweb.opsys os on (os.opsys_name = ca.opsys_name)
join oplweb2.oplweb.dbms_engine db on (db.dbms_name = ca.dbms_name)
join oplweb2.oplweb.processors pr on (pr.processor_name = os.processor_name and pr.processor_mode_id = os.processor_mode_id)
;
GRANT SELECT ON oplweb2.oplweb.component_archive TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.component_archive_type TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.component_category TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.component_mode TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.component_type TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.components TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.components_for_rdfs TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.dbms_engine TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.dbms_family TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.download_location TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.download_protocol TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.download_partner TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.opsys TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.opsys_family TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.opsys_type TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.processor_family TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.processor_mode TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.processors TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_benefits TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_benefits_category TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_category TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_category_with_code TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_category_features TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_family TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_family_features TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_features TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_format TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_format_features TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_feature_category TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_release TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_release_features TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.vendor_category TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.vendor_category_family TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.vendors TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_formats_categories TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_with_code TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_family_features_with_code TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_format_features_with_code TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_category_features_with_code TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.product_release_with_family TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON oplweb2.oplweb.archive_coverage_osdb TO "SPARQL", "SPARQL_UPDATE";
drop index oplweb2_product_price_format_cat;
create index oplweb2_product_price_format_cat on oplweb2.oplweb.product_price(product_cat_id, product_format_id, product_price_type_id);
drop index oplweb2_product_discount_format_cat;
create index oplweb2_product_discount_format_cat on oplweb2.oplweb.product_general_discount(product_cat_id, product_format_id, product_price_type_id);
drop view oplweb2.DBA.license_model_type;
create view oplweb2.DBA.license_model_type (
product_release_id, product_cat_id, product_format_id, product_id, product_price_type_id
)
as
SELECT distinct
product_release_id,
pp.product_cat_id, pp.product_format_id, product_id,
product_price_type_id
FROM
oplweb2.oplweb.product_price pp,
oplweb2.oplweb.product p
WHERE p.product_cat_id = pp.product_cat_id AND
p.product_format_id = pp.product_format_id
;
grant SELECT on oplweb2.DBA.license_model_type to "SPARQL", "SPARQL_UPDATE";--, rdf;
drop view oplweb2.DBA.license_model;
create view oplweb2.DBA.license_model as
SELECT distinct
product_release_id,
pc.product_cat_id,
pc.product_format_id,
pc.product_cat_code,
pc.product_format_code,
pc.product_id,
pp.opsys_family_id, pp.dbms_family_id,
replace(oo.opsys_family_name, ' ', '') as opsys_family_name,
replace(dd.dbms_family_name, ' ', '') as dbms_family_name,
pp.opsys_type_id,
pp.product_price_type_id,
pp.product_price_unit_type_id
from
oplweb2.oplweb.product_price pp,
oplweb2.oplweb.product_with_code pc, --category pc,
--oplweb2.oplweb.product_format pf,
oplweb2.oplweb.opsys os,
oplweb2.oplweb.dbms_engine dbe,
oplweb2.oplweb.dbms_family dd,
oplweb2.oplweb.opsys_family oo
--oplweb2.oplweb.product p
where
pp.product_format_id = pc.product_format_id and
pp.product_cat_id = pc.product_cat_id and
pp.opsys_family_id = oo.opsys_family_id and
pp.dbms_family_id = dd.dbms_family_id
--p.product_cat_id = pc.product_cat_id and
--p.product_format_id = pf.product_format_id and
;
grant SELECT on oplweb2.DBA.license_model to "SPARQL", "SPARQL_UPDATE";--, rdf;
drop view oplweb2.DBA.license_model_units;
create view oplweb2.DBA.license_model_units as
SELECT distinct
lm1.product_release_id,
lm1.product_id,
lm1.opsys_family_
pp.opsys_family_id, pp.dbms_family_id,
replace(oo.opsys_family_name, ' ', '') as opsys_family_name,
replace(dd.dbms_family_name, ' ', '') as dbms_family_name,
pp.opsys_type_id, ot.short_description as opsys_type_code
from
oplweb2.oplweb.product_price pp,
oplweb2.oplweb.opsys_type ot,
oplweb2.oplweb.dbms_family dd,
oplweb2.oplweb.opsys_family oo
where
pp.opsys_type_id = ot.opsys_type_id and
pp.opsys_family_id = oo.opsys_family_id and
pp.dbms_family_id = dd.dbms_family_id
and
pp.product_release_id = '6.1'
;
grant SELECT on oplweb2.DBA.license_model_units to "SPARQL", "SPARQL_UPDATE";--, rdf;
drop view oplweb2.DBA.product_general_discount_vc;
create view oplweb2.DBA.product_general_discount_vc as
SELECT distinct
product_release_id,
pgd.product_cat_id, pc.product_cat_code,
pgd.product_format_id, pc.product_format_code,
pc.product_id,
pgd.opsys_family_id, pgd.dbms_family_id,
pgd.opsys_type_id,
product_discount_description,
product_price_type_id,
cast(unit_discount as varchar) as unit_discount,
discount_start,
discount_end,
discount_token
from
oplweb2.oplweb.product_general_discount pgd,
oplweb2.oplweb.product_with_code pc
where
pgd.product_format_id = pc.product_format_id and
pgd.product_cat_id = pc.product_cat_id
;
drop view oplweb2.DBA.product_price_varchar;
create view oplweb2.DBA.product_price_varchar as
select
pp.product_price_id,
pp.product_release_id,
pp.product_cat_id, pc.product_cat_code,
pp.product_format_id, pf.product_format_code,
pp.opsys_family_id, pp.dbms_family_id,
replace(oo.opsys_family_name, ' ', '') as opsys_family_name,
replace(dd.dbms_family_name, ' ', '') as dbms_family_name,
pp.opsys_type_id, ot.short_description as opsys_type_code,
pp.product_price_type_id,
pp.product_price_unit_type_id, cast(pp.unit_price as varchar) as unit_price,
pp.component_archive_available
from
oplweb2.oplweb.product_price pp,
oplweb2.oplweb.product_category pc,
oplweb2.oplweb.product_format pf,
oplweb2.oplweb.opsys_type ot,
oplweb2.oplweb.dbms_family dd,
oplweb2.oplweb.opsys_family oo
where
pp.product_format_id = pf.product_format_id and
pp.product_cat_id = pc.product_cat_id and
pp.opsys_type_id = ot.opsys_type_id and
pp.opsys_family_id = oo.opsys_family_id and
pp.dbms_family_id = dd.dbms_family_id
--and
--pp.product_release_id = '6.1'
;
grant SELECT on oplweb2.oplweb.product_price to "SPARQL", "SPARQL_UPDATE";--, rdf;
grant SELECT on oplweb2.oplweb.product_price_type to "SPARQL", "SPARQL_UPDATE";--, rdf;
grant SELECT on oplweb2.oplweb.product_price_unit_type to "SPARQL", "SPARQL_UPDATE";--, rdf;
grant SELECT on oplweb2.DBA.product_general_discount_vc to "SPARQL", "SPARQL_UPDATE";--, rdf;
grant SELECT on oplweb2.DBA.product_price_varchar to "SPARQL", "SPARQL_UPDATE";--, rdf;
grant SELECT on oplweb2.DBA.license_model_type to "SPARQL", "SPARQL_UPDATE";--, rdf;
DB.DBA.RDF_AUDIT_METADATA (1, '*');
--DB.DBA.RDF_AUDIT_METADATA (2, '*');
--sparql drop graph <http://www.openlinksw.com/dataspace/organization/openlink/ProductPortfolioOntology/1.0/>;
--possible previous graph now merging with this oplweb graph
sparql drop graph <http://data.openlinksw.com/shop_pricing/>;
--others that have a dependency on this graph that may need kicking first
--sparql drop graph <http://data.openlinksw.com/customer/>;
--sparql drop graph <http://data.openlinksw.com/support/>;
--sparql drop graph <http://data.openlinksw.com/shop_pricing/>;
SPARQL drop graph <http://www.openlinksw.com/schemas/oplweb#> ;
SPARQL drop graph <http://www.openlinksw.com/dataspace/organization/openlink/oplweb#> ;
SPARQL drop graph <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/> ;
-- should now use <http://www.openlinksw.com/dataspace/organization/openlink#this>
SPARQL drop quad map virtrdf:product_portfolio ;
--only use this if you really really mean it, it will totally nuke your RDF data, useful on
--test boxes in a bit of jam (hasn't happened to me for a while now)
--rdf_global_reset();
--utility for stripping url killing stuff from friendly strings used as ids
create function oplweb2.oplweb.FIXUP4URI (in _string varchar)
returns varchar
{
declare _s varchar;
_s := replace (_string, ' ', '');
_s := replace (_s, '&', '_');
_s := replace (_s, '/', '');
return _s;
}
;
--URI-IRI mapping functions
create function oplweb2.oplweb.DOWNLOAD_LOCATION_URI (in uri varchar)
returns varchar
{
return sprintf('http://data.openlinksw.com/oplweb/download_location/%s#this',
replace(uri, 'http://', ''));
};
create function oplweb2.oplweb.DOWNLOAD_LOCATION_URI_INVERSE (in dl_iri varchar)
returns varchar
{
declare parts any;
parts := sprintf_inverse(dl_iri,
'http://data.openlinksw.com/oplweb/download_location/%s#this', 1);
if (parts is not null)
{
return sprintf('http://%s', parts[0]);
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.DOWNLOAD_LOCATION_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.DOWNLOAD_LOCATION_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.DBMS_FAMILY_URI (in _family_id integer)
returns varchar
{
declare _family_string varchar;
SELECT dbms_family_name into _family_string
FROM oplweb2.oplweb.dbms_family
WHERE dbms_family_id = _family_id ;
return sprintf('http://data.openlinksw.com/oplweb/dbms_family/%s#this',
oplweb2.oplweb.FIXUP4URI(_family_string));
};
create function oplweb2.oplweb.DBMS_FAMILY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _family_id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/dbms_family/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 dbms_family_id into _family_id FROM oplweb2.oplweb.dbms_family
WHERE lower(oplweb2.oplweb.FIXUP4URI(dbms_family_name)) = lower(parts[0]);
return _family_id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.DBMS_FAMILY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.DBMS_FAMILY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.COMPONENT_CATEGORY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.component_category
WHERE component_category_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/component_category/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.COMPONENT_CATEGORY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/component_category/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 component_category_id into _id FROM oplweb2.oplweb.component_category
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_CATEGORY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_CATEGORY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.COMPONENT_MODE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.component_mode
WHERE component_mode_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/component_mode/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.COMPONENT_MODE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/component_mode/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 component_mode_id into _id FROM oplweb2.oplweb.component_mode
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_MODE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_MODE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.COMPONENT_TYPE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.component_type
WHERE component_type_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/component_type/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.COMPONENT_TYPE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/component_type/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 component_type_id into _id FROM oplweb2.oplweb.component_type
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_TYPE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_TYPE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.COMPONENT_ARCHIVE_TYPE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT component_archive_short_name into _string
FROM oplweb2.oplweb.component_archive_type
WHERE component_archive_type_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/component_archive_type/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.COMPONENT_ARCHIVE_TYPE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/component_archive_type/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 component_archive_type_id into _id FROM oplweb2.oplweb.component_archive_type
WHERE lower(oplweb2.oplweb.FIXUP4URI(component_archive_short_name)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_ARCHIVE_TYPE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.COMPONENT_ARCHIVE_TYPE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.FEATURE_BENEFIT_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT product_benefit_desc into _string
FROM oplweb2.oplweb.product_benefits
WHERE product_benefit_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/feature_benefit/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.FEATURE_BENEFIT_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/feature_benefit/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_benefit_id into _id FROM oplweb2.oplweb.product_benefits
WHERE lower(oplweb2.oplweb.FIXUP4URI(product_benefit_desc)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.FEATURE_BENEFIT_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.FEATURE_BENEFIT_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.OPSYS_FAMILY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT opsys_family_name into _string
FROM oplweb2.oplweb.opsys_family
WHERE opsys_family_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/opsys_family/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.OPSYS_FAMILY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/opsys_family/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 opsys_family_id into _id FROM oplweb2.oplweb.opsys_family
WHERE lower(oplweb2.oplweb.FIXUP4URI(opsys_family_name)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.OPSYS_FAMILY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.OPSYS_FAMILY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.OPSYS_TYPE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.opsys_type
WHERE opsys_type_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/opsys_type/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.OPSYS_TYPE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/opsys_type/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT TOP 1 opsys_type_id into _id FROM oplweb2.oplweb.opsys_type
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.OPSYS_TYPE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.OPSYS_TYPE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PROCESSOR_FAMILY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT processor_family_name into _string
FROM oplweb2.oplweb.processor_family
WHERE processor_family_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/processor_family/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PROCESSOR_FAMILY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/processor_family/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 processor_family_id into _id FROM oplweb2.oplweb.processor_family
WHERE lower(oplweb2.oplweb.FIXUP4URI(processor_family_name)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PROCESSOR_FAMILY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PROCESSOR_FAMILY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
--FIXME might have to do something with possible & symbols
create function oplweb2.oplweb.PROCESSOR_MODE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT processor_mode_name into _string
FROM oplweb2.oplweb.processor_mode
where processor_mode_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/processor_mode/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PROCESSOR_MODE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/processor_mode/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 processor_mode_id into _id FROM oplweb2.oplweb.processor_mode
WHERE lower(oplweb2.oplweb.FIXUP4URI(processor_mode_name)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PROCESSOR_MODE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PROCESSOR_MODE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_CATEGORY_FEATURE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.product_category_features
WHERE product_category_feature_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_category_feature/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_CATEGORY_FEATURE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_category_feature/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_category_feature_id into _id FROM oplweb2.oplweb.product_category_features
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_CATEGORY_FEATURE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_CATEGORY_FEATURE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_FAMILY_FEATURE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.product_family_features
WHERE product_family_feature_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_family_feature/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_FAMILY_FEATURE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_family_feature/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_family_feature_id into _id FROM oplweb2.oplweb.product_family_features
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FAMILY_FEATURE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FAMILY_FEATURE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_FEATURE_CATEGORY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_desc into _string
FROM oplweb2.oplweb.product_feature_category
WHERE product_feature_category_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_feature_category/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_FEATURE_CATEGORY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_feature_category/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_feature_category_id into _id FROM oplweb2.oplweb.product_feature_category
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_desc)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FEATURE_CATEGORY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FEATURE_CATEGORY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_FEATURE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.product_features
WHERE product_feature_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_feature/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_FEATURE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_feature/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_feature_id into _id FROM oplweb2.oplweb.product_features
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FEATURE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FEATURE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_FORMAT_FEATURE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.product_format_features
WHERE product_format_feature_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_format_feature/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_FORMAT_FEATURE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_format_feature/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_format_feature_id into _id FROM oplweb2.oplweb.product_format_features
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FORMAT_FEATURE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_FORMAT_FEATURE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_RELEASE_FEATURE_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT short_description into _string
FROM oplweb2.oplweb.product_release_features
WHERE product_release_feature_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_release_feature/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_RELEASE_FEATURE_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_release_feature/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_release_feature_id into _id FROM oplweb2.oplweb.product_release_features
WHERE lower(oplweb2.oplweb.FIXUP4URI(short_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_RELEASE_FEATURE_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_RELEASE_FEATURE_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_BENEFIT_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT product_benefit_desc into _string
FROM oplweb2.oplweb.product_benefits
WHERE product_benefit_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_benefit/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_BENEFIT_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_benefit/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_benefit_id into _id FROM oplweb2.oplweb.product_benefits
WHERE lower(oplweb2.oplweb.FIXUP4URI(product_benefit_desc)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_BENEFIT_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_BENEFIT_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.PRODUCT_BENEFIT_CATEGORY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT description into _string
FROM oplweb2.oplweb.product_benefits_category
WHERE product_benefit_category_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/product_benefit_category/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.PRODUCT_BENEFIT_CATEGORY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/product_benefit_category/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 product_benefit_category_id into _id FROM oplweb2.oplweb.product_benefits_category
WHERE lower(oplweb2.oplweb.FIXUP4URI(description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_BENEFIT_CATEGORY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.PRODUCT_BENEFIT_CATEGORY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.VENDOR_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT vendor_name into _string
FROM oplweb2.oplweb.vendors
where vendor_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/vendor/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.VENDOR_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/vendor/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 vendor_id into _id FROM oplweb2.oplweb.vendors
WHERE lower(oplweb2.oplweb.FIXUP4URI(vendor_name)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.VENDOR_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.VENDOR_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.VENDOR_CATEGORY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT vendor_category_description into _string
FROM oplweb2.oplweb.vendor_category
where vendor_category_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/vendor_category/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.VENDOR_CATEGORY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/vendor_category/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 vendor_category_id into _id FROM oplweb2.oplweb.vendor_category
WHERE lower(oplweb2.oplweb.FIXUP4URI(vendor_category_description)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.VENDOR_CATEGORY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.VENDOR_CATEGORY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.VENDOR_CATEGORY_FAMILY_URI (in _id integer)
returns varchar
{
declare _string varchar;
SELECT vendor_category_family_desc into _string
FROM oplweb2.oplweb.vendor_category_family
where vendor_category_family_id = _id ;
return sprintf('http://data.openlinksw.com/oplweb/vendor_category_family/%s#this',
oplweb2.oplweb.FIXUP4URI(_string));
};
create function oplweb2.oplweb.VENDOR_CATEGORY_FAMILY_URI_INVERSE (in _iri varchar)
returns integer
{
declare parts any;
declare _id integer;
parts := sprintf_inverse(_iri,
'http://data.openlinksw.com/oplweb/vendor_category_family/%s#this', 1);
if (parts is not null)
{
declare exit handler for not found return null;
SELECT top 1 vendor_category_family_id into _id FROM oplweb2.oplweb.vendor_category_family
WHERE lower(oplweb2.oplweb.FIXUP4URI(vendor_category_family_desc)) = lower(parts[0]);
return _id;
}
return NULL;
};
GRANT EXECUTE ON oplweb2.oplweb.VENDOR_CATEGORY_FAMILY_URI TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON oplweb2.oplweb.VENDOR_CATEGORY_FAMILY_URI_INVERSE TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LIT_PRODUCT_RELEASE_LABEL (
in _product_id varchar, in _id integer, in _opsys_name varchar, in _dbms_name varchar
)
returns varchar
{
declare _string varchar;
SELECT 'OpenLink ' || poduct_description || ' (Release ' || product_release_id || ') on ' || commercial_name into _string
FROM oplweb2.oplweb.product_release pr,
oplweb2.oplweb.product p,
oplweb2.oplweb.opsys o
where
p.product_id = pr.product_id and
o.opsys_name = pr.opsys_name and
pr.product_release_id = _id and
pr.product_id = _product_id and
pr.opsys_name = _opsys_name and
pr.dbms_name = _dbms_name ;
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LIT_PRODUCT_RELEASE_LABEL TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LIT_FORMAT_CAT_LABEL (
in _format integer, in _cat integer
)
returns varchar
{
declare _string varchar;
SELECT top 1 'OpenLink ' || cast(product_format_description as varchar) || ' ' || cast(product_category_description as varchar) into _string
from
oplweb2.oplweb.product_formats_categories fc,
oplweb2.oplweb.product_format f,
oplweb2.oplweb.product_category c
where
fc.product_format_id = f.product_format_id and
fc.product_cat_id = c.product_cat_id and
fc.product_format_id = _format and
fc.product_cat_id = _cat;
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LIT_FORMAT_CAT_LABEL TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_openlink_logo (in _code varchar)
returns varchar
{
declare _string varchar;
SELECT top 1 product_family_logo_url into _string
FROM oplweb2.oplweb.product_family
WHERE product_family_code = _code;
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_openlink_logo TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_homepage (in _code varchar)
returns varchar
{
declare _string varchar;
SELECT top 1 product_family_homepage into _string
FROM oplweb2.oplweb.product_family
WHERE product_family_code = _code;
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_homepage TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_opsys_icon (in _id integer)
returns varchar
{
declare _string varchar; _string := '';
SELECT top 1 opsys_icon_name into _string
FROM oplweb2.oplweb.opsys_family
where opsys_family_id = _id;
_string := 'http://download.openlinksw.com/download/images/'||_string;
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_opsys_icon TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_to_shop (
in release_id varchar,
in product_id varchar,
in opsys varchar,
in dbms varchar
)
returns varchar
{
declare _string varchar; _string := '';
declare _cat, _format, _prod varchar;
_prod := product_id;
SELECT top 1 cast(product_cat_id as varchar), cast(product_format_id as varchar)
into _cat, _format
FROM oplweb2.oplweb.product p
WHERE p.product_id = _prod;
_string := sprintf(
'https://shop.openlinksw.com/?product_release_id=%s&product=%s&product_cat=%V&product_format=%V&os=%s&db=%s&buyme=yes',
release_id, product_id, _cat, _format, opsys, dbms
);
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_to_shop TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_license_model_type (
in _product_price_type_id integer
)
returns varchar
{
declare _string varchar; _string := '';
SELECT top 1 product_price_type_description into _string FROM oplweb2.oplweb.product_price_type
WHERE product_price_type_id = _product_price_type_id;
return _string || ' License';
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_license_model_type TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_license_model_explain (
in _product_price_type_id integer
)
returns varchar
{
declare _string varchar; _string := '';
SELECT top 1 product_price_type_long_description into _string FROM oplweb2.oplweb.product_price_type
WHERE product_price_type_id = _product_price_type_id;
return _string;
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_license_model_explain TO "SPARQL", "SPARQL_UPDATE";
create function oplweb2.oplweb.LITRDF_shop_sample (
in release_id varchar,
in product_id varchar,
in opsys varchar,
in dbms varchar
)
returns varchar
{
declare _string varchar; _string := '';
declare _cat, _format, _prod, _pricetype varchar;
_prod := product_id;
SELECT top 1 cast(product_cat_id as varchar), cast(product_format_id as varchar), cast(product_price_type_id as varchar)
into _cat, _format, _pricetype
FROM oplweb2.DBA.license_model p, oplweb2.oplweb.opsys o, oplweb2.oplweb.dbms_engine e
WHERE p.product_id = _prod and product_release_id = release_id and o.opsys_name = opsys and e.dbms_name = dbms
and p.dbms_family_id = e.dbms_family_id and o.opsys_family_id = p.opsys_family_id;
_string := sprintf(
'https://shop.openlinksw.com/price_calc.vsp?release=%s&cat=%V&format=%V&os=%s&db=%s&lictype=%V',
release_id, _cat, _format, opsys, dbms, _pricetype
);
return http_client(_string);
};
GRANT EXECUTE ON oplweb2.oplweb.LITRDF_shop_sample TO "SPARQL", "SPARQL_UPDATE";
-- $Id: rdfandsparql.xml,v 1.95.2.36 2010/07/08 15:18:23 source Exp $
-- Setup script for RDF view of OpenLink Product Portfolio version 2
--
--
-- This view is currently designed to SPECIFICALLY load on data.openlinksw.com. The default URI macro has NOT
-- been used here because it makes no sense on the target box which is actually my.usnet.private:8891 or
-- something similar. If you want to use this view on another box, a simple search-replace should do the trick,
-- but search-replace just`data.openlinksw.com' because http:// is sometimes encoded and you would miss it.
--
--
SPARQL drop quad map virtrdf:product_portfolio2 ;
SPARQL drop quad map virtrdf:product_portfolio ;
SPARQL
prefix opl: <http://www.openlinksw.com/schemas/oplweb#>
drop iri class opl:DownloadLocation .
drop iri class opl:ComponentCategory .
drop iri class opl:Component .
drop iri class opl:ComponentArchive .
drop iri class opl:ComponentArchiveType .
drop iri class opl:ComponentCategory .
drop iri class opl:ComponentMode .
drop iri class opl:ComponentType .
drop iri class opl:DbmsEngine .
drop iri class opl:DbmsFamily .
drop iri class opl:DownloadProtocol .
drop iri class opl:DownloadPartner .
drop iri class opl:FeatureBenefit .
drop iri class opl:Opsys .
drop iri class opl:OpsysFamily .
drop iri class opl:OpsysType .
drop iri class opl:Processor .
drop iri class opl:ProcessorFamily .
drop iri class opl:ProcessorMode .
drop iri class opl:ProductRelease .
drop iri class opl:Product .
drop iri class opl:ProductCategory .
drop iri class opl:ProductCategoryFeature .
drop iri class opl:ProductPortfolio .
drop iri class opl:ProductFamily .
drop iri class opl:ProductFamilyFeature .
drop iri class opl:ProductFeatureCategory .
drop iri class opl:ProductFeature .
drop iri class opl:ProductFormat .
drop iri class opl:ProductFormatCategory .
drop iri class opl:ProductFormatFeature .
drop iri class opl:ProductReleaseFeature .
drop iri class opl:ProductBenefit .
drop iri class opl:ProductBenefitCategory .
drop iri class opl:Vendor .
drop iri class opl:VendorCategory .
drop iri class opl:VendorCategoryFamily .
drop iri class opl:PriceType .
drop iri class opl:PriceUnitType .
drop iri class opl:PriceUnitIncrementalDiscount .
drop iri class opl:ProductPrice .
drop iri class opl:LicenseType .
drop iri class opl:LicenseModel .
drop iri class opl:LicenseClass .
drop iri class opl:Discount .
drop literal class opl:lit_product_release_label .
drop literal class opl:lit_format_cat_label .
drop literal class opl:lit_openlink_logo .
drop iri class opl:lit_openlink_logo .
drop literal class opl:lit_homepage .
drop iri class opl:lit_homepage .
drop literal class opl:lit_opsys_icon .
drop iri class opl:lit_opsys_icon .
drop literal class opl:lit_to_shop .
drop iri class opl:lit_to_shop .
drop literal class opl:lit_license_model_type .
drop literal class opl:lit_license_model_explain .
drop literal class opl:lit_shop_sample .
drop literal class opl:lit_wikipedia_to_dbpedia .
drop iri class opl:lit_wikipedia_to_dbpedia .
drop literal class opl:lit_to_string .
drop iri class opl:wwwsitefamily .
drop iri class opl:wwwsiteformat .
drop iri class opl:wwwsitecategory .
drop iri class opl:wwwsiteproduct .
;
DB.DBA.RDF_AUDIT_METADATA (1, '*');
SPARQL
prefix opl: <http://www.openlinksw.com/schemas/oplweb#>
create iri class opl:Component "http://data.openlinksw.com/oplweb/component/%s#this"
(in component_name varchar not null) .
create iri class opl:ComponentArchive "http://data.openlinksw.com/oplweb/component_archive/%s#this"
(in component_archive_name varchar not null) .
create iri class opl:ComponentArchiveType using
function oplweb2.oplweb.COMPONENT_CATEGORY_URI (in _id integer not null)
returns varchar,
function oplweb2.oplweb.COMPONENT_CATEGORY_URI_INVERSE (in _iri varchar)
returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/component_archive_type/%s#this' ).
create iri class opl:ComponentCategory using
function oplweb2.oplweb.COMPONENT_CATEGORY_URI (in _id integer not null)
returns varchar,
function oplweb2.oplweb.COMPONENT_CATEGORY_URI_INVERSE (in _iri varchar)
returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/component_category/%s#this' ).
create iri class opl:ComponentMode using
function oplweb2.oplweb.COMPONENT_MODE_URI (in _id integer not null)
returns varchar,
function oplweb2.oplweb.COMPONENT_MODE_URI_INVERSE (in _iri varchar)
returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/component_mode/%s#this' ).
create iri class opl:ComponentType using
function oplweb2.oplweb.COMPONENT_TYPE_URI (in _id integer not null)
returns varchar,
function oplweb2.oplweb.COMPONENT_TYPE_URI_INVERSE (in _iri varchar)
returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/component_type/%s#this' ).
create iri class opl:DbmsFamily using
function oplweb2.oplweb.DBMS_FAMILY_URI (in _family_id integer not null)
returns varchar,
function oplweb2.oplweb.DBMS_FAMILY_URI_INVERSE (in _iri varchar)
returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/dbms_family/%s#this' ).
create iri class opl:DbmsEngine "http://data.openlinksw.com/oplweb/dbms_engine/%s#this"
(in dbms_name varchar not null) .
create iri class opl:DownloadLocation using
function oplweb2.oplweb.DOWNLOAD_LOCATION_URI (in uri varchar not null)
returns varchar,
function oplweb2.oplweb.DOWNLOAD_LOCATION_URI_INVERSE (in dl_iri varchar)
returns varchar
option (bijection, returns 'http://data.openlinksw.com/oplweb/download_location/%s#this' ).
create iri class opl:DownloadProtocol "http://data.openlinksw.com/oplweb/download_protocol/%s#this"
(in protocol_name varchar not null) .
create iri class opl:DownloadPartner "http://data.openlinksw.com/oplweb/download_partner/%s/%s#this"
(
in host_name varchar not null,
in domain_name varchar not null
) .
create iri class opl:FeatureBenefit using
function oplweb2.oplweb.FEATURE_BENEFIT_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.FEATURE_BENEFIT_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/feature_benefit/%s#this' ).
create iri class opl:Opsys "http://data.openlinksw.com/oplweb/opsys/%s#this"
(in opsys_name varchar not null) .
create iri class opl:OpsysFamily using
function oplweb2.oplweb.OPSYS_FAMILY_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.OPSYS_FAMILY_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/opsys_family/%s#this' ).
create iri class opl:OpsysType using
function oplweb2.oplweb.OPSYS_TYPE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.OPSYS_TYPE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/opsys_type/%s#this' ).
create iri class opl:Processor "http://data.openlinksw.com/oplweb/processor/%s/%d#this"
(in processor_name varchar not null, in processor_mode_id integer not null) .
create iri class opl:ProcessorFamily using
function oplweb2.oplweb.PROCESSOR_FAMILY_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PROCESSOR_FAMILY_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/processor_family/%s#this' ).
create iri class opl:ProcessorMode using
function oplweb2.oplweb.PROCESSOR_MODE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PROCESSOR_MODE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/processor_mode/%s#this' ).
create iri class opl:Product "http://data.openlinksw.com/oplweb/product/%s#this"
(in product_id varchar not null) .
create iri class opl:ProductCategory "http://data.openlinksw.com/oplweb/product_category/%s#this"
(in product_cat_code varchar not null) .
create iri class opl:ProductCategoryFeature using
function oplweb2.oplweb.PRODUCT_CATEGORY_FEATURE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_CATEGORY_FEATURE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_category_feature/%s#this' ).
create iri class opl:ProductPortfolio "http://data.openlinksw.com/oplweb/portfolio/%s#this"
(in x varchar not null) .
create iri class opl:ProductFamily "http://data.openlinksw.com/oplweb/product_family/%s#this"
(in product_family_code varchar not null) .
create iri class opl:ProductFamilyFeature using
function oplweb2.oplweb.PRODUCT_FAMILY_FEATURE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_FAMILY_FEATURE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_family_feature/%s#this' ).
create iri class opl:ProductFeatureCategory using
function oplweb2.oplweb.PRODUCT_FEATURE_CATEGORY_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_FEATURE_CATEGORY_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_feature_category/%s#this' ).
create iri class opl:ProductFeature using
function oplweb2.oplweb.PRODUCT_FEATURE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_FEATURE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_feature/%s#this' ).
create iri class opl:ProductFormat "http://data.openlinksw.com/oplweb/product_format/%s#this"
(in product_format_code varchar not null) .
create iri class opl:ProductFormatCategory "http://data.openlinksw.com/oplweb/product_format_category/%s/%s#this"
(in product_format_code varchar not null, in product_cat_code varchar not null) .
create iri class opl:ProductFormatFeature using
function oplweb2.oplweb.PRODUCT_FORMAT_FEATURE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_FORMAT_FEATURE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_format_feature/%s#this' ).
create iri class opl:ProductReleaseFeature using
function oplweb2.oplweb.PRODUCT_RELEASE_FEATURE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_RELEASE_FEATURE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_release_feature/%s#this' ).
create iri class opl:ProductBenefit using
function oplweb2.oplweb.PRODUCT_BENEFIT_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_BENEFIT_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_benefit/%s#this' ).
create iri class opl:ProductBenefitCategory using
function oplweb2.oplweb.PRODUCT_BENEFIT_CATEGORY_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.PRODUCT_BENEFIT_CATEGORY_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/product_benefit_category/%s#this' ).
create iri class opl:ProductRelease "http://data.openlinksw.com/oplweb/product_release/%s/%s/%s/%s#this"
(
in product_id varchar not null,
in product_release_id varchar not null,
in opsys_name varchar not null,
in dbms_name varchar not null
) .
create iri class opl:Vendor using
function oplweb2.oplweb.VENDOR_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.VENDOR_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/vendor/%s#this' ).
create iri class opl:VendorCategory using
function oplweb2.oplweb.VENDOR_CATEGORY_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.VENDOR_CATEGORY_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/vendor_category/%s#this' ).
create iri class opl:VendorCategoryFamily using
function oplweb2.oplweb.VENDOR_CATEGORY_FAMILY_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.VENDOR_CATEGORY_FAMILY_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/vendor_category_family/%s#this' ).
create iri class opl:PriceType "http://data.openlinksw.com/oplweb/price_type/%d#this"
(in product_price_type_id integer not null) .
create iri class opl:LicenseType using
function oplweb2.oplweb.LICENSE_MODEL_TYPE_URI (in _id integer not null) returns varchar,
function oplweb2.oplweb.LICENSE_MODEL_TYPE_URI_INVERSE (in _iri varchar) returns integer
option (bijection, returns 'http://data.openlinksw.com/oplweb/license_type/%s#this' ).
create iri class opl:PriceUnitType "http://data.openlinksw.com/oplweb/price_unit_type/%s_%s_%d_%d_%d_%s#this"
(
in product_release_id varchar not null,
in product_id varchar not null,
in opsys_family_id integer not null,
in dbms_family_id integer not null,
in product_price_type_id integer not null,
in product_price_unit_type_id varchar not null) .
create iri class opl:PriceUnitIncrementalDiscount "http://data.openlinksw.com/oplweb/price_unit_discount/%s_%s_%d_%d_%d_%s#this"
(
in product_release_id varchar not null,
in product_id varchar not null,
in opsys_family_id integer not null,
in dbms_family_id integer not null,
in product_price_type_id integer not null,
in product_price_unit_type_id varchar not null) .
create iri class opl:ProductPrice "http://data.openlinksw.com/oplweb/product_price/%d#this"
(in product_price_id integer not null) .
create iri class opl:LicenseModel "http://data.openlinksw.com/oplweb/license_model/%s_%s_%d_%d_%d#this"
(
in product_release_id varchar not null,
in product_id varchar not null,
in opsys_family_id integer not null,
in dbms_family_id integer not null,
in product_price_type_id integer not null
) .
create iri class opl:Discount "http://data.openlinksw.com/oplweb/discount/%s/%d/%s/%d/%d/%d#this"
(
in product_release_id varchar not null,
in opsys_type_id integer not null,
in product_id varchar not null,
in opsys_family_id integer not null,
in dbms_family_id integer not null,
in product_price_type_id integer not null
) .
create iri class opl:wwwsitefamily "http://%s.openlinksw.com/"
(
in product_family_code varchar not null
) .
create iri class opl:wwwsitecategory "http://%s.openlinksw.com/%s/"
(
in product_family_code varchar not null,
in product_category_code varchar not null
) .
create iri class opl:wwwsiteformat "http://%s.openlinksw.com/%s/%s/"
(
in product_family_code varchar not null,
in product_category_code varchar not null,
in product_format_code varchar not null
) .
create iri class opl:Uri "%s"
( in uri varchar not null
) .
create literal class opl:lit_product_release_label using
function oplweb2.oplweb.LIT_PRODUCT_RELEASE_LABEL(
in _product_id varchar, in _id integer, in _opsys_name varchar, in _dbms_name varchar
)
returns varchar .
create literal class opl:lit_format_cat_label using
function oplweb2.oplweb.LIT_FORMAT_CAT_LABEL(
in _format integer, in _cat integer
)
returns varchar .
create iri class opl:lit_openlink_logo using
function oplweb2.oplweb.LITRDF_openlink_logo(
in _code varchar
)
returns varchar .
create iri class opl:lit_homepage using
function oplweb2.oplweb.LITRDF_homepage(
in _code varchar
)
returns varchar .
create iri class opl:lit_opsys_icon using
function oplweb2.oplweb.LITRDF_opsys_icon(
in _id integer
)
returns varchar .
create iri class opl:lit_to_shop using
function oplweb2.oplweb.LITRDF_to_shop(
in release_id varchar,
in product_id varchar,
in opsys varchar,
in dbms varchar
)
returns varchar .
create literal class opl:lit_license_model_type using
function oplweb2.oplweb.LITRDF_license_model_type (
in _product_price_type_id integer
)
returns varchar .
create literal class opl:lit_license_model_explain using
function oplweb2.oplweb.LITRDF_license_model_explain (
in _product_price_type_id integer
)
returns varchar .
create literal class opl:lit_shop_sample using
function oplweb2.oplweb.LITRDF_shop_sample (
in release_id varchar,
in product_id varchar,
in opsys varchar,
in dbms varchar
)
returns varchar .
create iri class opl:lit_wikipedia_to_dbpedia using
function oplweb2.oplweb.LITRDF_wikipedia_to_dbpedia (
in wikipedia_url varchar
)
returns varchar .
create literal class opl:lit_to_string using
function oplweb2.oplweb.LITRDF_to_string (
in _s varchar
)
returns varchar .
create iri class opl:wwwsiteproduct using
function oplweb2.oplweb.wwwsiteproduct_URI (in _id varchar not null) returns varchar,
function oplweb2.oplweb.wwwsiteproduct_URI_INVERSE (in _iri varchar) returns varchar
.
make opl:ProductCategory subclass of opl:ProductFamily .
make opl:Product subclass of opl:ProductCategory .
make opl:Product subclass of opl:ProductFormat .
make opl:ProductRelease subclass of opl:Product .
make opl:Opsys subclass of opl:OpsysFamily .
make opl:DbmsEngine subclass of opl:DbmsFamily .
;
DB.DBA.RDF_AUDIT_METADATA (1, '*');
SPARQL
prefix opl: <http://www.openlinksw.com/schemas/oplweb#>
prefix dc: <http://purl.org/dc/terms#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix oplds: <http://www.openlinksw.com/dataspace/organization/openlink#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix umbel: <http://umbel.org/umbel/sc/>
prefix gr: <http://purl.org/goodrelations/v1#>
alter quad storage virtrdf:DefaultQuadStorage
FROM oplweb2.oplweb.component_archive as component_archive_tbl
FROM oplweb2.oplweb.component_archive_type as component_archive_type_tbl
FROM oplweb2.oplweb.component_category as component_category_tbl text literal component_category_long_description
FROM oplweb2.oplweb.component_mode as component_mode_tbl
FROM oplweb2.oplweb.component_type as component_type_tbl
FROM oplweb2.oplweb.components_for_rdfs as components_tbl
FROM oplweb2.oplweb.dbms_engine as dbms_engine_tbl
FROM oplweb2.oplweb.dbms_family as dbms_family_tbl
FROM oplweb2.oplweb.download_location as download_location_tbl
FROM oplweb2.oplweb.download_protocol as download_protocol_tbl
FROM oplweb2.oplweb.download_partner as download_partner_tbl
FROM oplweb2.oplweb.opsys as opsys_tbl
FROM oplweb2.oplweb.opsys_family as opsys_family_tbl
FROM oplweb2.oplweb.opsys_type as opsys_type_tbl
FROM oplweb2.oplweb.processor_family as processor_family_tbl
FROM oplweb2.oplweb.processor_mode as processor_mode_tbl
FROM oplweb2.oplweb.processors as processors_tbl
FROM oplweb2.oplweb.product as product_tbl text literal long_description
FROM oplweb2.oplweb.product_benefits as product_benefits_tbl text literal product_benefit_explanation
FROM oplweb2.oplweb.product_benefits_category as product_benefits_category_tbl
FROM oplweb2.oplweb.product_category as product_category_tbl
FROM oplweb2.oplweb.product_category_features_with_code as product_category_features_tbl text literal long_description
FROM oplweb2.oplweb.product_family as product_family_tbl
FROM oplweb2.oplweb.product_family as product_family_tbl_2
FROM oplweb2.oplweb.product_family_features_with_code as product_family_features_tbl text literal long_description
FROM oplweb2.oplweb.product_features as product_features_tbl text literal long_description
FROM oplweb2.oplweb.product_feature_category as product_feature_category_tbl text literal description
FROM oplweb2.oplweb.product_format_features_with_code as product_format_features_tbl text literal long_description
FROM oplweb2.oplweb.product_release_features as product_release_features_tbl text literal long_description
FROM oplweb2.oplweb.product_release_with_family as product_release_tbl
FROM oplweb2.oplweb.vendor_category as vendor_category_tbl
FROM oplweb2.oplweb.vendor_category_family as vendor_category_family_tbl
FROM oplweb2.oplweb.vendors as vendors_tbl
FROM oplweb2.oplweb.product_formats_categories as product_formats_categories
FROM oplweb2.oplweb.product_with_code as product_with_code
FROM oplweb2.oplweb.product_category_with_code as product_category_with_code
FROM oplweb2.oplweb.product_format as product_format_with_code
FROM oplweb2.oplweb.product_price as pp
FROM oplweb2.oplweb.product_price_type as pt
FROM oplweb2.DBA.license_model_unit_type as put
FROM oplweb2.DBA.license_model_unit_type as put2
FROM oplweb2.DBA.license_model as lm
FROM oplweb2.DBA.license_model as lm2
FROM oplweb2.DBA.license_model_type as license_model_type_tbl
FROM oplweb2.DBA.product_price_varchar as ppv
FROM oplweb2.DBA.product_general_discount_vc as gd
FROM oplweb2.oplweb.archive_coverage_osdb as ac1
{
create virtrdf:product_portfolio as
graph <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
{
opl:ProductPortfolio(product_family_tbl.product_family_code)
a opl:ProductPortfolio
as virtrdf:OplProductPortfolio .
opl:ProductPortfolio(product_family_tbl.product_family_code) opl:hasProductFamilies
opl:ProductFamily(product_family_tbl.product_family_code)
as virtrdf:OplProductPortfolioProductFamily .
opl:ProductFamily(product_family_tbl.product_family_code)
a opl:ProductFamily
as virtrdf:OplProductFamily ;
rdfs:label product_family_tbl.product_family_description
as virtrdf:rdfsOplProductFamilyDescription ;
foaf:name product_family_tbl.product_family_description
as virtrdf:nameOplProductFamilyDescription ;
foaf:logo opl:lit_openlink_logo(product_family_tbl.product_family_code)
as virtrdf:logoOpenLinkSoftware ;
foaf:homepage opl:lit_homepage(product_family_tbl.product_family_code)
as virtrdf:homepageProductFamily ;
foaf:homepage opl:wwwsitefamily(product_family_tbl.product_family_code)
# where (
# ^{product_family_tbl.}^.product_family_code = 'uda'
# )
as virtrdf:homepageProductFamilyUda ;
foaf:maker oplds:this
as virtrdf:OplDataspaceOpenLinkUri ;
owl:sameAs product_family_tbl.dbpedia_uri
as virtrdf:OplFamilyOwlSameAsDBPediaUri ;
opl:ProductFamilyCode product_family_tbl.product_family_code
as virtrdf:OplProductFamilyCode ;
opl:ProductFamilyDescription product_family_tbl.product_family_description
as virtrdf:OplProductFamilyDescription ;
dc:description opl:lit_to_string(product_family_tbl.long_description)
as virtrdf:OplProductFamilyLongDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy owl: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductCategory(product_category_with_code.product_cat_code)
a opl:ProductCategory
as virtrdf:OplProductCategory ;
a opl:ProductFamily
as virtrdf:OplProductCategorySubClassOfProductFamily ;
rdfs:label product_category_with_code.product_category_description
as virtrdf:rdfsOplProductCategoryDescription ;
foaf:homepage opl:wwwsitecategory(product_category_with_code.product_family_code, product_category_with_code.product_cat_code)
# where (
# ^{product_category_with_code.}^.product_family_code = 'uda'
# )
as virtrdf:homepageProductFamilyCategoryUda ;
opl:ProductCategoryCode product_category_with_code.product_cat_code
as virtrdf:OplProductCategoryCode ;
owl:sameAs product_category_with_code.dbpedia_uri
as virtrdf:OplCategoryOwlSameAsDBPediaUri ;
opl:hasFamily opl:ProductFamily(product_category_with_code.product_family_code)
as virtrdf:OplProductCategoryIsOfFamily ;
opl:ProductCategoryDescription product_category_with_code.product_category_description
as virtrdf:OplProductCategoryDescription ;
dc:description opl:lit_to_string(product_category_with_code.long_description)
as virtrdf:OplProductCategoryLongDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy owl:
.
opl:ProductFormat(product_format_with_code.product_format_code)
a opl:ProductFormat
as virtrdf:OplProductFormat ;
opl:ProductFormatCode product_format_with_code.product_format_code
as virtrdf:OplProductFormatCode ;
rdfs:label product_format_with_code.product_format_description
as virtrdf:rdfsOplProductFormatDescription ;
dc:description product_format_with_code.product_format_description
as virtrdf:OplProductFormatDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs: ;
rdfs:isDefinedBy dc:
.
opl:ProductFormatCategory(product_formats_categories.product_format_code, product_formats_categories.product_cat_code)
a opl:ProductFormatCategory
as virtrdf:OplProductFormatCategory ;
a opl:ProductFormat
as virtrdf:OplProductFormatCategoryProductFormat ;
a opl:ProductCategory
as virtrdf:OplProductFormatCategoryProductCategory ;
foaf:homepage opl:wwwsiteformat(product_category_with_code.product_family_code, product_formats_categories.product_cat_code, product_formats_categories.product_format_code)
where (
^{product_category_with_code.}^.product_cat_code = ^{product_formats_categories.}^.product_cat_code
# and
# ^{product_category_with_code.}^.product_family_code = 'uda'
)
as virtrdf:homepageProductFamilyCategoryFormatUda ;
opl:ProductFormatCode product_formats_categories.product_format_code
as virtrdf:OplProductFormatCategoryFormatCode ;
opl:ProductCategoryCode product_formats_categories.product_cat_code
as virtrdf:OplProductFormatCategoryCategoryCode ;
opl:isProductCategory opl:ProductCategory(product_formats_categories.product_cat_code)
as virtrdf:OplProductFormatCategoryisCategory ;
opl:isProductFormat opl:ProductFormat(product_formats_categories.product_format_code)
as virtrdf:OplProductFormatCategoryisFormat ;
rdfs:label opl:lit_format_cat_label(product_formats_categories.product_format_id, product_formats_categories.product_cat_id)
as virtrdf:rdfsOplProductFormatCategoryDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductCategory(product_category_with_code.product_cat_code) opl:hasProduct
opl:Product(product_with_code.product_id)
where (^{product_with_code.}^.product_cat_id = ^{product_category_with_code.}^.product_cat_id)
as virtrdf:OplProductCategoryIsCategoryOfProduct .
opl:ProductFormat(product_format_with_code.product_format_code) opl:hasProduct
opl:Product(product_with_code.product_id)
where (^{product_with_code.}^.product_format_id = ^{product_format_with_code.}^.product_format_id)
as virtrdf:OplProductFormatIsFormatOfProduct .
opl:ProductFamily(product_family_tbl.product_family_code) opl:hasCategory
opl:ProductCategory(product_category_with_code.product_cat_code)
where (^{product_family_tbl.}^.product_family_id = ^{product_category_with_code.}^.product_family_id)
as virtrdf:OplProductFamilyIsFamilyOfProductCategory .
opl:ProductFamily(product_family_tbl.product_family_code) opl:hasFormat
opl:ProductFormat(product_formats_categories.product_format_code)
where (
^{product_family_tbl.}^.product_family_id = ^{product_formats_categories.}^.product_family_id
)
as virtrdf:OplProductFamilyIsFamilyOfProductFormats .
opl:ProductFamily(product_family_tbl.product_family_code) opl:otherProductFamilies
opl:ProductFamily(product_family_tbl_2.product_family_code)
where (
^{product_family_tbl.}^.product_family_id <> ^{product_family_tbl_2.}^.product_family_id
)
as virtrdf:OplProductFamilyHasOtherProductFamilies .
opl:ProductFormat(product_format_with_code.product_format_code) opl:hasCategory
opl:ProductFormatCategory(product_formats_categories.product_format_code, product_formats_categories.product_cat_code)
where (^{product_formats_categories.}^.product_format_id = ^{product_format_with_code.}^.product_format_id)
as virtrdf:OplProductFormatIsFormatOfProductFormatCategories .
opl:ProductFormatCategory(product_formats_categories.product_format_code, product_formats_categories.product_cat_code)
opl:hasProduct
opl:Product(product_with_code.product_id)
where (
^{product_with_code.}^.product_cat_id = ^{product_formats_categories.}^.product_cat_id
and
^{product_with_code.}^.product_format_id = ^{product_formats_categories.}^.product_format_id
)
as virtrdf:OplProductFormatCategoryIsFormatCategoryOfProduct .
opl:VendorCategoryFamily(vendor_category_family_tbl.vendor_category_family_id)
a opl:VendorCategoryFamily
as virtrdf:OplVendorCategoryFamily ;
opl:VendorCategoryFamilyDescription vendor_category_family_tbl.vendor_category_family_desc
as virtrdf:OplVendorCategoryFamilyDesc .
opl:VendorCategory(vendor_category_tbl.vendor_category_id)
a opl:VendorCategory
as virtrdf:OplVendorCategory ;
a opl:VendorCategoryFamily
as virtrdf:OplVendorCategorySubClassOfVendorCategoryFamily ;
rdfs:label vendor_category_tbl.vendor_category_description
as virtrdf:rdfsOplVendorCategoryDescription ;
opl:VendorCategoryDescription vendor_category_tbl.vendor_category_description
as virtrdf:OplVendorCategoryDescription ;
opl:isVendorCategoryOf opl:VendorCategoryFamily(vendor_category_tbl.vendor_category_family_id)
as virtrdf:OplVendorCategoryIsOfCategoryFamily ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:Vendor(vendors_tbl.vendor_id)
a opl:Vendor
as virtrdf:OplVendor ;
a opl:VendorCategory
as virtrdf:OplVendorSubClassOfVendorCategory ;
rdfs:label vendors_tbl.vendor_name
as virtrdf:rdfsOplVendorsName ;
opl:VendorName vendors_tbl.vendor_name
as virtrdf:OplVendorsName ;
opl:WikipediaPage opl:Uri(vendors_tbl.wikipedia_url)
as virtrdf:OplVendorsWikipediaUrl ;
owl:sameAs opl:lit_wikipedia_to_dbpedia(vendors_tbl.wikipedia_url)
as virtrdf:OplVendorsWikipediaUrlOwlSameAs ;
foaf:homepage opl:Uri(vendors_tbl.vendor_homepage)
as virtrdf:OplFoafVendorHomepage ;
opl:isOfVendorCategory opl:VendorCategory(vendors_tbl.vendor_category_id)
as virtrdf:OplVendorIsOfVendorCategory ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy owl:
.
opl:VendorCategoryFamily(vendor_category_family_tbl.vendor_category_family_id)
opl:hasVendorCategory
opl:VendorCategory(vendor_category_tbl.vendor_category_id)
where (
^{vendor_category_family_tbl.}^.vendor_category_family_id = ^{vendor_category_tbl.}^.vendor_category_family_id
)
as virtrdf:OplVendorCategoryFamilyHasVendorCategory .
opl:VendorCategory(vendor_category_tbl.vendor_category_id)
opl:hasVendorCategory
opl:Vendor(vendors_tbl.vendor_id)
where (
^{vendor_category_tbl.}^.vendor_category_id = ^{vendors_tbl.}^.vendor_category_id
)
as virtrdf:OplVendorCategoryHasVendors .
opl:OpsysFamily(opsys_family_tbl.opsys_family_id)
a opl:OpsysFamily
as virtrdf:OplOpsysFamily ;
rdfs:label opsys_family_tbl.opsys_family_name
as virtrdf:rdfsOplOpsysFamilyName ;
opl:OpsysFamilyName opsys_family_tbl.opsys_family_name
as virtrdf:OplOpsysFamilyName ;
opl:OpsysFamilyLicenseCode opsys_family_tbl.opsys_license_code
as virtrdf:OplOpsysFamilyLicenseCode ;
opl:OpsysFamilyVendor opl:Vendor(opsys_family_tbl.vendor_id)
as virtrdf:OplOpsysFamilyVendor ;
opl:OpsysFamilyRating opsys_family_tbl.rating
as virtrdf:OplOpsysFamilyRating ;
foaf:logo opl:lit_opsys_icon(opsys_family_tbl.opsys_family_id)
as virtrdf:OplLogoOpsysFamily ;
foaf:homepage opl:Uri(opsys_family_tbl.wikipedia_url)
as virtrdf:FoafHomepageOpsysFamilyWikipediaUrl ;
owl:sameAs opl:lit_wikipedia_to_dbpedia(opsys_family_tbl.wikipedia_url)
as virtrdf:FoafHomepageOpsysFamilyPediaUrlOwlSameAs ;
opl:WikipediaPage opl:Uri(opsys_family_tbl.wikipedia_url)
as virtrdf:OplOpsysFamilyWikipediaUrl ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy owl:
.
opl:OpsysFamily(opsys_family_tbl.opsys_family_id) opl:hasOpsys
opl:Opsys(opsys_tbl.opsys_name)
where (^{opsys_tbl.}^.opsys_family_id = ^{opsys_family_tbl.}^.opsys_family_id)
as virtrdf:OplOpsysFamilyIsOpsysFamilyOfOpsys .
opl:DbmsFamily(dbms_family_tbl.dbms_family_id)
a opl:DbmsFamily
as virtrdf:OplDbmsFamily ;
rdfs:label dbms_family_tbl.dbms_family_name
as virtrdf:rdfsOplDbmsFamilyName ;
opl:DbmsFamilyName dbms_family_tbl.dbms_family_name
as virtrdf:OplDbmsFamilyName ;
opl:DbmsFamilyVendor opl:Vendor(dbms_family_tbl.vendor_id)
as virtrdf:OplDbmsFamilyVendor ;
foaf:homepage opl:Uri(dbms_family_tbl.wikipedia_url)
as virtrdf:FoafHomepageDbmsFamilyWikipediaUrl ;
owl:sameAs opl:lit_wikipedia_to_dbpedia(dbms_family_tbl.wikipedia_url)
as virtrdf:OwnSameAsDbmsFamilyPediaUrl ;
opl:WikipediaPage opl:Uri(dbms_family_tbl.wikipedia_url)
as virtrdf:OplDbmsFamilyWikipediaUrl ;
opl:DbmsFamilyRating dbms_family_tbl.rating
as virtrdf:OplDbmsFamilyRating ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy owl:
.
opl:DbmsEngine(dbms_engine_tbl.dbms_name)
a opl:DbmsEngine
as virtrdf:OplDbmsEngine ;
a opl:DbmsFamily
as virtrdf:DbmsEngineSubClassOfDbmsFamily ;
a umbel:RelationalDatabaseServerProgram
as virtrdf:DbmEngineSubClassOfUmbel ;
opl:isOfDbmsFamily opl:DbmsFamily(dbms_engine_tbl.dbms_family_id)
as virtrdf:OplDbmsEngineisOfDbmsFamily ;
rdfs:label dbms_engine_tbl.dbms_name
as virtrdf:rdfsOplLabelDbmsName ;
opl:DbmsEngineVersion dbms_engine_tbl.dbms_version
as virtrdf:OplDbmsEngineVersion ;
opl:DbmsEngineUpwardCompatible dbms_engine_tbl.upward_compatible
as virtrdf:OplDbmsEngineUpwardCompatible ;
opl:DbmsEngineDownwardCompatible dbms_engine_tbl.downward_compatible
as virtrdf:OplDbmsEngineDownwardCompatible ;
opl:DbmsEngineRating dbms_engine_tbl.rating
as virtrdf:OplDbmsEngineRating ;
opl:DbmsEngineOldArchiveCode dbms_engine_tbl.old_archive_code
as virtrdf:OplDbmsEngineOldArchiveCode ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:DbmsFamily(dbms_family_tbl.dbms_family_id)
opl:hasDatabaseVersions
opl:DbmsEngine(dbms_engine_tbl.dbms_name)
where (
^{dbms_family_tbl.}^.dbms_family_id = ^{dbms_engine_tbl.}^.dbms_family_id
)
as virtrdf:OplDbmsFamilyToDbms .
opl:OpsysType(opsys_type_tbl.opsys_type_id)
a opl:OpsysType
as virtrdf:OplOpsysType ;
rdfs:label opsys_type_tbl.opsys_type_description
as virtrdf:rdfsOplOpsysTypeDescription ;
opl:OpsysTypeDescription opsys_type_tbl.opsys_type_description
as virtrdf:OplOpsysTypeDescription ;
opl:OpsysTypeShortDescription opsys_type_tbl.short_description
as virtrdf:OplOpsysTypeShortDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:OpsysType(opsys_type_tbl.opsys_type_id) opl:hasOpsys
opl:Opsys(opsys_tbl.opsys_name)
where (^{opsys_tbl.}^.opsys_type_id = ^{opsys_type_tbl.}^.opsys_type_id)
as virtrdf:OplOpsysTypeIsOpsysTypeOfOpsys .
opl:ProcessorMode(processor_mode_tbl.processor_mode_id)
a opl:ProcessorMode
as virtrdf:OplProcessorMode ;
opl:ProcessorModeName processor_mode_tbl.processor_mode_name
as virtrdf:OplProcessorModeName .
opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
a opl:Processor
as virtrdf:OplProcessor ;
opl:ProcessorName processors_tbl.processor_name
as virtrdf:OplProcessorName ;
opl:ProcessorVersion processors_tbl.processor_version
as virtrdf:OplProcessorVersion ;
rdfs:label processors_tbl.processor_description
as virtrdf:rdfsOplProcessorDescription ;
opl:ProcessorDescription processors_tbl.processor_description
as virtrdf:OplProcessorDescription ;
opl:ProcessorMode opl:ProcessorMode(processors_tbl.processor_mode_id)
as virtrdf:OplProcessorProcessorMode ;
opl:isOfProcessorFamily opl:ProcessorFamily(processors_tbl.processor_family_id)
as virtrdf:OplProcessorIsOfProcessorFamily ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ProcessorFamily(processor_family_tbl.processor_family_id)
a opl:ProcessorFamily
as virtrdf:OplProcessorFamily ;
opl:ProcessorFamilyName processor_family_tbl.processor_family_name
as virtrdf:OplProcessorFamilyName ;
opl:ProcessorFamilyVendor opl:Vendor(processor_family_tbl.vendor_id)
as virtrdf:OplProcessorFamilyVendor ;
foaf:homepage opl:Uri(processor_family_tbl.wikipedia_url)
as virtrdf:FoafHomepageProcessorFamilyWikipediaUrl ;
owl:sameAs opl:lit_wikipedia_to_dbpedia(processor_family_tbl.wikipedia_url)
as virtrdf:OwlSameAsProcessorFamilyPediaUrl ;
opl:WikipediaPage opl:Uri(processor_family_tbl.wikipedia_url)
as virtrdf:OplProcessorFamilyWikipediaUrl ;
rdfs:label processor_family_tbl.processor_family_description
as virtrdf:rdfsOplProcessorFamilyDescription ;
opl:ProcessorFamilyDescription processor_family_tbl.processor_family_description
as virtrdf:OplProcessorFamilyDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy owl: ;
rdfs:isDefinedBy rdfs:
.
opl:Opsys(opsys_tbl.opsys_name)
a opl:Opsys
as virtrdf:OplOpsys ;
a opl:OpsysFamily
as virtrdf:OpsysSubClassOfOplOpsysFamily ;
a umbel:OperatingSystem
as virtrdf:OpsysSubClassOfUmbelOpsys ;
opl:OpsysVersion opsys_tbl.opsys_version
as virtrdf:OplOpsysVersion ;
opl:OpsysUpwardCompatible opsys_tbl.upward_compatible
as virtrdf:OplOpsysUpwardCompatible ;
opl:OpsysDownwardCompatible opsys_tbl.downward_compatible
as virtrdf:OplOpsysDownwardCompatible ;
opl:OpsysSupported opsys_tbl.supported
as virtrdf:OplOpsysSupported ;
opl:OpsysLicenseCode opsys_tbl.opsys_license_code
as virtrdf:OplOpsysLicenseCode ;
rdfs:label opsys_tbl.commercial_name
as virtrdf:rdfsOplOpsysCommercialName ;
opl:OpsysCommercialName opsys_tbl.commercial_name
as virtrdf:OplOpsysCommercialName ;
opl:OpsysEmulationMode opl:ProcessorMode(opsys_tbl.emulation_mode_id)
as virtrdf:OplOpsysEmulationMode ;
opl:OpsysProcessor opl:Processor(opsys_tbl.processor_name, opsys_tbl.processor_mode_id)
as virtrdf:OplOpsysProcessor ;
opl:isOfOpsysFamily opl:OpsysFamily(opsys_tbl.opsys_family_id)
as virtrdf:OplOpsysIsOfOpsysFamily ;
opl:isOfOpsysType opl:OpsysType(opsys_tbl.opsys_type_id)
as virtrdf:OplOpsysIsOfOpsysType ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:Product(product_with_code.product_id)
a opl:Product
as virtrdf:OplProduct ;
a opl:ProductFormat
as virtrdf:ProductSubClassOfProductFormat ;
a opl:ProductCategory
as virtrdf:ProductSubClassOfProductCategory ;
a opl:ProductFormatCategory
as virtrdf:OplProductProductFormatCategory ;
rdfs:label product_with_code.poduct_description
as virtrdf:rdfsOplProductDescription ;
foaf:homepage opl:wwwsiteproduct(product_with_code.product_id)
as virtrdf:homepageProductFamilyCategoryFormatProductUda ;
opl:ProductDescription product_with_code.poduct_description
as virtrdf:OplProductDescription ;
dc:description opl:lit_to_string(product_with_code.long_description)
as virtrdf:OplProductLongDescription ;
opl:isOfCategory opl:ProductCategory(product_with_code.product_cat_code)
as virtrdf:OplProductIsOfCategory ;
opl:isOfFormat opl:ProductFormat(product_with_code.product_format_code)
as virtrdf:OplProductIsOfFormat ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy foaf: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
opl:Product(product_with_code.product_id) opl:hasProductRelease
opl:ProductRelease(
product_release_tbl.product_id,
product_release_tbl.product_release_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
where (^{product_with_code.}^.product_id = ^{product_release_tbl.}^.product_id)
as virtrdf:OplProductIsProductOfProductRelease .
opl:ProductRelease(
product_release_tbl.product_id,
product_release_tbl.product_release_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
a opl:ProductRelease
as virtrdf:OplProductRelease ;
a opl:Product
as virtrdf:OplProductReleaseSubClassProduct ;
a gr:ProductOrService
as virtrdf:OplProductReleaseAgrProductOrService ;
rdfs:label opl:lit_product_release_label(
product_release_tbl.product_id,
product_release_tbl.product_release_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
as virtrdf:rdfsOplProductReleaseProductReleaseId ;
opl:ProductReleaseProductReleaseId product_release_tbl.product_release_id
as virtrdf:OplProductReleaseProductReleaseId ;
opl:isOfProduct opl:Product(product_release_tbl.product_id)
as virtrdf:OplProductReleaseIsOfProduct ;
opl:isForOpsys opl:Opsys(product_release_tbl.opsys_name)
as virtrdf:OplProductReleaseIsForOpsys ;
opl:isForDbmsEngine opl:DbmsEngine(product_release_tbl.dbms_name)
as virtrdf:OplProductReleaseIsForDbmsEngine ;
opl:UpwardCompatible product_release_tbl.upward_compatible
as virtrdf:OplProductReleaseUpwardCompatible ;
opl:DownwardCompatible product_release_tbl.downward_compatible
as virtrdf:OplProductReleaseDownwardCompatible ;
opl:PurchaseInShop opl:lit_to_shop (
product_release_tbl.product_release_id,
product_release_tbl.product_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
as virtrdf:OplProductReleaseToShop ;
gr:hasBusinessFunction gr:Sell as virtrdf:grbusinessfunctionsell;
opl:Supported product_release_tbl.supported
as virtrdf:OplProductReleaseSupported ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy gr:
.
opl:ProductRelease(
product_release_tbl.product_id,
product_release_tbl.product_release_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
) opl:hasComponentArchive
opl:ComponentArchive(component_archive_tbl.component_archive_name)
where (
^{product_release_tbl.}^.product_id = ^{component_archive_tbl.}^.product_id and
^{product_release_tbl.}^.product_release_id = ^{component_archive_tbl.}^.product_release_id and
^{product_release_tbl.}^.opsys_name = ^{component_archive_tbl.}^.opsys_name and
^{product_release_tbl.}^.dbms_name = ^{component_archive_tbl.}^.dbms_name
)
as virtrdf:OplProductReleaseIsProductReleaseOfComponentArchive .
opl:Component(components_tbl.component_name)
a opl:Component
as virtrdf:OplComponent ;
opl:isOfComponentCategory opl:ComponentCategory(components_tbl.component_category_id)
as virtrdf:OplComponentIsOfComponentCategory ;
opl:isOfComponentType opl:ComponentType(components_tbl.component_type_id)
as virtrdf:OplComponentIsOfComponentType ;
opl:isOfComponentMode opl:ComponentMode(components_tbl.component_mode_id)
as virtrdf:OplComponentIsOfComponentMode ;
opl:isForOpsys opl:Opsys(components_tbl.opsys_name)
as virtrdf:OplComponentIsForOpsys ;
opl:isForDbmsEngine opl:DbmsEngine(components_tbl.dbms_name)
as virtrdf:OplComponentIsForDbmsEngine ;
opl:ComponentCvsid components_tbl.component_cvsid
as virtrdf:OplComponentComponentCvsId ;
opl:ComponentBuildDate components_tbl.component_build_date
as virtrdf:OplComponentComponentBuildDate ;
opl:Notes components_tbl.notes
as virtrdf:OplComponentNotes ;
opl:BuildComments components_tbl.build_comments
as virtrdf:OplComponentBuildComments ;
opl:Filesize components_tbl.str_filesize
as virtrdf:OplComponentFilesize ;
rdfs:isDefinedBy opl:
.
opl:DbmsEngine (dbms_engine_tbl.dbms_name) opl:hasComponents
opl:Component(components_tbl.component_name)
where (^{components_tbl.}^.dbms_name = ^{dbms_engine_tbl.}^.dbms_name)
as virtrdf:OplDbmsEngineForComponents .
opl:Opsys (opsys_tbl.opsys_name) opl:hasComponents
opl:Component(components_tbl.component_name)
where (^{components_tbl.}^.opsys_name = ^{opsys_tbl.}^.opsys_name)
as virtrdf:OplOpsysForComponents .
opl:ComponentMode(component_mode_tbl.component_mode_id)
a opl:ComponentMode
as virtrdf:OplComponentMode ;
rdfs:label component_mode_tbl.component_mode_description
as virtrdf:rdfsOplComponentModeDescription ;
opl:ComponentModeDescription component_mode_tbl.component_mode_description
as virtrdf:OplComponentModeDescription ;
opl:ComponentModeShortDescription component_mode_tbl.short_description
as virtrdf:OplComponentModeShortDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ComponentType(component_type_tbl.component_type_id)
a opl:ComponentType
as virtrdf:OplComponentType ;
rdfs:label component_type_tbl.component_type_description
as virtrdf:rdfsOplComponentTypeDescription ;
opl:ComponentTypeDescription component_type_tbl.component_type_description
as virtrdf:OplComponentTypeDescription ;
opl:ComponentTypeShortDescription component_type_tbl.short_description
as virtrdf:OplComponentTypeShortDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ComponentCategory(component_category_tbl.component_category_id)
a opl:ComponentCategory
as virtrdf:OplComponentCategory ;
rdfs:label component_category_tbl.component_category_description
as virtrdf:rdfsOplComponentCategoryDescription ;
opl:ComponentCategoryDescription component_category_tbl.component_category_description
as virtrdf:OplComponentCategoryDescription ;
opl:ComponentCategoryShortDescription component_category_tbl.short_description
as virtrdf:OplComponentCategoryShortDescription ;
dc:description opl:lit_to_string(component_category_tbl.component_category_long_description)
as virtrdf:OplComponentCategoryLongDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ComponentArchive(component_archive_tbl.component_archive_name)
a opl:ComponentArchive
as virtrdf:OplComponentArchive ;
a opl:Component
as virtrdf:ComponentArchiveSubClassOfComponent ;
opl:ComponentArchiveName component_archive_tbl.component_archive_name
as virtrdf:OplComponentArchiveComponentArchiveName ;
rdfs:label component_archive_tbl.component_archive_name
as virtrdf:rdfsComponentArchiveComponentArchiveName ;
opl:ComponentArchiveType opl:ComponentArchiveType(component_archive_tbl.component_archive_type_id)
as virtrdf:ComponentArchiveComponentArchiveType ;
opl:isOfComponent opl:Component(component_archive_tbl.component_name)
as virtrdf:OplComponentArchiveIsOfComponent ;
opl:isOfProductRelease opl:ProductRelease(
component_archive_tbl.product_id,
component_archive_tbl.product_release_id,
component_archive_tbl.opsys_name,
component_archive_tbl.dbms_name
)
as virtrdf:OplComponentArchiveIsOfProductRelease ;
opl:AssemblyDate component_archive_tbl.assembly_date
as virtrdf:OplComponentArchiveAssemblyDate ;
opl:FileUri component_archive_tbl.file_uri
as virtrdf:OplComponentArchiveFileUri ;
opl:LicenseCode component_archive_tbl.license_code
as virtrdf:OplComponentArchiveLicenseCode ;
opl:ResFullPath component_archive_tbl.res_full_path
as virtrdf:OplComponentArchiveResFullPath ;
opl:ResName component_archive_tbl.res_name
as virtrdf:OplComponentArchiveResName ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ComponentArchiveType(component_archive_type_tbl.component_archive_type_id)
a opl:ComponentArchiveType
as virtrdf:OplComponentArchiveType ;
opl:ComponentArchiveShortName component_archive_type_tbl.component_archive_short_name
as virtrdf:OplComponentArchiveTypeComponentArchiveShortName ;
rdfs:label component_archive_type_tbl.component_archive_type_name
as virtrdf:rdfsOplComponentArchiveTypeComponentArchiveTypeName ;
opl:ComponentArchiveTypeName component_archive_type_tbl.component_archive_type_name
as virtrdf:OplComponentArchiveTypeComponentArchiveTypeName ;
opl:Extension component_archive_type_tbl.extension
as virtrdf:OplComponentArchiveTypeExtension ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:DownloadLocation(download_location_tbl.uri)
a opl:DownloadLocation
as virtrdf:OplDownloadLocation ;
opl:isOfComponentArchive opl:ComponentArchive(download_location_tbl.component_archive_name)
as virtrdf:OplDownloadLocationIsOfComponentArchive ;
opl:hasDownloadProtocol opl:DownloadProtocol(download_location_tbl.protocol_name)
as virtrdf:DownloadLocationHasProtocolName ;
rdfs:label download_location_tbl.uri_old
as virtrdf:rdfsOplDownloadLocationLabel ;
opl:isOfProductRelease opl:ProductRelease(
download_location_tbl.product_id,
download_location_tbl.product_release_id,
download_location_tbl.opsys_name,
download_location_tbl.dbms_name
)
as virtrdf:OplDownloadLocationIsOfProductRelease ;
opl:Uri download_location_tbl.uri
as virtrdf:OplDownloadLocationUri ;
opl:UriOld download_location_tbl.uri_old
as virtrdf:OplDownloadLocationUriOld ;
opl:hasDownloadPartner opl:DownloadPartner(
download_location_tbl.host_name,
download_location_tbl.domain_name
)
as virtrdf:OplDownloadLocationHasDownloadPartner ;
opl:DomainName download_location_tbl.domain_name
as virtrdf:OplDownloadLocationDomainName ;
opl:HostName download_location_tbl.host_name
as virtrdf:OplDownloadLocationHostName ;
opl:ResName download_location_tbl.res_name
as virtrdf:OplDownloadLocationResName ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:DownloadProtocol(download_protocol_tbl.protocol_name)
a opl:DownloadProtocol
as virtrdf:OplDownloadProtocolProtocolName ;
opl:ProtocolDescription download_protocol_tbl.protocol_description
as virtrdf:OplDownloadProtocolProtocolDescription .
opl:DownloadPartner(
download_partner_tbl.host_name,
download_partner_tbl.domain_name
)
a opl:DownloadPartner
as virtrdf:OplDownloadPartner;
rdfs:label download_partner_tbl.partner_name
as virtrdf:rdfsOplDownloadPartnerPartnerNamelabel ;
opl:DownloadPartner download_partner_tbl.partner_name
as virtrdf:OplDownloadPartnerPartnerName ;
opl:PortNumber download_partner_tbl.port_number
as virtrdf:OplDownloadPartnerPortNumber ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ComponentArchive(component_archive_tbl.component_archive_name)
opl:hasDownloadLocation
opl:DownloadLocation(download_location_tbl.uri)
where (
^{component_archive_tbl.}^.component_archive_name = ^{download_location_tbl.}^.component_archive_name
)
as virtrdf:OplComponentArchiveIsComponentArchiveOfDownloadLocation .
opl:DownloadLocation(download_location_tbl.uri)
opl:isDownloadLocationOf
opl:ComponentArchive(component_archive_tbl.component_archive_name)
where (
^{download_location_tbl.}^.component_archive_name = ^{component_archive_tbl.}^.component_archive_name
)
as virtrdf:OplDownloadLocationIsDownloadLocationOfComponentArchive .
#
# Extra Peripheral family/cat/format/etc... to/from... dbfamily/opsysfamily/....
# ==================================================================================
# ---------------------> product_family
# opl:ProductFamily(product_family_tbl.product_family_code)
# opl:OperatingSystems
# opl:Opsys(ac1.opsys_name)
# where (
# ^{product_family_tbl.}^.product_family_code = ^{ac1.}^.product_family_code
# )
# as virtrdf:OplProductFamilyToOpsys .
opl:ProductFamily(product_family_tbl.product_family_code)
opl:OperatingSystemsFamilies
opl:OpsysFamily(ac1.opsys_family_id)
where (
^{product_family_tbl.}^.product_family_code = ^{ac1.}^.product_family_code
)
as virtrdf:OplProductFamilyToOpsysFamily .
# opl:ProductFamily(product_family_tbl.product_family_code)
# opl:Databases
# opl:DbmsEngine(ac1.dbms_name)
# where (
# ^{product_family_tbl.}^.product_family_code = ^{ac1.}^.product_family_code
# )
# as virtrdf:OplProductFamilyToDbms .
opl:ProductFamily(product_family_tbl.product_family_code)
opl:DatabaseFamilies
opl:DbmsFamily(ac1.dbms_family_id)
where (
^{product_family_tbl.}^.product_family_code = ^{ac1.}^.product_family_code
)
as virtrdf:OplProductFamilyToDbmsFamily .
# opl:ProductFamily(product_family_tbl.product_family_code)
# opl:Processors
# opl:Processor(ac1.processor_name, ac1.processor_mode_id)
# where (
# ^{product_family_tbl.}^.product_family_code = ^{ac1.}^.product_family_code
# )
# as virtrdf:OplProductFamilyToProcessor .
opl:ProductFamily(product_family_tbl.product_family_code)
opl:ProcessorFamilies
opl:ProcessorFamily(ac1.processor_family_id)
where (
^{product_family_tbl.}^.product_family_code = ^{ac1.}^.product_family_code
)
as virtrdf:OplProductFamilyToProcessorFamily .
# ---------------------> product_format
# opl:ProductFormat(product_format_with_code.product_format_code)
# opl:OperatingSystems
# opl:Opsys(ac1.opsys_name)
# where (
# ^{product_format_with_code.}^.product_format_code = ^{ac1.}^.product_format_code
# )
# as virtrdf:OplProductFormatToOpsys .
opl:ProductFormat(product_format_with_code.product_format_code)
opl:OperatingSystemsFamilies
opl:OpsysFamily(ac1.opsys_family_id)
where (
^{product_format_with_code.}^.product_format_code = ^{ac1.}^.product_format_code
)
as virtrdf:OplProductFormatToOpsysFamily .
# opl:ProductFormat(product_format_with_code.product_format_code)
# opl:Databases
# opl:DbmsEngine(ac1.dbms_name)
# where (
# ^{product_format_with_code.}^.product_format_code = ^{ac1.}^.product_format_code
# )
# as virtrdf:OplProductFormatToDbms .
opl:ProductFormat(product_format_with_code.product_format_code)
opl:DatabaseFamilies
opl:DbmsFamily(ac1.dbms_family_id)
where (
^{product_format_with_code.}^.product_format_code = ^{ac1.}^.product_format_code
)
as virtrdf:OplProductFormatToDbmsFamily .
opl:ProductFormat(product_format_with_code.product_format_code)
opl:Processors
opl:Processor(ac1.processor_name, ac1.processor_mode_id)
where (
^{product_format_with_code.}^.product_format_code = ^{ac1.}^.product_format_code
)
as virtrdf:OplProductFormatToProcessor .
opl:ProductFormat(product_format_with_code.product_format_code)
opl:ProcessorFamilies
opl:ProcessorFamily(ac1.processor_family_id)
where (
^{product_format_with_code.}^.product_format_code = ^{ac1.}^.product_format_code
)
as virtrdf:OplProductFormatToProcessorFamily .
# ---------------------> product_category
# opl:ProductCategory(product_category_with_code.product_cat_code)
# opl:OperatingSystems
# opl:Opsys(ac1.opsys_name)
# where (
# ^{product_category_with_code.}^.product_cat_code = ^{ac1.}^.product_cat_code
# )
# as virtrdf:OplProductCatToOpsys .
opl:ProductCategory(product_category_with_code.product_cat_code)
opl:OperatingSystemsFamilies
opl:OpsysFamily(ac1.opsys_family_id)
where (
^{product_category_with_code.}^.product_cat_code = ^{ac1.}^.product_cat_code
)
as virtrdf:OplProductCatToOpsysFamily .
# opl:ProductCategory(product_category_with_code.product_cat_code)
# opl:Databases
# opl:DbmsEngine(ac1.dbms_name)
# where (
# ^{product_category_with_code.}^.product_cat_code = ^{ac1.}^.product_cat_code
# )
# as virtrdf:OplProductCatToDbms .
opl:ProductCategory(product_category_with_code.product_cat_code)
opl:DatabaseFamilies
opl:DbmsFamily(ac1.dbms_family_id)
where (
^{product_category_with_code.}^.product_cat_code = ^{ac1.}^.product_cat_code
)
as virtrdf:OplProductCatToDbmsFamily .
# opl:ProductCategory(product_category_with_code.product_cat_code)
# opl:Processors
# opl:Processor(ac1.processor_name, ac1.processor_mode_id)
# where (
# ^{product_category_with_code.}^.product_cat_code = ^{ac1.}^.product_cat_code
# )
# as virtrdf:OplProductCatToProcessor .
opl:ProductCategory(product_category_with_code.product_cat_code)
opl:ProcessorFamilies
opl:ProcessorFamily(ac1.processor_family_id)
where (
^{product_category_with_code.}^.product_cat_code = ^{ac1.}^.product_cat_code
)
as virtrdf:OplProductCatToProcessorFamily .
# ---------------------> product
opl:Product(product_with_code.product_id)
opl:OperatingSystems
opl:Opsys(ac1.opsys_name)
where (
^{product_with_code.}^.product_id = ^{ac1.}^.product_id
)
as virtrdf:OplProductToOpsys .
opl:Product(product_with_code.product_id)
opl:OperatingSystemsFamilies
opl:OpsysFamily(ac1.opsys_family_id)
where (
^{product_with_code.}^.product_id = ^{ac1.}^.product_id
)
as virtrdf:OplProductToOpsysFamily .
opl:Product(product_with_code.product_id)
opl:Databases
opl:DbmsEngine(ac1.dbms_name)
where (
^{product_with_code.}^.product_id = ^{ac1.}^.product_id
)
as virtrdf:OplProductToDbms .
opl:Product(product_with_code.product_id)
opl:DatabaseFamilies
opl:DbmsFamily(ac1.dbms_family_id)
where (
^{product_with_code.}^.product_id = ^{ac1.}^.product_id
)
as virtrdf:OplProductToDbmsFamily .
opl:Product(product_with_code.product_id)
opl:Processors
opl:Processor(ac1.processor_name, ac1.processor_mode_id)
where (
^{product_with_code.}^.product_id = ^{ac1.}^.product_id
)
as virtrdf:OplProductToProcessor .
opl:Product(product_with_code.product_id)
opl:ProcessorFamilies
opl:ProcessorFamily(ac1.processor_family_id)
where (
^{product_with_code.}^.product_id = ^{ac1.}^.product_id
)
as virtrdf:OplProductToProcessorFamily .
# ---------------------> to product
opl:Opsys(opsys_tbl.opsys_name)
opl:hasProducts
opl:Product(ac1.product_id)
where (
^{opsys_tbl.}^.opsys_name = ^{ac1.}^.opsys_name
)
as virtrdf:OplOpsysToProduct .
opl:OpsysFamily(opsys_family_tbl.opsys_family_id)
opl:hasProducts
opl:Product(ac1.product_id)
where (
^{opsys_family_tbl.}^.opsys_family_id = ^{ac1.}^.opsys_family_id
)
as virtrdf:OplOpsysFamilyToProduct .
opl:DbmsEngine(dbms_engine_tbl.dbms_name)
opl:hasProducts
opl:Product(ac1.product_id)
where (
^{dbms_engine_tbl.}^.dbms_name = ^{ac1.}^.dbms_name
)
as virtrdf:OplDbmsToProduct .
opl:DbmsFamily(dbms_family_tbl.dbms_family_id)
opl:hasProducts
opl:Product(ac1.product_id)
where (
^{dbms_family_tbl.}^.dbms_family_id = ^{ac1.}^.dbms_family_id
)
as virtrdf:OplDbmsFamilyToProduct .
opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
opl:hasProducts
opl:Product(ac1.product_id)
where (
^{processors_tbl.}^.processor_name = ^{ac1.}^.processor_name
and
^{processors_tbl.}^.processor_mode_id = ^{ac1.}^.processor_mode_id
)
as virtrdf:OplProcessorToProduct .
opl:ProcessorFamily(processor_family_tbl.processor_family_id)
opl:hasProducts
opl:Product(ac1.product_id)
where (
^{processor_family_tbl.}^.processor_family_id = ^{ac1.}^.processor_family_id
)
as virtrdf:OplProcessorFamilyProduct .
# ---------------------> to product_cat
# opl:Opsys(opsys_tbl.opsys_name)
# opl:hasProductCategory
# opl:ProductCategory(ac1.product_cat_code)
# where (
# ^{opsys_tbl.}^.opsys_name = ^{ac1.}^.opsys_name
# )
# as virtrdf:OplOpsysToProductCategory .
opl:OpsysFamily(opsys_family_tbl.opsys_family_id)
opl:hasProductCategory
opl:ProductCategory(ac1.product_cat_code)
where (
^{opsys_family_tbl.}^.opsys_family_id = ^{ac1.}^.opsys_family_id
)
as virtrdf:OplOpsysFamilyToProductCategory .
# opl:DbmsEngine(dbms_engine_tbl.dbms_name)
# opl:hasProductCategory
# opl:ProductCategory(ac1.product_cat_code)
# where (
# ^{dbms_engine_tbl.}^.dbms_name = ^{ac1.}^.dbms_name
# )
# as virtrdf:OplDbmsToProductCategory .
opl:DbmsFamily(dbms_family_tbl.dbms_family_id)
opl:hasProductCategory
opl:ProductCategory(ac1.product_cat_code)
where (
^{dbms_family_tbl.}^.dbms_family_id = ^{ac1.}^.dbms_family_id
)
as virtrdf:OplDbmsFamilyToProductCategory .
# opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
# opl:hasProductCategory
# opl:ProductCategory(ac1.product_cat_code)
# where (
# ^{processors_tbl.}^.processor_name = ^{ac1.}^.processor_name
# and
# ^{processors_tbl.}^.processor_mode_id = ^{ac1.}^.processor_mode_id
# )
# as virtrdf:OplProcessorToProductCategory .
opl:ProcessorFamily(processor_family_tbl.processor_family_id)
opl:hasProductCategory
opl:ProductCategory(ac1.product_cat_code)
where (
^{processor_family_tbl.}^.processor_family_id = ^{ac1.}^.processor_family_id
)
as virtrdf:OplProcessorFamilyProductCategory .
# ---------------------> to product_format
# opl:Opsys(opsys_tbl.opsys_name)
# opl:hasProductFormat
# opl:ProductFormat(ac1.product_format_code)
# where (
# ^{opsys_tbl.}^.opsys_name = ^{ac1.}^.opsys_name
# )
# as virtrdf:OplOpsysToProductFormat .
opl:OpsysFamily(opsys_family_tbl.opsys_family_id)
opl:hasProductFormat
opl:ProductFormat(ac1.product_format_code)
where (
^{opsys_family_tbl.}^.opsys_family_id = ^{ac1.}^.opsys_family_id
)
as virtrdf:OplOpsysFamilyToProductFormat .
# opl:DbmsEngine(dbms_engine_tbl.dbms_name)
# opl:hasProductFormat
# opl:ProductFormat(ac1.product_format_code)
# where (
# ^{dbms_engine_tbl.}^.dbms_name = ^{ac1.}^.dbms_name
# )
# as virtrdf:OplDbmsToProductFormat .
opl:DbmsFamily(dbms_family_tbl.dbms_family_id)
opl:hasProductFormat
opl:ProductFormat(ac1.product_format_code)
where (
^{dbms_family_tbl.}^.dbms_family_id = ^{ac1.}^.dbms_family_id
)
as virtrdf:OplDbmsFamilyToProductFormat .
# opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
# opl:hasProductFormat
# opl:ProductFormat(ac1.product_format_code)
# where (
# ^{processors_tbl.}^.processor_name = ^{ac1.}^.processor_name
# and
# ^{processors_tbl.}^.processor_mode_id = ^{ac1.}^.processor_mode_id
# )
# as virtrdf:OplProcessorToProductFormat .
opl:ProcessorFamily(processor_family_tbl.processor_family_id)
opl:hasProductFormat
opl:ProductFormat(ac1.product_format_code)
where (
^{processor_family_tbl.}^.processor_family_id = ^{ac1.}^.processor_family_id
)
as virtrdf:OplProcessorFamilyProductFormat .
# ---------------------> to product_family
# opl:Opsys(opsys_tbl.opsys_name)
# opl:hasProductFamily
# opl:ProductFamily(ac1.product_family_code)
# where (
# ^{opsys_tbl.}^.opsys_name = ^{ac1.}^.opsys_name
# )
# as virtrdf:OplOpsysToProductFamily .
opl:OpsysFamily(opsys_family_tbl.opsys_family_id)
opl:hasProductFamily
opl:ProductFamily(ac1.product_family_code)
where (
^{opsys_family_tbl.}^.opsys_family_id = ^{ac1.}^.opsys_family_id
)
as virtrdf:OplOpsysFamilyToProductFamily .
# opl:DbmsEngine(dbms_engine_tbl.dbms_name)
# opl:hasProductFamily
# opl:ProductFamily(ac1.product_family_code)
# where (
# ^{dbms_engine_tbl.}^.dbms_name = ^{ac1.}^.dbms_name
# )
# as virtrdf:OplDbmsToProductFamily .
opl:DbmsFamily(dbms_family_tbl.dbms_family_id)
opl:hasProductFamily
opl:ProductFamily(ac1.product_family_code)
where (
^{dbms_family_tbl.}^.dbms_family_id = ^{ac1.}^.dbms_family_id
)
as virtrdf:OplDbmsFamilyToProductFamily .
# opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
# opl:hasProductFamily
# opl:ProductFamily(ac1.product_family_code)
# where (
# ^{processors_tbl.}^.processor_name = ^{ac1.}^.processor_name
# and
# ^{processors_tbl.}^.processor_mode_id = ^{ac1.}^.processor_mode_id
# )
# as virtrdf:OplProcessorToProductFamily .
opl:ProcessorFamily(processor_family_tbl.processor_family_id)
opl:hasProductFamily
opl:ProductFamily(ac1.product_family_code)
where (
^{processor_family_tbl.}^.processor_family_id = ^{ac1.}^.processor_family_id
)
as virtrdf:OplProcessorFamilyProductFamily .
#
# Product Benefits and things
# =========================================
opl:ProductBenefit(product_benefits_tbl.product_benefit_id)
a opl:ProductBenefit
as virtrdf:OplProductBenefit ;
rdfs:label product_benefits_tbl.product_benefit_desc
as virtrdf:rdfsLabelProductBenefitDescription ;
opl:isOfProductBenefitCategory opl:ProductBenefitCategory(product_benefits_tbl.product_benefit_category_id)
as virtrdf:OplProductBenefitIsOfProductBenefitCategory ;
opl:Description product_benefits_tbl.product_benefit_desc
as virtrdf:OplProductBenefitDescription ;
opl:Acronym product_benefits_tbl.product_benefit_acronym
as virtrdf:OplProductBenefitAcronym ;
opl:Explanation product_benefits_tbl.product_benefit_explanation
as virtrdf:OplProductBenefitExplanation ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductBenefitCategory(product_benefits_category_tbl.product_benefit_category_id)
a opl:ProductBenefitCategory
as virtrdf:OplProductBenefitCategory ;
rdfs:label product_benefits_category_tbl.description
as virtrdf:rdfsLabelProductBenefitCategoryDescription ;
opl:Description product_benefits_category_tbl.description
as virtrdf:OplProductBenefitCategoryDescription ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductFeatureCategory(product_feature_category_tbl.product_feature_category_id)
a opl:ProductFeatureCategory
as virtrdf:OplProductFeatureCategory ;
rdfs:label product_feature_category_tbl.short_desc
as virtrdf:rdfsLabelProductFeatureCategoryShortDescription ;
opl:ShortDescription product_feature_category_tbl.short_desc
as virtrdf:OplProductFeatureCategoryShortDescription ;
opl:Description product_feature_category_tbl.description
as virtrdf:OplProductFeatureCategoryDescription ;
opl:StandardsId product_feature_category_tbl.standards_id
as virtrdf:OplProductFeatureCategoryStandardsId ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductFeature(product_features_tbl.product_feature_id)
a opl:ProductFeature
as virtrdf:OplProductFeature ;
rdfs:label product_features_tbl.short_description
as virtrdf:rdfsLabelProductFeaturesShortDescription ;
opl:Description product_features_tbl.short_description
as virtrdf:OplProductFeaturesShortDescription ;
dc:description opl:lit_to_string(product_features_tbl.long_description)
as virtrdf:OplProductFeaturesLongDescription ;
opl:isOfProductBenefit opl:ProductBenefit(product_features_tbl.product_feature_benefit_id)
as virtrdf:ProductFeaturesIsOfProductBenefit ;
opl:isOfProductFeatureCategory opl:ProductFeatureCategory(product_features_tbl.product_feature_category_id)
as virtrdf:ProductFeaturesIsOfProductFeatureCategory ;
opl:isOfProduct opl:Product(product_features_tbl.product_id)
as virtrdf:ProductFeaturesIsOfProduct ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
opl:Product(product_with_code.product_id)
opl:hasFeature
opl:ProductFeature(product_features_tbl.product_feature_id)
where (
^{product_with_code.}^.product_id = ^{product_features_tbl.}^.product_id
)
as virtrdf:OplProductHasProductFeaturesProductFeatures .
opl:ProductFeature(product_features_tbl.product_feature_id)
opl:isFeatureOf
opl:Product(product_with_code.product_id)
where (
^{product_with_code.}^.product_id = ^{product_features_tbl.}^.product_id
)
as virtrdf:OplProductFeaturesAreProductFeaturesProduct .
opl:ProductFamilyFeature(product_family_features_tbl.product_family_feature_id)
a opl:ProductFamilyFeature
as virtrdf:OplProductFamilyFeature ;
rdfs:label product_family_features_tbl.short_description
as virtrdf:rdfsLabelProductFamilyFeaturesShortDescription ;
opl:Description product_family_features_tbl.short_description
as virtrdf:OplProductFamilyFeaturesShortDescription ;
dc:description opl:lit_to_string(product_family_features_tbl.long_description)
as virtrdf:OplProductFamilyFeaturesLongDescription ;
opl:isOfProductBenefit opl:ProductBenefit(product_family_features_tbl.product_family_feature_benefit_id)
as virtrdf:ProductFamilyFeaturesIsOfProductBenefit ;
opl:isOfProductFeatureCategory opl:ProductFeatureCategory(product_family_features_tbl.product_family_feature_cat_id)
as virtrdf:ProductFamilyFeaturesIsOfProductFeatureCategory ;
opl:isOfProductFamily opl:ProductFamily(product_family_features_tbl.product_family_code)
as virtrdf:ProductFamilyFeaturesIsOfProductFamily ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductFamily(product_family_tbl.product_family_code)
opl:hasFeature
opl:ProductFamilyFeature(product_family_features_tbl.product_family_feature_id)
where (
^{product_family_tbl.}^.product_family_id = ^{product_family_features_tbl.}^.product_family_id
)
as virtrdf:OplProductFamilyHasProductFamilyFeaturesProductFamilyFeatures .
opl:ProductFamilyFeature(product_family_features_tbl.product_family_feature_id)
opl:isFeatureOf
opl:Product(product_family_tbl.product_family_code)
where (
^{product_family_tbl.}^.product_family_id = ^{product_family_features_tbl.}^.product_family_id
)
as virtrdf:OplProductFamilyFeaturesAreProductFamilyFeaturesProductFamily .
opl:ProductFormatFeature(product_format_features_tbl.product_format_feature_id)
a opl:ProductFormatFeature
as virtrdf:OplProductFormatFeature ;
rdfs:label product_format_features_tbl.short_description
as virtrdf:rdfsLabelProductFormatFeaturesShortDescription ;
opl:Description product_format_features_tbl.short_description
as virtrdf:OplProductFormatFeaturesShortDescription ;
dc:description opl:lit_to_string(product_format_features_tbl.long_description)
as virtrdf:OplProductFormatFeaturesLongDescription ;
opl:isOfProductBenefit opl:ProductBenefit(product_format_features_tbl.product_format_feature_benefit_id)
as virtrdf:ProductFormatFeaturesIsOfProductBenefit ;
opl:isOfProductFeatureCategory opl:ProductFeatureCategory(product_format_features_tbl.product_format_feature_cat_id)
as virtrdf:ProductFormatFeaturesIsOfProductFeatureCategory ;
opl:isOfProductFormat opl:ProductFormat(product_format_features_tbl.product_format_code)
as virtrdf:ProductFormatFeaturesIsOfProductFormat ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductFormat(product_format_with_code.product_format_code)
opl:hasFeature
opl:ProductFormatFeature(product_format_features_tbl.product_format_feature_id)
where (
^{product_format_with_code.}^.product_format_id = ^{product_format_features_tbl.}^.product_format_id
)
as virtrdf:OplProductFormatHasProductFormatFeaturesProductFormatFeatures .
opl:ProductFormatFeature(product_format_features_tbl.product_format_feature_id)
opl:isFeatureOf
opl:ProductFormat(product_format_with_code.product_format_code)
where (
^{product_format_with_code.}^.product_format_id = ^{product_format_features_tbl.}^.product_format_id
)
as virtrdf:OplProductFormatFeaturesAreProductFormatFeaturesProductFormat .
opl:ProductCategoryFeature(product_category_features_tbl.product_category_feature_id)
a opl:ProductCategoryFeature
as virtrdf:OplProductCategoryFeature ;
rdfs:label product_category_features_tbl.short_description
as virtrdf:rdfsLabelProductCategoryFeaturesShortDescription ;
opl:Description product_category_features_tbl.short_description
as virtrdf:OplProductCategoryFeaturesShortDescription ;
dc:description opl:lit_to_string(product_category_features_tbl.long_description)
as virtrdf:OplProductCategoryFeaturesLongDescription ;
opl:isOfProductBenefit opl:ProductBenefit(product_category_features_tbl.product_category_feature_benefit_id)
as virtrdf:ProductCategoryFeaturesIsOfProductBenefit ;
opl:isOfProductFeatureCategory opl:ProductFeatureCategory(product_category_features_tbl.product_category_feature_category_id)
as virtrdf:ProductCategoryFeaturesIsOfProductFeatureCategory ;
opl:isOfProductCategory opl:ProductCategory(product_category_features_tbl.product_cat_code)
as virtrdf:ProductCategoryFeaturesIsOfProductCategory ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
opl:ProductCategory(product_category_with_code.product_cat_code)
opl:hasFeature
opl:ProductCategoryFeature(product_category_features_tbl.product_category_feature_id)
where (
^{product_category_with_code.}^.product_cat_id = ^{product_category_features_tbl.}^.product_cat_id
)
as virtrdf:OplProductCategoryHasProductCategoryFeaturesProductCategoryFeatures .
opl:ProductCategoryFeature(product_category_features_tbl.product_category_feature_id)
opl:isFeatureOf
opl:ProductCategory(product_category_with_code.product_cat_code)
where (
^{product_category_with_code.}^.product_cat_id = ^{product_category_features_tbl.}^.product_cat_id
)
as virtrdf:OplProductCategoryFeaturesAreProductCategoryFeaturesProductCategory .
opl:ProductReleaseFeature(product_release_features_tbl.product_release_feature_id)
a opl:ProductReleaseFeature
as virtrdf:OplProductReleaseFeature ;
rdfs:label product_release_features_tbl.short_description
as virtrdf:rdfsLabelProductReleaseFeaturesShortDescription ;
opl:Description product_release_features_tbl.short_description
as virtrdf:OplProductReleaseFeaturesShortDescription ;
dc:description opl:lit_to_string(product_release_features_tbl.long_description)
as virtrdf:OplProductReleaseFeaturesLongDescription ;
opl:isOfProductBenefit opl:ProductBenefit(product_release_features_tbl.product_release_feature_benefit_id)
as virtrdf:ProductReleaseFeaturesIsOfProductBenefit ;
opl:isOfProductFeatureCategory opl:ProductFeatureCategory(product_release_features_tbl.product_release_feature_cat_id)
as virtrdf:ProductReleaseFeaturesIsOfProductFeatureCategory ;
opl:isOfProduct opl:Product(product_release_features_tbl.product_id)
as virtrdf:ProductReleaseFeaturesIsOfProduct ;
opl:ProductReleaseId product_release_features_tbl.product_release_id
as virtrdf:ProductReleaseFeaturesProductRelease ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
} .
} .
;
DB.DBA.RDF_AUDIT_METADATA (1, '*');
SPARQL
prefix opl: <http://www.openlinksw.com/schemas/oplweb#>
prefix dc: <http://purl.org/dc/terms#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix oplds: <http://www.openlinksw.com/dataspace/organization/openlink#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix umbel: <http://umbel.org/umbel/sc/>
prefix gr: <http://purl.org/goodrelations/v1#>
alter quad storage virtrdf:DefaultQuadStorage
FROM oplweb2.oplweb.component_archive as component_archive_tbl
FROM oplweb2.oplweb.component_archive_type as component_archive_type_tbl
FROM oplweb2.oplweb.component_category as component_category_tbl text literal component_category_long_description
FROM oplweb2.oplweb.component_mode as component_mode_tbl
FROM oplweb2.oplweb.component_type as component_type_tbl
FROM oplweb2.oplweb.components_for_rdfs as components_tbl
FROM oplweb2.oplweb.dbms_engine as dbms_engine_tbl
FROM oplweb2.oplweb.dbms_family as dbms_family_tbl
FROM oplweb2.oplweb.download_location as download_location_tbl
FROM oplweb2.oplweb.download_protocol as download_protocol_tbl
FROM oplweb2.oplweb.download_partner as download_partner_tbl
FROM oplweb2.oplweb.opsys as opsys_tbl
FROM oplweb2.oplweb.opsys_family as opsys_family_tbl
FROM oplweb2.oplweb.opsys_type as opsys_type_tbl
FROM oplweb2.oplweb.processor_family as processor_family_tbl
FROM oplweb2.oplweb.processor_mode as processor_mode_tbl
FROM oplweb2.oplweb.processors as processors_tbl
FROM oplweb2.oplweb.product as product_tbl text literal long_description
FROM oplweb2.oplweb.product_benefits as product_benefits_tbl text literal product_benefit_explanation
FROM oplweb2.oplweb.product_benefits_category as product_benefits_category_tbl
FROM oplweb2.oplweb.product_category as product_category_tbl
FROM oplweb2.oplweb.product_category_features_with_code as product_category_features_tbl text literal long_description
FROM oplweb2.oplweb.product_family as product_family_tbl
FROM oplweb2.oplweb.product_family as product_family_tbl_2
FROM oplweb2.oplweb.product_family_features_with_code as product_family_features_tbl text literal long_description
FROM oplweb2.oplweb.product_features as product_features_tbl text literal long_description
FROM oplweb2.oplweb.product_feature_category as product_feature_category_tbl text literal description
FROM oplweb2.oplweb.product_format_features_with_code as product_format_features_tbl text literal long_description
FROM oplweb2.oplweb.product_release_features as product_release_features_tbl text literal long_description
FROM oplweb2.oplweb.product_release_with_family as product_release_tbl
FROM oplweb2.oplweb.vendor_category as vendor_category_tbl
FROM oplweb2.oplweb.vendor_category_family as vendor_category_family_tbl
FROM oplweb2.oplweb.vendors as vendors_tbl
FROM oplweb2.oplweb.product_formats_categories as product_formats_categories
FROM oplweb2.oplweb.product_with_code as product_with_code
FROM oplweb2.oplweb.product_category_with_code as product_category_with_code
FROM oplweb2.oplweb.product_format as product_format_with_code
FROM oplweb2.oplweb.product_price as pp
FROM oplweb2.oplweb.product_price_type as pt
FROM oplweb2.DBA.license_model_unit_type as put
FROM oplweb2.DBA.license_model_unit_type as put2
FROM oplweb2.DBA.license_model as lm
FROM oplweb2.DBA.license_model as lm2
FROM oplweb2.DBA.license_model_type as license_model_type_tbl
FROM oplweb2.DBA.product_price_varchar as ppv
FROM oplweb2.DBA.product_general_discount_vc as gd
FROM oplweb2.oplweb.archive_coverage_osdb as ac1
{
create virtrdf:product_portfolio2 as
graph <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
option (exclusive)
{
opl:ProcessorFamily(processor_family_tbl.processor_family_id)
opl:hasProcessors
opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
where (
^{processor_family_tbl.}^.processor_family_id = ^{processors_tbl.}^.processor_family_id
)
as virtrdf:OplProcessorFamilyHasProcessors .
opl:Processor(processors_tbl.processor_name, processors_tbl.processor_mode_id)
opl:hasProductFamily
opl:ProductFamily(ac1.product_family_code)
where (
^{processors_tbl.}^.processor_name = ^{ac1.}^.processor_name
and
^{processors_tbl.}^.processor_mode_id = ^{ac1.}^.processor_mode_id
)
as virtrdf:OplProcessorToProductFamily .
#
# Product Licensing and Shop stuff
# =========================================
opl:ProductRelease(
product_release_tbl.product_id,
product_release_tbl.product_release_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
opl:hasLicenseModel
opl:LicenseModel(
lm.product_release_id,
lm.product_id,
lm.opsys_family_id,
lm.dbms_family_id,
lm.product_price_type_id
)
where (
^{lm.}^.product_id = ^{product_release_tbl.}^.product_id and
^{lm.}^.product_release_id = ^{product_release_tbl.}^.product_release_id and
^{lm.}^.opsys_family_id = ^{product_release_tbl.}^.opsys_family_id and
^{lm.}^.dbms_family_id = ^{product_release_tbl.}^.dbms_family_id
)
as virtrdf:OplProductReleaseHasLicenseModel .
opl:ProductRelease(
product_release_tbl.product_id,
product_release_tbl.product_release_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
opl:hasPriceSample
opl:lit_shop_sample (
product_release_tbl.product_release_id,
product_release_tbl.product_id,
product_release_tbl.opsys_name,
product_release_tbl.dbms_name
)
as virtrdf:OplPriceSamples .
opl:LicenseModel(
lm.product_release_id,
lm.product_id,
lm.opsys_family_id,
lm.dbms_family_id,
lm.product_price_type_id)
a opl:LicenseModel
as virtrdf:OplLicenseModel;
a gr:Sell
as virtrdf:OplLicenseModelAgrSell ;
a gr:ActualProductOrServiceInstance
as virtrdf:OplLicenseModelAgrProductOrServiceInstance ;
rdfs:label opl:lit_license_model_type(
lm.product_price_type_id
) as virtrdf:OplLabelLicenseModel ;
rdfs:description opl:lit_license_model_explain (
lm.product_price_type_id
) as virtrdf:OplLicenseModelExplain ;
opl:ProductReleaseId
lm.product_release_id
as virtrdf:lm_shop_price_product_release;
opl:isOfFormat
opl:ProductFormat(lm.product_format_code)
as virtrdf:lm_shop_price_product_format;
opl:isOfCategory
opl:ProductCategory(lm.product_cat_code)
as virtrdf:lm_shop_price_product_cat;
opl:OpsysFamily
opl:OpsysFamily(lm.opsys_family_id)
as virtrdf:lm_shop_price_opsys_family_oplweb;
opl:OpsysType
opl:OpsysType(lm.opsys_type_id)
as virtrdf:lm_shop_price_opsys_type;
opl:DbmsFamily
opl:DbmsFamily(lm.dbms_family_id)
as virtrdf:lm_shop_price_dbms_family ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs: ;
rdfs:isDefinedBy gr:
.
opl:LicenseModel(
lm.product_release_id,
lm.product_id,
lm.opsys_family_id,
lm.dbms_family_id,
lm.product_price_type_id)
opl:hasPriceUnitType
opl:PriceUnitType(
lm2.product_release_id,
lm2.product_id,
lm2.opsys_family_id,
lm2.dbms_family_id,
lm2.product_price_type_id,
lm2.product_price_unit_type_id)
where (
^{lm.}^.product_release_id = ^{lm2.}^.product_release_id AND
^{lm.}^.product_id = ^{lm2.}^.product_id AND
^{lm.}^.opsys_family_id = ^{lm2.}^.opsys_family_id AND
^{lm.}^.opsys_type_id = ^{lm2.}^.opsys_type_id AND
^{lm.}^.product_price_type_id = ^{lm2.}^.product_price_type_id AND
^{lm2.}^.product_price_unit_type_id <> 'db_sessions'
and
(
^{lm.}^.dbms_family_id = ^{lm2.}^.dbms_family_id
OR
^{lm2.}^.dbms_family_id = 15
)
)
as virtrdf:OplLicenseModelPriceUnitTypes .
opl:LicenseModel(
lm.product_release_id,
lm.product_id,
lm.opsys_family_id,
lm.dbms_family_id,
lm.product_price_type_id)
gr:hasPriceSpecification
opl:PriceUnitType(
lm2.product_release_id,
lm2.product_id,
lm2.opsys_family_id,
lm2.dbms_family_id,
lm2.product_price_type_id,
lm2.product_price_unit_type_id)
where (
^{lm.}^.product_release_id = ^{lm2.}^.product_release_id AND
^{lm.}^.product_id = ^{lm2.}^.product_id AND
^{lm.}^.opsys_family_id = ^{lm2.}^.opsys_family_id AND
^{lm.}^.opsys_type_id = ^{lm2.}^.opsys_type_id AND
^{lm.}^.product_price_type_id = ^{lm2.}^.product_price_type_id AND
^{lm2.}^.product_price_unit_type_id = 'db_sessions'
and
(
^{lm.}^.dbms_family_id = ^{lm2.}^.dbms_family_id
OR
^{lm2.}^.dbms_family_id = 15
)
)
as virtrdf:OplLicenseModelBasePriceUnitTypes .
opl:Discount(
gd.product_release_id,
gd.opsys_type_id,
gd.product_id,
gd.opsys_family_id,
gd.dbms_family_id,
gd.product_price_type_id)
a opl:Discount
as virtrdf:product_discount;
rdfs:label gd.product_discount_description as virtrdf:OplLabelDiscount ;
rdfs:description gd.product_discount_description as virtrdf:OplDiscountExplain ;
opl:discount_description
gd.product_discount_description
as virtrdf:gd_discount_description;
opl:discount_start
gd.discount_start
as virtrdf:gd_discount_start;
opl:discount_end
gd.discount_end
as virtrdf:gd_discount_end;
opl:ProductPriceType
opl:PriceType(gd.product_price_type_id)
as virtrdf:gd_shop_price_type;
gr:hasUnitOfMeasurement
opl:PriceType(gd.product_price_type_id)
as virtrdf:gd_shop_price_type_grUnitOfMeasurement;
opl:ProductReleaseId
gd.product_release_id
as virtrdf:gd_shop_price_product_release;
opl:ProductFormat
opl:ProductFormat(gd.product_format_code)
as virtrdf:gd_shop_price_product_format;
opl:ProductCategory
opl:ProductCategory(gd.product_cat_code)
as virtrdf:gd_shop_price_product_cat;
opl:OpsysFamily
opl:OpsysFamily(gd.opsys_family_id)
as virtrdf:gd_shop_price_opsys_family_oplweb;
opl:OpsysType
opl:OpsysType(gd.opsys_type_id)
as virtrdf:gd_shop_price_opsys_type;
opl:DbmsFamily
opl:DbmsFamily(gd.dbms_family_id)
as virtrdf:gd_shop_price_dbms_family;
opl:discount_token
gd.discount_token
as virtrdf:gd_discount_token ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:PriceType(pt.product_price_type_id)
a opl:PriceType
as virtrdf:shop_product_price_type;
rdfs:label pt.product_price_type_description as virtrdf:OplLabelPriceType ;
rdfs:description pt.product_price_type_description as virtrdf:OplPriceTypeExplain ;
opl:PriceTypeDescription
pt.product_price_type_description
as virtrdf:shop_product_price_type_description;
dc:description
pt.product_price_type_long_description
as virtrdf:shop_product_price_type_long_description ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy dc: ;
rdfs:isDefinedBy rdfs:
.
opl:PriceUnitType(
put.product_release_id,
put.product_id,
put.opsys_family_id,
put.dbms_family_id,
put.product_price_type_id,
put.product_price_unit_type_id)
a opl:PriceUnitType
as virtrdf:shop_product_price_unit_type;
rdfs:label put.product_price_unit_description as virtrdf:OplLabelproductpriceunitdescription ;
rdfs:description put.product_price_unit_description as virtrdf:OplproductpriceunitdescriptionExplain ;
gr:hasUnitOfMeasurement
opl:PriceType(put.product_price_type_id)
as virtrdf:put_shop_price_type_grUnitOfMeasurement;
opl:unitValue
put.unit_price
as virtrdf:unit_type_unit_price;
gr:hasValue
put.unit_price
as virtrdf:unit_type_unit_price_grHasValue;
opl:graceUnits
put.unit_grace
as virtrdf:unit_type_unit_grace;
opl:minUnits
put.unit_low
as virtrdf:unit_type_unit_low;
opl:maxUnits
put.unit_cap
as virtrdf:unit_type_unit_cap;
opl:unit_type_description
put.product_price_unit_description
as virtrdf:unit_type_description ;
rdfs:isDefinedBy opl: ;
rdfs:isDefinedBy rdfs:
.
opl:PriceUnitType(
put.product_release_id,
put.product_id,
put.opsys_family_id,
put.dbms_family_id,
put.product_price_type_id,
put.product_price_unit_type_id
)
opl:hasIncrementalDiscount
opl:PriceUnitIncrementalDiscount(
put2.product_release_id,
put2.product_id,
put2.opsys_family_id,
put2.dbms_family_id,
put2.product_price_type_id,
put2.product_price_unit_type_id
)
where (
^{put.}^.product_release_id = ^{put2.}^.product_release_id and
^{put.}^.product_id = ^{put2.}^.product_id and
^{put.}^.opsys_family_id = ^{put2.}^.opsys_family_id and
^{put.}^.dbms_family_id = ^{put2.}^.dbms_family_id and
^{put.}^.product_price_type_id = ^{put2.}^.product_price_type_id and
^{put.}^.product_price_unit_type_id = ^{put2.}^.product_price_unit_type_id
)
as virtrdf:OplLicenseModelUnitsIncrementalDiscounts .
opl:PriceUnitIncrementalDiscount(
put.product_release_id,
put.product_id,
put.opsys_family_id,
put.dbms_family_id,
put.product_price_type_id,
put.product_price_unit_type_id)
a opl:PriceUnitIncrementalDiscount
as virtrdf:shop_product_price_unit_type_incremental_discount;
rdfs:label put.product_price_unit_description as virtrdf:OplLabelproductpriceunitIncDisdescription ;
rdfs:description put.product_price_unit_description as virtrdf:OplproductpriceunitIncDisdescriptionExplain ;
opl:percentageOfBase
put.unit_discount
as virtrdf:unit_type_unit_discount;
opl:triggerPoint
put.quantity
as virtrdf:unit_type_unit_discount_quantity
.
opl:LicenseModel(
lm.product_release_id,
lm.product_id,
lm.opsys_family_id,
lm.dbms_family_id,
lm.product_price_type_id
)
opl:hasGeneralDiscounts
opl:Discount(
gd.product_release_id,
gd.opsys_type_id,
gd.product_id,
gd.opsys_family_id,
gd.dbms_family_id,
gd.product_price_type_id
)
where (
^{lm.}^.product_release_id = ^{gd.}^.product_release_id AND
^{lm.}^.product_id = ^{gd.}^.product_id AND
^{lm.}^.opsys_family_id = ^{gd.}^.opsys_family_id AND
^{lm.}^.dbms_family_id = ^{gd.}^.dbms_family_id AND
^{lm.}^.opsys_type_id = ^{gd.}^.opsys_type_id AND
^{lm.}^.product_price_type_id = ^{gd.}^.product_price_type_id
)
as virtrdf:OplLicenseModelGeneralDiscounts .
} .
} .
;
DB.DBA.XML_SET_NS_DECL ('OpenLink', 'http://www.openlinksw.com/schemas/oplweb#', 2);
DB.DBA.XML_SET_NS_DECL ('OplProductCategory', 'http://data.openlinksw.com/oplweb/product_category/', 2);
DB.DBA.XML_SET_NS_DECL ('OplProductFamily', 'http://data.openlinksw.com/oplweb/product_family/', 2);
DB.DBA.XML_SET_NS_DECL ('OplProductFormat', 'http://data.openlinksw.com/oplweb/product_format/', 2);
DB.DBA.XML_SET_NS_DECL ('OplProduct', 'http://data.openlinksw.com/oplweb/product/', 2);
DB.DBA.XML_SET_NS_DECL ('OplProductRelease', 'http://data.openlinksw.com/oplweb/product_release/', 2);
DB.DBA.RDF_AUDIT_METADATA (1, '*');
commit work;
-- Clear the 'cache' for immediate effects
SELECT hs_local_iri, exec ('SPARQL clear graph <'||hs_local_iri||'>')
FROM sys_http_sponge
WHERE hs_local_iri like '%oplweb%';
SELECT id_to_iri(G), exec ('SPARQL clear graph <'||id_to_iri(G)||'>')
FROM rdf_quad
WHERE id_to_iri(G) like '%oplweb%';
SPARQL CLEAR GRAPH <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>;
commit work;
SPARQL CONSTRUCT { <http://data.openlinksw.com/oplweb/product_family/uda#this> ?p ?o }
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/product_family/uda#this> ?p ?o }
;
SPARQL SELECT *
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/product_category/odbc#this> ?p ?o }
limit 100
;
SPARQL define get:soft "soft" SELECT *
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/product_category/odbc#this> ?p ?o }
limit 100
;
SPARQL CONSTRUCT { <http://data.openlinksw.com/oplweb/product_category/jdbc#this> ?p ?o }
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/product_category/jdbc#this> ?p ?o }
limit 100
;
SPARQL CONSTRUCT { <http://data.openlinksw.com/oplweb/product_format/mt#this> ?p ?o }
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/product_format/mt#this> ?p ?o }
limit 1
;
SPARQL SELECT ?p ?o
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/product_family/uda#this> ?p ?o }
limit 1
;
SPARQL
prefix opl: <http://www.openlinksw.com/schemas/oplweb#>
SELECT ?s ?o
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { ?s opl:hasProcessors ?o }
limit 1
;
SPARQL
prefix opl: <http://www.openlinksw.com/schemas/oplweb#>
SELECT distinct ?o
FROM <http://www.openlinksw.com/dataspace/organization/openlink/oplweb/>
WHERE { <http://data.openlinksw.com/oplweb/processor/i686_1#this> opl:hasProductFamily ?o }
limit 10
;
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/price_unit_type/6.1_odbc-sqlserver-st_1_2_1_db_sessions#this"
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/price_unit_type/6.1_odbc-sqlserver-st_1_2_1_cpu#this"
--SELECT top 10 * FROM oplweb2.DBA.license_model_unit_type WHERE product_release_id = '6.1' and product_id = 'odbc-sqlserver-st'
-- and opsys_family_id = 1 and dbms_family_id = 15 and product_price_type_id = 1 and product_price_unit_type_id = 'cpu';
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/rdfbrowser/index.html?uri=http%3A//data.openlinksw.com/oplweb/component_archive/6.1-odbc-oracle-st-i686-generic-win-32-ora10-odbclt-clnt-only_mv.msi"
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/product_family/uda"
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/product_category/odbc"
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/dbms_family/MySQL"
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/product_release/odbc-oracle-mt_6.1_i686-generic-win-32_ora9"
-- curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/license_model/6.1_odbc-sqlserver-st_1_2_1"
curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/rdfbrowser/index.html?uri=http%3A//data.openlinksw.com/oplweb/component_archive/6.1-odbc-oracle-st-i686-generic-win-32-ora10-odbclt-clnt-only_mv.msi"
curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/product_family/uda"
curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/product_release/odbc-oracle-mt_6.1_i686-generic-win-32_ora9"
curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/license_model/6.1_odbc-sqlserver-st_1_2_1"
--
-- XXX: note , the below would work only if www.openlinksw.com has the GRAPH <http://data.openlinksw.com/oplweb/>
-- if experimenting on other box, then www.openlinksw.com should be replaced with [URIQA] DefaultHost INI value
--
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oplweb2_rule2',
1,
'/oplweb(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//data.openlinksw.com/oplweb%U%%23this%%3E+%%3Fp+%%3Fo+}+FROM+%%3Chttp%%3A//www.openlinksw.com/dataspace/organization/openlink/oplweb/%%3E+WHERE+{+%%3Chttp%%3A//data.openlinksw.com/oplweb%U%%23this%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oplweb2_rule1',
1,
'(/oplweb/[^#]*)',
vector('path'),
1,
'/rdfbrowser/index.html?uri=http%%3A//data.openlinksw.com%U%',
-- '/DAV/RDF/rdfqry.vsp?uri=http%%3A//data.openlinksw.com%U%%23this',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oplweb2_rule3',
1,
'(/[^#]*)/\x24',
vector('path'),
1,
'%s',
vector('path'),
null,
null,
0,
null
);
create procedure DB.DBA.REDO_OPLWEB2_RDF_DET()
{
declare colid int;
colid := DAV_SEARCH_ID('/DAV/RDF/oplweb2/', 'C');
if (colid < 0)
return;
update WS.WS.SYS_DAV_COL set COL_DET=null where COL_ID = colid;
}
;
DB.DBA.REDO_OPLWEB2_RDF_DET();
drop procedure DB.DBA.REDO_OPLWEB2_RDF_DET;
DB.DBA."RDFData_MAKE_DET_COL" ('/DAV/RDF/oplweb2/', 'http://data.openlinksw.com/oplweb', NULL);
VHOST_REMOVE (lpath=>'/oplweb/data/rdf');
DB.DBA.VHOST_DEFINE (lpath=>'/oplweb/data/rdf', ppath=>'/DAV/RDF/oplweb2/All/', is_dav=>1, vsp_user=>'dba');
-- procedure to convert path to DET resource name
create procedure DB.DBA.OPLWEB2_DET_REF (in par varchar, in fmt varchar, in val varchar)
{
declare res, iri any;
iri := 'http://data.openlinksw.com/oplweb' || val;
res := sprintf ('iid (%d).rdf', iri_id_num (iri_to_id (iri)));
return sprintf (fmt, res);
}
;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('oplweb2_rdf', 1,
'/oplweb/(.*)', vector('path'), 1,
'/oplweb/data/rdf/%U', vector('path'),
'DB.DBA.OPLWEB2_DET_REF',
'application/rdf.xml',
2,
303);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'oplweb2_rule_list1',
1,
vector (
'oplweb2_rule1',
'oplweb2_rule2',
'oplweb2_rule3',
'oplweb2_rdf'
));
VHOST_REMOVE (vhost=>'data.openlinksw.com:80', lpath=>'/oplweb');
DB.DBA.VHOST_DEFINE (vhost=>'data.openlinksw.com:80', lpath=>'/oplweb', ppath=>'/DAV/RDF/oplweb2/',
vsp_user=>'dba', is_dav=>1, def_page=>'sfront.vspx', is_brws=>0, opts=>vector ('url_rewrite', 'oplweb2_rule_list1'));
/*
DB.DBA.VHOST_DEFINE (vhost=>'data.openlinksw.com:80', lhost=>':80', lpath=>'/rdf_net', ppath=>'/rdf_net');
DB.DBA.VHOST_DEFINE (vhost=>'data.openlinksw.com:80', lhost=>':80', lpath=>'/sparql/',
ppath => '/!sparql/', is_dav => 1, vsp_user => 'dba', opts => vector('noinherit', 1));
VHOST_REMOVE (vhost=>'data.openlinksw.com', lpath=>'/proxy');
DB.DBA.VHOST_DEFINE (vhost=>'data.openlinksw.com', lhost=>':80', lpath=>'/proxy',
ppath=>'/SOAP/Http/ext_http_proxy', soap_user=>'PROXY');
DB.DBA.VHOST_DEFINE (vhost=>'data.openlinksw.com:80', lhost=>':80', lpath=>'/xml_a',
ppath=>'/SOAP/',soap_user=>'XML_A');
DB.DBA.VHOST_DEFINE (vhost=>'data.openlinksw.com:80', lhost=>':80', lpath=>'/XMLA',
ppath=>'/SOAP/', soap_user=>'XMLA', soap_opts => vector ('ServiceName', 'XMLAnalysis', 'elementFormDefault', 'qualified'))
GRANT EXECUTE ON DB.DBA.RDF_SPONGE_UP TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON DB.DBA.TTLP_EV_NEW_GRAPH TO "SPARQL", "SPARQL_UPDATE";
grant SPARQL_UPDATE to "SPARQL";
curl -H "Accept: application/rdf+xml" "http://data.openlinksw.com/oplweb/product_family/uda#this"
SELECT hs_local_iri, exec ('sparql clear graph <'||hs_local_iri||'>') from sys_http_sponge;
*/
OWL based Ontology
--sparql construct { ?x ?y ?z } from --<http://www.openlinksw.com/dataspace/organization/openlink#this>
-- where { ?x ?y ?z }
DB.DBA.RDF_LOAD_RDFXML_MT (
'<?xml version="1.0"?>
<rdf:RDF
xmlns="http://www.openlinksw.com/dataspace/organization/openlink/oplweb#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:virtrdf="http://www.openlinksw.com/schemas/virtrdf#"
xml:base="http://www.openlinksw.com/schemas/oplweb#">
<owl:Ontology rdf:about="http://www.openlinksw.com/schemas/oplweb#">
<rdfs:label>ProductPortfolio</rdfs:label>
<rdfs:comment>OpenLink Product Portfolio</rdfs:comment>
<virtrdf:catName>oplweb</virtrdf:catName>
<virtrdf:version>1.00</virtrdf:version>
</owl:Ontology>
<!-- Family / Category / Format -->
<rdfs:Class rdf:ID="ProductFamily">
<rdfs:label>Product Family</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Family
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductCategory">
<rdfs:label>Product Category</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Category
</rdfs:comment>
<rdfs:subPropertyOf rdf:resource="#ProductFamily"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductFormat">
<rdfs:label>Product Format</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Format
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductFormatCategory">
<rdfs:label>Product Format Category</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Format Category
</rdfs:comment>
</rdfs:Class>
<rdf:Property rdf:ID="ProductFamilyDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:label>Product Family Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductFamilyLongDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:label>Product Family Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductFamilyCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:label>Product Family Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductFormatDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:label>Product Format Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductFormatLongDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:label>Product Format Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductFormatCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFormatCategory"/>
<rdfs:label>Product Format Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductCategoryDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:label>Product Category Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductCategoryLongDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:label>Product Category Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductCategoryCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFormatCategory"/>
<rdfs:label>Product Category Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="hasProduct">
<rdfs:range rdf:resource="#Product"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFormatCategory"/>
<rdfs:label>Product</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="hasCategory">
<rdfs:range rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:label>Product</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="hasFormat">
<rdfs:range rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:label>Product</rdfs:label>
</rdf:Property>
<!-- Vendor -->
<rdfs:Class rdf:ID="VendorCategoryFamily">
<rdfs:label>vendor_category_family</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
vendor_category_family
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="VendorCategory">
<rdfs:label>vendor_category</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
vendor_category
</rdfs:comment>
<rdfs:subClassOf rdf:resource="VendorCategoryFamily"/>
</rdfs:Class>
<rdfs:Class rdf:ID="Vendors">
<rdfs:label>vendors</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
vendors
</rdfs:comment>
<rdfs:subClassOf rdf:resource="VendorCategory"/>
</rdfs:Class>
<rdf:Property rdf:ID="VendorName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Vendors"/>
<rdfs:label>vendor name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="VendorCategoryFamilyDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#VendorCategoryFamily"/>
<rdfs:label>vendor_category_family_description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="VendorCategoryDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#VendorCategory"/>
<rdfs:label>vendor_category_description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="isOfVendorCategory">
<rdfs:range rdf:resource="#VendorCategory"/>
<rdfs:domain rdf:resource="#Vendors"/>
<rdfs:label>vendor_category_description</rdfs:label>
</rdf:Property>
<!-- Opsys / DBMS -->
<rdfs:Class rdf:ID="OpsysFamily">
<rdfs:label>Opsys Family</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Opsys Family
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="DbmsFamily">
<rdfs:label>Dbms Family</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Dbms Family
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="DbmsEngine">
<rdfs:label>Dbms Engine</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Dbms Engine
</rdfs:comment>
<rdfs:subClassOf rdf:resource="DbmsFamily"/>
</rdfs:Class>
<rdfs:Class rdf:ID="OpsysType">
<rdfs:label>Opsys Type</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Opsys Type
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ProcessorMode">
<rdfs:label>Processor Mode</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Processor Mode
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="Processor">
<rdfs:label>Processor</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Processor
</rdfs:comment>
<rdfs:subClassOf rdf:resource="ProcessorFamily"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProcessorFamily">
<rdfs:label>Processor Family</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Processor Family
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="Opsys">
<rdfs:label>Dbms Engine</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
opsys
</rdfs:comment>
<rdfs:subClassOf rdf:resource="OpsysFamily"/>
<rdfs:subClassOf rdf:resource="OpsysType"/>
</rdfs:Class>
<rdf:Property rdf:ID="OpsysFamilyName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#OpsysFamily"/>
<rdfs:label>Opsys Family Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysFamilyRating">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#OpsysFamily"/>
<rdfs:label>Opsys Family Rating</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysFamilyLicenseCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#OpsysFamily"/>
<rdfs:label>Opsys Family License Code</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysFamilyVendor">
<rdfs:range rdf:resource="#Vendors"/>
<rdfs:domain rdf:resource="#OpsysFamily"/>
<rdfs:label>Opsys Family Vendor</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsFamilyName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsFamily"/>
<rdfs:label>DBMS Family Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsFamilyVendor">
<rdfs:range rdf:resource="#Vendors"/>
<rdfs:domain rdf:resource="#DbmsFamily"/>
<rdfs:label>DBMS Family Vendor</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:label>DBMS Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsVersion">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:label>DBMS Version</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsEngineRating">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:label>DBMS Engine Rating</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsEngineOldArchiveCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:label>DBMS Engine old Archive Code</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsUpwardCompatible">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:label>DBMS Upward Compatible</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DbmsDownwardCompatible">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:label>DBMS Downward Compatible</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysTypeDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#OpsysType"/>
<rdfs:label>Opsys Type Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysTypeShortDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#OpsysType"/>
<rdfs:label>Opsys Type Short Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysVersion">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Version</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysUpwardCompatible">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Compatible</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysDownwardCompatible">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Downward Compatible</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysLicenseCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys License Code</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysCommercialName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Commercial Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysProcessor">
<rdfs:range rdf:resource="#Processor"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Processor</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OpsysEmulation">
<rdfs:range rdf:resource="#ProcessorMode"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:label>Opsys Emulation Mode</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorModeName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProcessorMode"/>
<rdfs:label>Processor Mode Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Processor"/>
<rdfs:label>Processor Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorProcessorMode">
<rdfs:range rdf:resource="#ProcessorMode"/>
<rdfs:domain rdf:resource="#Processor"/>
<rdfs:label>Processor Mode</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Processor"/>
<rdfs:label>Processor Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorFamilyName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProcessorFamily"/>
<rdfs:label>Processor Family Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorFamilyDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProcessorFamily"/>
<rdfs:label>Processor Family Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProcessorFamilyVendor">
<rdfs:range rdf:resource="#Vendors"/>
<rdfs:domain rdf:resource="#ProcessorFamily"/>
<rdfs:label>Processor Family Vendor</rdfs:label>
</rdf:Property>
<!-- Product / Product Release -->
<rdfs:Class rdf:ID="Product">
<rdfs:label>Product</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product
</rdfs:comment>
<rdfs:subPropertyOf rdf:resource="#ProductFormat"/>
<rdfs:subPropertyOf rdf:resource="#ProductCategory"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductRelease">
<rdfs:label>Product Release</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Release
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#Product"/>
</rdfs:Class>
<rdf:Property rdf:ID="ProductId">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:label>Product ID</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="isOfCategory">
<rdfs:range rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:label>Product Category</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="isOfFormat">
<rdfs:range rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:label>Product Category</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductDescription">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:label>Product Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductLongDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:label>Product Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductReleaseId">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Product Release ID</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductReleaseOpsys">
<rdfs:range rdf:resource="#Opsys"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Product Release Opsys</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductReleaseDbms">
<rdfs:range rdf:resource="#DbmsEngine"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Product Release DBMS</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductReleaseUpwardCompatible">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Product Release upward compatible</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductReleaseDownwardCompatible">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Product Release downward compatible</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductReleaseSupported">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Product Release Supported</rdfs:label>
</rdf:Property>
<!-- Components -->
<rdfs:Class rdf:ID="Component">
<rdfs:label>Components</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Components
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ComponentMode">
<rdfs:label>Component Mode</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Component
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ComponentType">
<rdfs:label>Component</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Component Type
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ComponentCategory">
<rdfs:label>Component Category</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Component
</rdfs:comment>
</rdfs:Class>
<rdf:Property rdf:ID="ComponentModeDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentMode"/>
<rdfs:label>Component Mode Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentModeShortDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentMode"/>
<rdfs:label>Component Mode Short Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentTypeDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentType"/>
<rdfs:label>Component Type Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentTypeShortDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentType"/>
<rdfs:label>Component Type Short Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentCategoryDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentCategory"/>
<rdfs:label>Component Category Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentCategoryLongDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentCategory"/>
<rdfs:label>Component Category Long Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentCategoryShortDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentCategory"/>
<rdfs:label>Component Category Short Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentCvsid">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components CVSID</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentBuildDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Build Date</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Notes">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Notes</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="BuildComments">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Build Comments</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Filesize">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentComponentCategory">
<rdfs:range rdf:resource="#ComponentCategory"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Component Category</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentComponentType">
<rdfs:range rdf:resource="#ComponentType"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Component Type</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentComponentMode">
<rdfs:range rdf:resource="#ComponentMode"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Component Mode</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentOpsys">
<rdfs:range rdf:resource="#Opsys"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components Opsys</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentDbmsEngine">
<rdfs:range rdf:resource="#DbmsEngine"/>
<rdfs:domain rdf:resource="#Component"/>
<rdfs:label>Components DBMS</rdfs:label>
</rdf:Property>
<!-- Component Archives -->
<rdfs:Class rdf:ID="ComponentArchive">
<rdfs:label>Component Archive</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Component Archives
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductRelease"/>
<rdfs:subClassOf rdf:resource="#Component"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ComponentArchiveType">
<rdfs:label>Component Archive Type</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Component Archives Type
</rdfs:comment>
</rdfs:Class>
<rdf:Property rdf:ID="ComponentArchiveTypeName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchiveType"/>
<rdfs:label>Component Archive Type Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveTypeShortName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchiveType"/>
<rdfs:label>Component Archive Type Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveTypeExtension">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchiveType"/>
<rdfs:label>Component Archive Type Extension</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveComponentArchiveType">
<rdfs:range rdf:resource="#ComponentArchiveType"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive Component Archive Type</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveName">
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveAssemblyDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive Assembly Date</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveFileUri">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive File URI</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveLicenseCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive License Code</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveResName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive DAV Resource Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveResFullPath">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive DAV Full Path</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ComponentArchiveResFileSize">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:label>Component Archive File Size in DAV</rdfs:label>
</rdf:Property>
<!-- Download locations -->
<rdfs:Class rdf:ID="DownloadLocation">
<rdfs:label>Download Location</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Download Location
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ComponentArchive"/>
<rdfs:subClassOf rdf:resource="#DownloadPartner"/>
<rdfs:subClassOf rdf:resource="#DownloadProtocol"/>
</rdfs:Class>
<rdfs:Class rdf:ID="DownloadProtocol">
<rdfs:label>Download Protocol</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Download Protocol
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="DownloadPartner">
<rdfs:label>Download Partner</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Download Partner
</rdfs:comment>
</rdfs:Class>
<rdf:Property rdf:ID="ProtocolName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadProtocol"/>
<rdfs:label>Protocol Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProtocolDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadProtocol"/>
<rdfs:label>Protocol Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProtocolActive">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadProtocol"/>
<rdfs:label>Protocol Active</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="PartnerName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadPartner"/>
<rdfs:label>Download Partner Partner Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="HostName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadPartner"/>
<rdfs:label>Download Partner Hostname</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DomainName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadPartner"/>
<rdfs:label>Download Partner Domain Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="PortNumber">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadPartner"/>
<rdfs:label>Download Partner Port Number</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Uri">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadLocation"/>
<rdfs:label>Download Location URI</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="UriOld">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#DownloadLocation"/>
<rdfs:label>Download Location URI Old</rdfs:label>
</rdf:Property>
<!-- Features and Benefits -->
<rdfs:Class rdf:ID="ProductBenefit">
<rdfs:label>Product Benefit</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Benefit
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductBenefitCategory"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductBenefitCategory">
<rdfs:label>Product Benefit</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Benefit
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductFeatureCategory">
<rdfs:label>Product Feature Category</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Feature Category
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductFeature">
<rdfs:label>Product Features</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Features
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductFeatureCategory"/>
<rdfs:subClassOf rdf:resource="#ProductBenefit"/>
<rdfs:subClassOf rdf:resource="#Product"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductFamilyFeature">
<rdfs:label>Product Family Features</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Family Features
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductFeatureCategory"/>
<rdfs:subClassOf rdf:resource="#ProductBenefit"/>
<rdfs:subClassOf rdf:resource="#ProductFamily"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductFormatFeature">
<rdfs:label>Product Format Features</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Format Features
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductFeatureCategory"/>
<rdfs:subClassOf rdf:resource="#ProductBenefit"/>
<rdfs:subClassOf rdf:resource="#ProductFormat"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductCategoryFeature">
<rdfs:label>Product Category Features</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Category Features
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductFeatureCategory"/>
<rdfs:subClassOf rdf:resource="#ProductBenefit"/>
<rdfs:subClassOf rdf:resource="#ProductCategory"/>
</rdfs:Class>
<rdfs:Class rdf:ID="ProductReleaseFeature">
<rdfs:label>Product Benefit</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Product Benefit
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#ProductFeatureCategory"/>
<rdfs:subClassOf rdf:resource="#ProductBenefit"/>
<rdfs:subClassOf rdf:resource="#ProductRelease"/>
</rdfs:Class>
<rdf:Property rdf:ID="ProductBenefitsCategoryDescription">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductBenefitsCategory"/>
<rdfs:label>product Benefits Category</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Description">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductBenefit"/>
<rdfs:domain rdf:resource="#ProductBenefitCategory"/>
<rdfs:domain rdf:resource="#ProductFeatureCategory"/>
<rdfs:domain rdf:resource="#ProductFeature"/>
<rdfs:domain rdf:resource="#ProductFamilyFeature"/>
<rdfs:domain rdf:resource="#ProductFormatFeature"/>
<rdfs:domain rdf:resource="#ProductCategoryFeature"/>
<rdfs:domain rdf:resource="#ProductReleaseFeature"/>
<rdfs:label>Product Benefits Description</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Details">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductFeature"/>
<rdfs:domain rdf:resource="#ProductFamilyFeature"/>
<rdfs:domain rdf:resource="#ProductFormatFeature"/>
<rdfs:domain rdf:resource="#ProductCategoryFeature"/>
<rdfs:domain rdf:resource="#ProductReleaseFeature"/>
<rdfs:label>Product Benefits Description Details</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductBenefitsAcronym">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductBenefit"/>
<rdfs:label>Product Benefits Acronym</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductBenefitsExplanation">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductBenefit"/>
<rdfs:label>Product Benefits Explanation</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="DemoUrl">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductCategoryFeature"/>
<rdfs:domain rdf:resource="#ProductFormatFeature"/>
<rdfs:domain rdf:resource="#ProductFamilyFeature"/>
<rdfs:domain rdf:resource="#ProductReleaseFeature"/>
<rdfs:label>The Features Demo URL</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="HypesPerSecond">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#ProductCategoryFeature"/>
<rdfs:domain rdf:resource="#ProductFormatFeature"/>
<rdfs:domain rdf:resource="#ProductFamilyFeature"/>
<rdfs:domain rdf:resource="#ProductreleaseFeature"/>
<rdfs:label>The Features Number of Hypes per second</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Implemented">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#ProductCategoryFeature"/>
<rdfs:domain rdf:resource="#ProductFormatFeature"/>
<rdfs:domain rdf:resource="#ProductFamilyFeature"/>
<rdfs:domain rdf:resource="#ProductReleaseFeature"/>
<rdfs:label>The Features Short Description</rdfs:label>
</rdf:Property>
<!-- shop / pricing stuff -->
<rdfs:Class rdf:ID="LicenseType">
<rdfs:label>License Type</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
License Type
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="UnitType">
<rdfs:label>Unit Type</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Unit Type
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="GeneralDiscount">
<rdfs:label>General Discount</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
General Discount
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="IncrementalDiscount">
<rdfs:label>Incremental Discount</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
Incremental Discount
</rdfs:comment>
</rdfs:Class>
<rdfs:Class rdf:ID="License">
<rdfs:label>License</rdfs:label>
<rdfs:comment rdf:datatype="http://www.w3.org/2001/XMLSchema#string">
License
</rdfs:comment>
<rdfs:subClassOf rdf:resource="#LicenseType"/>
<rdfs:subClassOf rdf:resource="#ProductRelease"/>
</rdfs:Class>
<rdf:Property rdf:ID="BaseCostUnit">
<rdfs:range rdf:resource="#UnitType"/>
<rdfs:domain rdf:resource="#License"/>
<rdfs:label>Base Unit Cost</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="PriceUnit">
<rdfs:range rdf:resource="#UnitType"/>
<rdfs:domain rdf:resource="#License"/>
<rdfs:label>Price Unit Cost</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="hasDiscount">
<rdfs:range rdf:resource="#IncrementalDiscount"/>
<rdfs:domain rdf:resource="#UnitType"/>
<rdfs:label>Base Unit Cost</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="hasGeneralDiscount">
<rdfs:range rdf:resource="#GeneralDiscount"/>
<rdfs:domain rdf:resource="#License"/>
<rdfs:label>General Discount</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="unitValue">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#UnitType"/>
<rdfs:label>Unit Value</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="graceUnit">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#UnitType"/>
<rdfs:label>Grace Unit</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="minUnits">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#UnitType"/>
<rdfs:label>Minimum Units</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="maxUnits">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#UnitType"/>
<rdfs:label>Maximum Units</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="codeWord">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#GeneralDiscount"/>
<rdfs:label>Code Word needed to activate this discount</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="startDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#GeneralDiscount"/>
<rdfs:label>Discount Start Date</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="endDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#GeneralDiscount"/>
<rdfs:label>Discount End Date</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="percentageOfCost">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#GeneralDiscount"/>
<rdfs:label>Percentage of cost attributing as discount</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="triggerPoint">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#IncrementalDiscount"/>
<rdfs:label>Discount Trigger Point</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="percentageOfBase">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#IncrementalDiscount"/>
<rdfs:label>Percentage of base cost attributing as discount</rdfs:label>
</rdf:Property>
<!-- common properties -->
<rdf:Property rdf:ID="label">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://www.w3.org/2001/XMLSchema#label"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:domain rdf:resource="#VendorCategory"/>
<rdfs:domain rdf:resource="#Vendor"/>
<rdfs:domain rdf:resource="#OpsysFamily"/>
<rdfs:domain rdf:resource="#DbmsFamily"/>
<rdfs:domain rdf:resource="#DbmsEngine"/>
<rdfs:domain rdf:resource="#OpsysType"/>
<rdfs:domain rdf:resource="#Processor"/>
<rdfs:domain rdf:resource="#ProcessorFamily"/>
<rdfs:domain rdf:resource="#Opsys"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:domain rdf:resource="#ComponentMode"/>
<rdfs:domain rdf:resource="#ComponentType"/>
<rdfs:domain rdf:resource="#ComponentCategory"/>
<rdfs:domain rdf:resource="#ComponentArchive"/>
<rdfs:domain rdf:resource="#ComponentArchiveType"/>
<rdfs:domain rdf:resource="#DownloadLocation"/>
<rdfs:domain rdf:resource="#ProductBenefit"/>
<rdfs:domain rdf:resource="#ProductBenefitCategory"/>
<rdfs:domain rdf:resource="#ProductFeatureCategory"/>
<rdfs:domain rdf:resource="#ProductFeature"/>
<rdfs:domain rdf:resource="#ProductFamilyFeature"/>
<rdfs:domain rdf:resource="#ProductFormatFeature"/>
<rdfs:domain rdf:resource="#ProductCategoryFeature"/>
<rdfs:domain rdf:resource="#ProductReleaseFeature"/>
<rdfs:domain rdf:resource="#LicenseModel"/>
<rdfs:domain rdf:resource="#Discount"/>
<rdfs:domain rdf:resource="#PriceType"/>
<rdfs:domain rdf:resource="#PriceUnitType"/>
<rdfs:label>Label</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="name">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="logo">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/logo"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:label>logo</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="homepage">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/homepage"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#ProcessorFamily"/>
<rdfs:domain rdf:resource="#OpsysFamily"/>
<rdfs:domain rdf:resource="#DbmsFamily"/>
<rdfs:label>homepage</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="maker">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/maker"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:label>Maker</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="sameAs">
<rdfs:range rdf:resource="owl#sameAs"/>
<rdfs:domain rdf:resource="#ProductCategory"/>
<rdfs:domain rdf:resource="#ProductFormat"/>
<rdfs:domain rdf:resource="#ProductFamily"/>
<rdfs:domain rdf:resource="#ProductRelease"/>
<rdfs:domain rdf:resource="#ProductFormatCategory"/>
<rdfs:label>Name</rdfs:label>
</rdf:Property>
</rdf:RDF>
',
'http://www.openlinksw.com/schemas/oplweb#',
'http://www.openlinksw.com/schemas/oplweb#')
--'http://www.openlinksw.com/dataspace/organization/openlink/ProductPortfolioOntology/1.0/')
;
rdfs_rule_set ('oplweb2_owlset', 'http://www.openlinksw.com/schemas/oplweb#', 1);
DB.DBA.XML_SET_NS_DECL ('opl', 'http://www.openlinksw.com/schemas/oplweb#', 2);
]]></programlisting>
</sect4>
</sect3>
<sect3 id="rdfviewsenterprsyb">
<title>Sybase using demonstration 'pubs2' database</title>
<programlisting><![CDATA[
-- Setup script for RDF views of Sybase 15 PUBS2 Sample Database --
DB..vd_remote_data_source ('syb15ma-pubs2', '', '<uid>','<pwd>');
ATTACH TABLE "pubs2.dbo.au_pix" PRIMARY KEY ("au_id") AS "pubs2"."syb"."au_pix" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.authors" PRIMARY KEY ("au_id") AS "pubs2"."syb"."authors" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.discounts" PRIMARY KEY ("stor_id") AS "pubs2"."syb"."discounts" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.publishers" PRIMARY KEY ("pub_id") AS "pubs2"."syb"."publishers" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.roysched" PRIMARY KEY ("title_id") AS "pubs2"."syb"."roysched" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.sales" PRIMARY KEY ("stor_id", "ord_num") AS "pubs2"."syb"."sales" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.salesdetail" PRIMARY KEY ("stor_id", "ord_num", "title_id") AS "pubs2"."syb"."salesdetail" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.stores" PRIMARY KEY ("stor_id") AS "pubs2"."syb"."stores" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.titleauthor" PRIMARY KEY ("au_id", "title_id") AS "pubs2"."syb"."titleauthor" FROM 'syb15ma-pubs2';
ATTACH TABLE "pubs2.dbo.titles" PRIMARY KEY ("title_id", "pub_id") AS "pubs2"."syb"."titles" FROM 'syb15ma-pubs2';
COMMIT WORK;
GRANT SELECT ON pubs2.syb.au_pix TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.authors TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.discounts TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.publishers TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.roysched TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.sales TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.salesdetail TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.stores TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.titleauthor TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON pubs2.syb.titles TO "SPARQL", "SPARQL_UPDATE";
-------------------------------------------------------------------
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix syb: <http://localhost:8890/schemas/sybasepubs2/> .
syb:titles a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "titles" ;
rdfs:comment "Sybase Pubs2 titles table" .
syb:title_id a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:string ;
rdfs:label "title id" .
syb:title a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:string ;
rdfs:label "title" .
syb:type a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:string ;
rdfs:label "type" .
syb:pub_id a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range syb:publishers ;
rdfs:label "pub_id" .
syb:advance a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:decimal ;
rdfs:label "advance" .
syb:price a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:decimal ;
rdfs:label "price" .
syb:total_sales a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:integer ;
rdfs:label "total_sales" .
syb:notes a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:string ;
rdfs:label "notes" .
syb:contract a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:integer ;
rdfs:label "contract" .
syb:pubdate a rdf:Property ;
rdfs:domain syb:titles ;
rdfs:range xsd:dateTime ;
rdfs:label "publish date" .
syb:authors a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "authors" ;
rdfs:comment "Sybase Pubs2 authors table" .
syb:au_id a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "author id" .
syb:au_lname a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "author last name" .
syb:au_fname a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "author first name" .
syb:phone a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "phone number" .
syb:address a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "address" .
syb:city a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "city" .
syb:state a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "state" .
syb:country a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "country" .
syb:postalcode a rdf:Property ;
rdfs:domain syb:authors ;
rdfs:range xsd:string ;
rdfs:label "postalcode" .
syb:stores a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "stores" ;
rdfs:comment "Sybase Pubs2 stores table" .
syb:stor_id a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "store id" .
syb:stor_name a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "store name" .
syb:stor_address a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "store address" .
syb:city a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "city" .
syb:state a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "state" .
syb:country a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "country" .
syb:postalcode a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "postal code" .
syb:payterms a rdf:Property ;
rdfs:domain syb:stores ;
rdfs:range xsd:string ;
rdfs:label "payment terms" .
syb:au_pix a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "authors pictures" ;
rdfs:comment "Sybase Pubs2 au_pix table" .
syb:au_id a rdf:Property ;
rdfs:domain syb:au_pix ;
rdfs:range syb:authors ;
rdfs:label "author id" .
syb:format_type a rdf:Property ;
rdfs:domain syb:au_pix ;
rdfs:range xsd:string ;
rdfs:label "format type" .
syb:bytesize a rdf:Property ;
rdfs:domain syb:au_pix ;
rdfs:range xsd:integer ;
rdfs:label "byte size" .
syb:pixwidth_hor a rdf:Property ;
rdfs:domain syb:au_pix ;
rdfs:range xsd:string ;
rdfs:label "picture horizontal width" .
syb:pixwidth_vert a rdf:Property ;
rdfs:domain syb:au_pix ;
rdfs:range xsd:string ;
rdfs:label "picture vertical width" .
syb:discounts a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "discounts" ;
rdfs:comment "Sybase Pubs2 discount table" .
syb:discounttype a rdf:Property ;
rdfs:domain syb:discounts ;
rdfs:range xsd:string ;
rdfs:label "discounttype" .
syb:stor_id a rdf:Property ;
rdfs:domain syb:discounts ;
rdfs:range syb:stores ;
rdfs:label "store id" .
syb:lowqty a rdf:Property ;
rdfs:domain syb:discounts ;
rdfs:range xsd:integer ;
rdfs:label "min quantity" .
syb:highqty a rdf:Property ;
rdfs:domain syb:discounts ;
rdfs:range xsd:integer ;
rdfs:label "max quantity" .
syb:discount a rdf:Property ;
rdfs:domain syb:discounts ;
rdfs:range xsd:decimal ;
rdfs:label "min quantity" .
syb:salesdetail a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "sales details" ;
rdfs:comment "Sybase Pubs2 sales detail table" .
syb:store_id a rdf:Property ;
rdfs:domain syb:salesdetail ;
rdfs:range syb:stores ;
rdfs:label "store id" .
syb:ord_num a rdf:Property ;
rdfs:domain syb:salesdetail ;
rdfs:range syb:sales ;
rdfs:label "order number" .
syb:title_id a rdf:Property ;
rdfs:domain syb:salesdetail ;
rdfs:range syb:titles ;
rdfs:label "title id" .
syb:qty a rdf:Property ;
rdfs:domain syb:salesdetail ;
rdfs:range xsd:integer ;
rdfs:label "quantity" .
syb:discount a rdf:Property ;
rdfs:domain syb:salesdetail ;
rdfs:range xsd:decimal ;
rdfs:label "discount" .
syb:publishers a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "Publishers" ;
rdfs:comment "Sybase Pubs2 publishers table" .
syb:pub_id a rdf:Property ;
rdfs:domain syb:publishers ;
rdfs:range xsd:string ;
rdfs:label "publisher id" .
syb:pub_name a rdf:Property ;
rdfs:domain syb:publishers ;
rdfs:range xsd:string ;
rdfs:label "publisher name" .
syb:city a rdf:Property ;
rdfs:domain syb:publishers ;
rdfs:range xsd:string ;
rdfs:label "city" .
syb:state a rdf:Property ;
rdfs:domain syb:publishers ;
rdfs:range xsd:string ;
rdfs:label "state" .
syb:titleauthor a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "title author" ;
rdfs:comment "Sybase Pubs2 titleauthor table" .
syb:au_id a rdf:Property ;
rdfs:domain syb:titleauthor ;
rdfs:range syb:authors ;
rdfs:label "author id" .
syb:title_id a rdf:Property ;
rdfs:domain syb:titleauthor ;
rdfs:range syb:titles ;
rdfs:label "title id" .
syb:au_ord a rdf:Property ;
rdfs:domain syb:titleauthor ;
rdfs:range xsd:integer ;
rdfs:label "author order" .
syb:royaltyper a rdf:Property ;
rdfs:domain syb:titleauthor ;
rdfs:range xsd:integer ;
rdfs:label "royalty per book" .
syb:roysched a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "Royalty Schedule" ;
rdfs:comment "Sybase Pubs2 roysched table" .
syb:title_id a rdf:Property ;
rdfs:domain syb:roysched ;
rdfs:range syb:titles ;
rdfs:label "title id" .
syb:lorange a rdf:Property ;
rdfs:domain syb:roysched ;
rdfs:range xsd:integer ;
rdfs:label "low range" .
syb:hirange a rdf:Property ;
rdfs:domain syb:roysched ;
rdfs:range xsd:integer ;
rdfs:label "high range" .
syb:royalty a rdf:Property ;
rdfs:domain syb:roysched ;
rdfs:range xsd:integer ;
rdfs:label "royalty" .
syb:sales a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/sybasepubs2> ;
rdfs:label "Sales" ;
rdfs:comment "Sybase Pubs2 sales table" .
syb:stor_id a rdf:Property ;
rdfs:domain syb:sales ;
rdfs:range xsd:string ;
rdfs:label "store id" .
syb:ord_num a rdf:Property ;
rdfs:domain syb:sales ;
rdfs:range xsd:string ;
rdfs:label "order number" .
syb:date a rdf:Property ;
rdfs:domain syb:sales ;
rdfs:range xsd:dateTime ;
rdfs:label "date" .
', '', 'http://localhost:8890/schemas/sybasepubs2', 0);
---------------------------------------------------------------
----------- Create IRI Classes -------------
SPARQL
create iri class <http://localhost:8890/schemas/sybasepubs2/titles_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/titles/%s_%s#this"
(in title_id varchar not null, in title varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/authors_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/authors/%s#this"
(in au_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/stores_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/stores/%s#this"
(in stor_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/au_pix_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/au_pix/%s#this"
(in au_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/discounts_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/discounts/%s#this"
(in discounttype varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/salesdetail_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/salesdetail/%s_%s_%s#this"
(in stor_id varchar not null, in ord_num varchar not null, in title_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/publishers_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/publishers/%s#this"
(in pub_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/titleauthor_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/titleauthor/%s_%s#this"
(in au_id varchar not null, in title_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/roysched_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/roysched/%s#this"
(in title_id varchar not null) .
create iri class <http://localhost:8890/schemas/sybasepubs2/sales_iri>
"http://^{URIQADefaultHost}^/sybasepubs2/sales/%s_%s#this"
(in stor_id varchar not null, in ord_num varchar not null) .
;
--------------------------------------------------------------------
------------- Create Quad Store ------------------------------------
SPARQL
prefix syb: <http://localhost:8890/schemas/sybasepubs2/>
alter quad storage virtrdf:DefaultQuadStorage
from pubs2.syb.au_pix as au_pix_tbl
from pubs2.syb.authors as authors_tbl
from pubs2.syb.discounts as discounts_tbl
from pubs2.syb.publishers as publishers_tbl
from pubs2.syb.roysched as roysched_tbl
from pubs2.syb.sales as sales_tbl
from pubs2.syb.salesdetail as salesdetail_tbl
from pubs2.syb.stores as stores_tbl
from pubs2.syb.titleauthor as titleauthor_tbl
from pubs2.syb.titles as titles_tbl
{
create virtrdf:sybasepubs2 as
graph <http://localhost:8890/sybasepubs2>
{
syb:au_pix_iri (au_pix_tbl.au_id) a syb:au_pix as virtrdf:au_pix_id;
syb:au_id au_pix_tbl.au_id as virtrdf:au_pix_au_id;
syb:format_type au_pix_tbl.format_type as virtrdf:au_pix_format_type;
syb:bytesize au_pix_tbl.bytesize as virtrdf:au_pix_bytesize;
syb:pixwidth_hor au_pix_tbl.pixwidth_hor as virtrdf:au_pix_pixwidth_hor;
syb:pixwidth_vert au_pix_tbl.pixwidth_vert as virtrdf:au_pix_pixwidth_vert ;
syb:has_author syb:authors_iri(authors_tbl.au_id) where (^{authors_tbl.}^.au_id = ^{au_pix_tbl.}^.au_id) as virtrdf:au_pix_has_author .
syb:authors_iri (authors_tbl.au_id) a syb:authors as virtrdf:authors_pk ;
syb:au_id authors_tbl.au_id as virtrdf:authors_au_id;
syb:au_lname authors_tbl.au_lname as virtrdf:authors_au_lname;
syb:au_fname authors_tbl.au_fname as virtrdf:authors_au_fname;
syb:phone authors_tbl.phone as virtrdf:authors_phone;
syb:address authors_tbl.address as virtrdf:authors_address;
syb:city authors_tbl.city as virtrdf:authors_city;
syb:state authors_tbl.state as virtrdf:authors_state;
syb:country authors_tbl.country as virtrdf:authors_country;
syb:postalcode authors_tbl.postalcode as virtrdf:authors_postalcode;
syb:has_title syb:titleauthor_iri(titleauthor_tbl.au_id, titleauthor_tbl.title_id) where (^{titleauthor_tbl.}^.au_id = ^{authors_tbl.}^.au_id) as virtrdf:authors_has_title;
syb:has_pix syb:au_pix_iri(au_pix_tbl.au_id) where (^{au_pix_tbl.}^.au_id = ^{authors_tbl.}^.au_id) as virtrdf:authors_has_pix .
syb:discounts_iri (discounts_tbl.stor_id) a syb:discounts as virtrdf:discounts_pk;
syb:discounttype discounts_tbl.discounttype as virtrdf:discounts_discounttype;
syb:stor_id syb:stores_iri(stores_tbl.stor_id) where (^{stores_tbl.}^.stor_id = ^{stores_tbl.}^.stor_id) as virtrdf:discounts_stor_id;
syb:lowqty discounts_tbl.lowqty as virtrdf:discounts_lowqty;
syb:highqty discounts_tbl.highqty as virtrdf:discounts_highqty;
syb:discount discounts_tbl.discount as virtrdf:discounts_discount .
syb:publishers_iri (publishers_tbl.pub_id) a syb:publishers as virtrdf:publishers_pk;
syb:pub_id syb:titles_iri(titles_tbl.title_id, titles_tbl.pub_id) where (^{titles_tbl.}^.pub_id = ^{titles_tbl.}^.pub_id) as virtrdf:publisherss_pub_id;
syb:pub_name publishers_tbl.pub_name as virtrdf:publisherss_pub_name;
syb:city publishers_tbl.city as virtrdf:publisherss_city;
syb:state publishers_tbl.state as virtrdf:publisherss_state .
syb:roysched_iri (roysched_tbl.title_id) a syb:roysched as virtrdf:roysched_pk;
syb:title_id syb:titleauthor_iri(titleauthor_tbl.au_id, titleauthor_tbl.title_id) where (^{titleauthor_tbl.}^.title_id = ^{roysched_tbl.}^.title_id) as virtrdf:roysched_title_id;
syb:lorange roysched_tbl.lorange as virtrdf:roysched_lorange;
syb:hirange roysched_tbl.hirange as virtrdf:roysched_hirange;
syb:royalty roysched_tbl.royalty as virtrdf:roysched_royalty .
syb:sales_iri (sales_tbl.stor_id, sales_tbl.ord_num) a syb:sales as virtrdf:sales_pk;
syb:stor_id sales_tbl.stor_id as virtrdf:sales_stor_id;
syb:ord_num sales_tbl.ord_num as virtrdf:sales_ord_num;
syb:date sales_tbl.date as virtrdf:sales_date;
syb:has_salesdetail syb:salesdetail_iri(salesdetail_tbl.stor_id, salesdetail_tbl.ord_num, salesdetail_tbl.title_id) where (^{salesdetail_tbl.}^.stor_id = ^{sales_tbl.}^.stor_id and ^{salesdetail_tbl.}^.ord_num = ^{sales_tbl.}^.ord_num) as virtrdf:sales_has_salesdetail;
syb:has_stores syb:stores_iri(stores_tbl.stor_id) where (^{stores_tbl.}^.stor_id = ^{sales_tbl.}^.stor_id) as virtrdf:sales_has_stores .
syb:salesdetail_iri (salesdetail_tbl.stor_id, salesdetail_tbl.ord_num, salesdetail_tbl.title_id) a syb:salesdetail as virtrdf:salesdetail_pk;
syb:stor_id salesdetail_tbl.stor_id as virtrdf:salesdetail_stor_id;
syb:ord_num salesdetail_tbl.ord_num as virtrdf:salesdetail_ord_num;
syb:title_id salesdetail_tbl.title_id as virtrdf:salesdetail_title_id;
syb:qty salesdetail_tbl.qty as virtrdf:salesdeail_qty;
syb:discount salesdetail_tbl.discount as virtrdf:salesdetail_discount;
syb:has_title syb:titles_iri (titles_tbl.title_id, titles_tbl.pub_id) where (^{titles_tbl.}^.title_id = ^{salesdetail_tbl.}^.title_id) as virtrdf:salesdetail_has_title;
syb:has_sales syb:sales_iri(sales_tbl.stor_id, sales_tbl.ord_num) where (^{salesdetail_tbl.}^.stor_id = ^{sales_tbl.}^.stor_id and ^{salesdetail_tbl.}^.ord_num = ^{sales_tbl.}^.ord_num ) as virtrdf:salesdetail_has_sales .
syb:stores_iri (stores_tbl.stor_id) a syb:stores as virtrdf:stores_pk;
syb:stor_id stores_tbl.stor_id as virtrdf:stores_stor_id;
syb:stor_name stores_tbl.stor_name as virtrdf:stores_stor_name;
syb:stor_address stores_tbl.stor_address as virtrdf:stores_stor_address;
syb:city stores_tbl.city as virtrdf:stores_city;
syb:state stores_tbl.state as virtrdf:stores_state;
syb:country stores_tbl.country as virtrdf:stores_country;
syb:postalcode stores_tbl.postalcode as virtrdf:stores_postalcode;
syb:payterms stores_tbl.payterms as virtrdf:stores_payterms;
syb:has_sales syb:sales_iri(sales_tbl.stor_id, sales_tbl.ord_num) where (^{sales_tbl.}^.stor_id = ^{stores_tbl.}^.stor_id) as virtrdf:stores_has_sales .
syb:titleauthor_iri (titleauthor_tbl.au_id, titleauthor_tbl.title_id) a syb:titleauthor as virtrdf:titleauthor_pk;
syb:au_id titleauthor_tbl.au_id as virtrdf:titleauthor_au_id;
syb:title_id titleauthor_tbl.title_id as virtrdf:titleauthor_title_id;
syb:au_ord titleauthor_tbl.au_ord as virtrdf:titleauthor_au_ord;
syb:royaltyper titleauthor_tbl.royaltyper as virtrdf:titleauthor_royaltyper;
syb:has_author syb:authors_iri(authors_tbl.au_id) where (^{authors_tbl.}^.au_id = ^{titleauthor_tbl.}^.au_id) as virtrdf:titleauthor_has_author;
syb:has_titles syb:titles_iri(titles_tbl.title_id, titles_tbl.pub_id) where (^{titles_tbl.}^.title_id = ^{titleauthor_tbl.}^.title_id) as virtrdf:titleauthor_has_titles .
syb:titles_iri (titles_tbl.title_id, titles_tbl.pub_id) a syb:titles as virtrdf:titles_pk;
syb:title_id titles_tbl.title_id as virtrdf:titles_title_idd;
syb:title titles_tbl.title as virtrdf:titles_title;
syb:type titles_tbl.type as virtrdf:titles_type;
syb:pub_id titles_tbl.pub_id as virtrdf:titles_pub_id;
syb:price titles_tbl.price as virtrdf:titles_price;
syb:advance titles_tbl.advance as virtrdf:titles_advance;
syb:total_sales titles_tbl.total_sales as virtrdf:titles_total_sales;
syb:notes titles_tbl.notes as virtrdf:titles_notes;
syb:pubdate titles_tbl.pubdate as virtrdf:titles_pubdate;
syb:contract titles_tbl.contract as virtrdf:titles_contract;
syb:has_titleauthor syb:titleauthor_iri(titleauthor_tbl.au_id, titleauthor_tbl.title_id) where (^{titleauthor_tbl.}^.title_id = ^{titles_tbl.}^.title_id) as virtrdf:titles_has_titleauthor;
syb:has_salesdetail syb:salesdetail_iri (salesdetail_tbl.stor_id, salesdetail_tbl.ord_num, salesdetail_tbl.title_id) where (^{salesdetail_tbl.}^.title_id = ^{titles_tbl.}^.title_id) as virtrdf:titles_has_salesdetail .
} .
} .
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'sybasepubs2_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'sybasepubs2_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'sybasepubs2_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'sybasepubs2_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/sybasepubs2%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'sybasepubs2_rule_list1',
1,
vector (
'sybasepubs2_rule1',
'sybasepubs2_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/sybasepubs2');
VHOST_DEFINE (
lpath=>'/sybasepubs2',
ppath=>'/DAV/sybasepubs2/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'sybasepubs2_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'sybase_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'sybase_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'sybase_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'sybase_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/sybasepubs2%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'sybase_schemas_rule_list1',
1,
vector (
'sybase_schemas_rule1',
'sybase_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schema/sybasepubs2');
VHOST_DEFINE (
lpath=>'/schemas/sybasepubs2',
ppath=>'/DAV/schemas/sybasepubs2/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'sybase_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('hr', 'http://^{URIQADefaultHost}^/schemas/sybasepubs2', 2);
]]></programlisting>
</sect3>
<sect3 id="rdfviewsenterpr"><title>Examples</title>
<sect4 id="rdfviewsenterprtn">
<title>Virtuoso's Northwind based Demo Database (Tutorials variant) to RDF </title>
<programlisting><![CDATA[
use DB;
DB.DBA.exec_no_error('UPDATE WS.WS.SYS_DAV_RES set RES_TYPE=\'image/jpeg\' where RES_FULL_PATH like \'/DAV/VAD/demo/sql/CAT%\'')
;
DB.DBA.exec_no_error('UPDATE WS.WS.SYS_DAV_RES set RES_TYPE=\'image/jpeg\' where RES_FULL_PATH like \'/DAV/VAD/demo/sql/EMP%\'')
;
GRANT SELECT ON "Demo"."demo"."Products" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Suppliers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Shippers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Categories" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Customers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Employees" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Orders" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Order_Details" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Countries" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Provinces" TO "SPARQL";
SPARQL
prefix tut_northwind: <http://demo.openlinksw.com/schemas/tutorial/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
drop quad map graph iri("http://^{URIQADefaultHost}^/tutorial/Northwind") .
;
SPARQL
prefix tut_northwind: <http://demo.openlinksw.com/schemas/tutorial/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
drop quad map virtrdf:TutorialNorthwindDemo .
;
create function DB.DBA.TUT_NORTHWIND_ID_TO_IRI(in _prefix varchar,in _id varchar)
{
declare iri, uriqa_host any;
uriqa_host := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
iri := 'http://' || uriqa_host || '/tutorial/Northwind/' || _prefix || '/' || _id || '#this';
return sprintf ('http://%s/DAV/VAD/tutorial/rdfview/rd_v_1/RDFData/All/iid%%20(%d).rdf', uriqa_host, iri_id_num (iri_to_id (iri)));
}
;
create function DB.DBA.TUT_NORTHWIND_IRI_TO_ID(in _iri varchar)
{
declare parts any;
parts := sprintf_inverse (_iri, 'http://%s/DAV/VAD/tutorial/rdfview/rd_v_1/RDFData/All/iid (%d).rdf', 1 );
if (parts is not null)
{
declare uriqa_host, iri any;
uriqa_host := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
if (parts[0] = uriqa_host)
{
iri := id_to_iri(iri_id_from_num(parts[1]));
parts := sprintf_inverse (iri, 'http://%s/tutorial/Northwind/%s/%s#this', 1 );
if (parts[0] = uriqa_host)
{
return parts[2];
}
}
}
return NULL;
}
;
create function DB.DBA.TUT_CATEGORY_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Category', cast(_id as varchar));
}
;
create function DB.DBA.TUT_CATEGORY_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_SHIPPER_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Shipper', cast(_id as varchar));
}
;
create function DB.DBA.TUT_SHIPPER_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_SUPPLIER_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Supplier', cast(_id as varchar));
}
;
create function DB.DBA.TUT_SUPPLIER_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_PRODUCT_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Product', cast(_id as varchar));
}
;
create function DB.DBA.TUT_PRODUCT_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_CUSTOMER_IRI (in _id varchar) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Customer', _id);
}
;
create function DB.DBA.TUT_CUSTOMER_IRI_INVERSE (in _iri varchar) returns varchar
{
return DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri);
};
create function DB.DBA.TUT_EMPLOYEE_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Employee', cast(_id as varchar));
}
;
create function DB.DBA.TUT_EMPLOYEE_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_ORDER_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Order', cast(_id as varchar));
}
;
create function DB.DBA.TUT_ORDER_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_CUSTOMERCONTACT_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('CustomerContact', cast(_id as varchar));
}
;
create function DB.DBA.TUT_CUSTOMERCONTACT_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_ORDERLINE_IRI (in _id1 integer, in _id2 integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('OrderLine', sprintf('%d/%d', _id1, _id2));
}
;
create function DB.DBA.TUT_ORDERLINE_IRI_INV_1 (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_ORDERLINE_IRI_INV_2 (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_PROVINCE_IRI (in _id1 varchar, in _id2 varchar) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Province', sprintf('%s/%s', _id1, _id2));
}
;
create function DB.DBA.TUT_PROVINCE_IRI_INV_1 (in _iri varchar) returns varchar
{
return DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri);
};
create function DB.DBA.TUT_PROVINCE_IRI_INV_2 (in _iri varchar) returns varchar
{
return DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri);
};
create function DB.DBA.TUT_COUNTRY_IRI (in _id varchar) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Country', _id);
}
;
create function DB.DBA.TUT_COUNTRY_IRI_INVERSE (in _iri varchar) returns varchar
{
return DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri);
};
create function DB.DBA.TUT_FLAG_IRI (in _id varchar) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('Flag', _id);
}
;
create function DB.DBA.TUT_FLAG_IRI_INVERSE (in _iri varchar) returns varchar
{
return DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri);
};
create function DB.DBA.TUT_EMPLOYEEPHOTO_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('EmployeePhoto', cast(_id as varchar));
}
;
create function DB.DBA.TUT_EMPLOYEEPHOTO_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
create function DB.DBA.TUT_CATEGORYPHOTO_IRI (in _id integer) returns varchar
{
return TUT_NORTHWIND_ID_TO_IRI('CategoryPhoto', cast(_id as varchar));
}
;
create function DB.DBA.TUT_CATEGORYPHOTO_IRI_INVERSE (in _iri varchar) returns integer
{
return atoi(DB.DBA.TUT_NORTHWIND_IRI_TO_ID(_iri));
};
grant execute on DB.DBA.TUT_CATEGORY_IRI to "SPARQL";
grant execute on DB.DBA.TUT_CATEGORY_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_SHIPPER_IRI to "SPARQL";
grant execute on DB.DBA.TUT_SHIPPER_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_SUPPLIER_IRI to "SPARQL";
grant execute on DB.DBA.TUT_SUPPLIER_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_PRODUCT_IRI to "SPARQL";
grant execute on DB.DBA.TUT_PRODUCT_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_CUSTOMER_IRI to "SPARQL";
grant execute on DB.DBA.TUT_CUSTOMER_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_EMPLOYEE_IRI to "SPARQL";
grant execute on DB.DBA.TUT_EMPLOYEE_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_ORDER_IRI to "SPARQL";
grant execute on DB.DBA.TUT_ORDER_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_CUSTOMERCONTACT_IRI to "SPARQL";
grant execute on DB.DBA.TUT_CUSTOMERCONTACT_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_ORDERLINE_IRI to "SPARQL";
grant execute on DB.DBA.TUT_ORDERLINE_IRI_INV_1 to "SPARQL";
grant execute on DB.DBA.TUT_ORDERLINE_IRI_INV_2 to "SPARQL";
grant execute on DB.DBA.TUT_PROVINCE_IRI to "SPARQL";
grant execute on DB.DBA.TUT_PROVINCE_IRI_INV_1 to "SPARQL";
grant execute on DB.DBA.TUT_PROVINCE_IRI_INV_2 to "SPARQL";
grant execute on DB.DBA.TUT_COUNTRY_IRI to "SPARQL";
grant execute on DB.DBA.TUT_COUNTRY_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_FLAG_IRI to "SPARQL";
grant execute on DB.DBA.TUT_FLAG_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_EMPLOYEEPHOTO_IRI to "SPARQL";
grant execute on DB.DBA.TUT_EMPLOYEEPHOTO_IRI_INVERSE to "SPARQL";
grant execute on DB.DBA.TUT_CATEGORYPHOTO_IRI to "SPARQL";
grant execute on DB.DBA.TUT_CATEGORYPHOTO_IRI_INVERSE to "SPARQL";
SPARQL
prefix tut_northwind: <http://demo.openlinksw.com/schemas/tutorial/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
create iri class tut_northwind:Category "http://^{URIQADefaultHost}^/tutorial/Northwind/Category/%d#this" (in category_id integer not null) .
create iri class tut_northwind:Shipper "http://^{URIQADefaultHost}^/tutorial/Northwind/Shipper/%d#this" (in shipper_id integer not null) .
create iri class tut_northwind:Supplier "http://^{URIQADefaultHost}^/tutorial/Northwind/Supplier/%d#this" (in supplier_id integer not null) .
create iri class tut_northwind:Product "http://^{URIQADefaultHost}^/tutorial/Northwind/Product/%d#this" (in product_id integer not null) .
create iri class tut_northwind:Customer "http://^{URIQADefaultHost}^/tutorial/Northwind/Customer/%U#this" (in customer_id varchar not null) .
create iri class tut_northwind:Employee "http://^{URIQADefaultHost}^/tutorial/Northwind/Employee/%U%U%d#this" (in employee_firstname varchar not null, in employee_lastname varchar not null, in employee_id integer not null) .
create iri class tut_northwind:Order "http://^{URIQADefaultHost}^/tutorial/Northwind/Order/%d#this" (in order_id integer not null) .
create iri class tut_northwind:CustomerContact "http://^{URIQADefaultHost}^/tutorial/Northwind/CustomerContact/%U#this" (in customer_id varchar not null) .
create iri class tut_northwind:OrderLine "http://^{URIQADefaultHost}^/tutorial/Northwind/OrderLine/%d/%d#this" (in order_id integer not null, in product_id integer not null) .
create iri class tut_northwind:Province "http://^{URIQADefaultHost}^/tutorial/Northwind/Province/%U/%U#this" (in country_name varchar not null, in province_name varchar not null) .
create iri class tut_northwind:Country "http://^{URIQADefaultHost}^/tutorial/Northwind/Country/%U#this" (in country_name varchar not null) .
create iri class tut_northwind:Flag "http://^{URIQADefaultHost}^%U#this" (in flag_path varchar not null) .
create iri class tut_northwind:dbpedia_iri "http://dbpedia.org/resource/%U" (in uname varchar not null) .
create iri class tut_northwind:EmployeePhoto "http://^{URIQADefaultHost}^/DAV/VAD/demo/sql/EMP%d#this" (in emp_id varchar not null) .
create iri class tut_northwind:CategoryPhoto "http://^{URIQADefaultHost}^/DAV/VAD/demo/sql/CAT%d#this" (in category_id varchar not null) .
;
SPARQL
prefix tut_northwind: <http://demo.openlinksw.com/schemas/tutorial/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
create iri class tut_northwind:customercontact_iri using
function DB.DBA.TUT_CUSTOMERCONTACT_IRI (in customer_id varchar) returns varchar,
function DB.DBA.TUT_CUSTOMERCONTACT_IRI_INVERSE (in customer_iri varchar) returns varchar.
create iri class tut_northwind:category_iri using
function DB.DBA.TUT_CATEGORY_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_CATEGORY_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:shipper_iri using
function DB.DBA.TUT_SHIPPER_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_SHIPPER_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:supplier_iri using
function DB.DBA.TUT_SUPPLIER_IRI (in customer_id varchar) returns varchar,
function DB.DBA.TUT_SUPPLIER_IRI_INVERSE (in customer_iri varchar) returns varchar.
create iri class tut_northwind:product_iri using
function DB.DBA.TUT_PRODUCT_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_PRODUCT_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:customer_iri using
function DB.DBA.TUT_CUSTOMER_IRI (in customer_id varchar) returns varchar,
function DB.DBA.TUT_CUSTOMER_IRI_INVERSE (in customer_iri varchar) returns varchar.
create iri class tut_northwind:employee_iri using
function DB.DBA.TUT_EMPLOYEE_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_EMPLOYEE_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:order_iri using
function DB.DBA.TUT_ORDER_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_ORDER_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:orderline_iri using
function DB.DBA.TUT_ORDERLINE_IRI (in customer_id integer, in customer_id2 integer) returns varchar,
function DB.DBA.TUT_ORDERLINE_IRI_INV_1 (in customer_iri varchar) returns integer,
function DB.DBA.TUT_ORDERLINE_IRI_INV_2 (in customer_iri varchar) returns integer.
create iri class tut_northwind:province_iri using
function DB.DBA.TUT_PROVINCE_IRI (in customer_id varchar, in customer_id2 varchar) returns varchar,
function DB.DBA.TUT_PROVINCE_IRI_INV_1 (in customer_iri varchar) returns varchar,
function DB.DBA.TUT_PROVINCE_IRI_INV_2 (in customer_iri varchar) returns varchar.
create iri class tut_northwind:country_iri using
function DB.DBA.TUT_COUNTRY_IRI (in customer_id varchar) returns varchar,
function DB.DBA.TUT_COUNTRY_IRI_INVERSE (in customer_iri varchar) returns varchar.
create iri class tut_northwind:employeephoto_iri using
function DB.DBA.TUT_EMPLOYEEPHOTO_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_EMPLOYEEPHOTO_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:categoryphoto_iri using
function DB.DBA.TUT_CATEGORYPHOTO_IRI (in customer_id integer) returns varchar,
function DB.DBA.TUT_CATEGORYPHOTO_IRI_INVERSE (in customer_iri varchar) returns integer.
create iri class tut_northwind:flag_iri using
function DB.DBA.TUT_FLAG_IRI (in customer_id varchar) returns varchar,
function DB.DBA.TUT_FLAG_IRI_INVERSE (in customer_iri varchar) returns varchar.
;
SPARQL
prefix tut_northwind: <http://demo.openlinksw.com/schemas/tutorial/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
alter quad storage virtrdf:DefaultQuadStorage
from Demo.demo.Products as products
from Demo.demo.Suppliers as suppliers
from Demo.demo.Shippers as shippers
from Demo.demo.Categories as categories
from Demo.demo.Customers as customers
from Demo.demo.Employees as employees
from Demo.demo.Orders as orders
from Demo.demo.Order_Details as order_lines
from Demo.demo.Countries as countries
from Demo.demo.Provinces as provinces
where (^{suppliers.}^.Country = ^{countries.}^.Name)
where (^{customers.}^.Country = ^{countries.}^.Name)
where (^{employees.}^.Country = ^{countries.}^.Name)
where (^{orders.}^.ShipCountry = ^{countries.}^.Name)
{
create virtrdf:TutorialNorthwindDemo as graph iri ("http://^{URIQADefaultHost}^/tutorial/Northwind") option (exclusive)
{
tut_northwind:CustomerContact (customers.CustomerID)
a foaf:Person
as virtrdf:tutCustomerContact-foaf_Person .
tut_northwind:CustomerContact (customers.CustomerID)
a tut_northwind:CustomerContact
as virtrdf:tutCustomerContact-CustomerContact;
foaf:name customers.ContactName
as virtrdf:tutCustomerContact-contact_name ;
foaf:phone customers.Phone
as virtrdf:tutCustomerContact-foaf_phone ;
tut_northwind:is_contact_at tut_northwind:Customer (customers.CustomerID)
as virtrdf:tutCustomerContact-is_contact_at ;
tut_northwind:country tut_northwind:Country (customers.Country)
as virtrdf:tutCustomerContact-country ;
rdfs:isDefinedBy tut_northwind:customercontact_iri (customers.CustomerID) ;
rdfs:isDefinedBy tut_northwind:CustomerContact (customers.CustomerID) .
tut_northwind:Country (customers.Country)
tut_northwind:is_country_of
tut_northwind:CustomerContact (customers.CustomerID) as virtrdf:tutCustomerContact-is_country_of .
tut_northwind:Product (products.ProductID)
a tut_northwind:Product
as virtrdf:tutProduct-ProductID ;
tut_northwind:has_category tut_northwind:Category (products.CategoryID)
as virtrdf:tutProduct-product_has_category ;
tut_northwind:has_supplier tut_northwind:Supplier (products.SupplierID)
as virtrdf:tutProduct-product_has_supplier ;
tut_northwind:productName products.ProductName
as virtrdf:tutProduct-name_of_product ;
tut_northwind:quantityPerUnit products.QuantityPerUnit
as virtrdf:tutProduct-quantity_per_unit ;
tut_northwind:unitPrice products.UnitPrice
as virtrdf:tutProduct-unit_price ;
tut_northwind:unitsInStock products.UnitsInStock
as virtrdf:tutProduct-units_in_stock ;
tut_northwind:unitsOnOrder products.UnitsOnOrder
as virtrdf:tutProduct-units_on_order ;
tut_northwind:reorderLevel products.ReorderLevel
as virtrdf:tutProduct-reorder_level ;
tut_northwind:discontinued products.Discontinued
as virtrdf:tutProduct-discontinued ;
rdfs:isDefinedBy tut_northwind:product_iri (products.ProductID) ;
rdfs:isDefinedBy tut_northwind:Product (products.ProductID).
tut_northwind:Category (products.CategoryID)
tut_northwind:category_of tut_northwind:Product (products.ProductID) as virtrdf:tutProduct-category_of .
tut_northwind:Supplier (products.SupplierID)
tut_northwind:supplier_of tut_northwind:Product (products.ProductID) as virtrdf:tutProduct-supplier_of .
tut_northwind:Supplier (suppliers.SupplierID)
a tut_northwind:Supplier
as virtrdf:tutSupplier-SupplierID ;
tut_northwind:companyName suppliers.CompanyName
as virtrdf:tutSupplier-company_name ;
tut_northwind:contactName suppliers.ContactName
as virtrdf:tutSupplier-contact_name ;
tut_northwind:contactTitle suppliers.ContactTitle
as virtrdf:tutSupplier-contact_title ;
tut_northwind:address suppliers.Address
as virtrdf:tutSupplier-address ;
tut_northwind:city suppliers.City
as virtrdf:tutSupplier-city ;
tut_northwind:dbpedia_city tut_northwind:dbpedia_iri(suppliers.City)
as virtrdf:tutSupplier-dbpedia_city ;
tut_northwind:region suppliers.Region
as virtrdf:tutSupplier-region ;
tut_northwind:postalCode suppliers.PostalCode
as virtrdf:tutSupplier-postal_code ;
tut_northwind:country tut_northwind:Country(suppliers.Country)
as virtrdf:tutSupplier-country ;
tut_northwind:phone suppliers.Phone
as virtrdf:tutSupplier-phone ;
tut_northwind:fax suppliers.Fax
as virtrdf:tutSupplier-fax ;
tut_northwind:homePage suppliers.HomePage
as virtrdf:tutSupplier-home_page ;
rdfs:isDefinedBy tut_northwind:supplier_iri (suppliers.SupplierID) ;
rdfs:isDefinedBy tut_northwind:Supplier (suppliers.SupplierID).
tut_northwind:Country (suppliers.Country)
tut_northwind:is_country_of
tut_northwind:Supplier (suppliers.SupplierID) as virtrdf:tutSupplier-is_country_of .
tut_northwind:Category (categories.CategoryID)
a tut_northwind:Category
as virtrdf:tutCategory-CategoryID ;
tut_northwind:categoryName categories.CategoryName
as virtrdf:tutCategory-home_page ;
tut_northwind:description categories.Description
as virtrdf:tutCategory-description ;
foaf:img tut_northwind:CategoryPhoto(categories.CategoryID)
as virtrdf:tutCategory-categories.CategoryPhoto ;
rdfs:isDefinedBy tut_northwind:category_iri (categories.CategoryID) ;
rdfs:isDefinedBy tut_northwind:Category (categories.CategoryID).
tut_northwind:CategoryPhoto(categories.CategoryID)
a tut_northwind:CategoryPhoto
as virtrdf:tutCategory-categories.CategoryPhotoID ;
rdfs:isDefinedBy tut_northwind:categoryphoto_iri (categories.CategoryID) ;
rdfs:isDefinedBy tut_northwind:CategoryPhoto(categories.CategoryID).
tut_northwind:Shipper (shippers.ShipperID)
a tut_northwind:Shipper
as virtrdf:tutShipper-ShipperID ;
tut_northwind:companyName shippers.CompanyName
as virtrdf:tutShipper-company_name ;
tut_northwind:phone shippers.Phone
as virtrdf:tutShipper-phone ;
rdfs:isDefinedBy tut_northwind:shipper_iri (shippers.ShipperID) ;
rdfs:isDefinedBy tut_northwind:Shipper (shippers.ShipperID).
tut_northwind:Customer (customers.CustomerID)
a tut_northwind:Customer
as virtrdf:tutCustomer-CustomerID2 ;
a foaf:Organization
as virtrdf:tutCustomer-CustomerID ;
foaf:name customers.CompanyName
as virtrdf:tutCustomer-foaf_name ;
tut_northwind:companyName customers.CompanyName
as virtrdf:tutCustomer-company_name ;
tut_northwind:has_contact tut_northwind:CustomerContact (customers.CustomerID)
as virtrdf:tutCustomer-contact ;
tut_northwind:country tut_northwind:Country (customers.Country)
as virtrdf:tutCustomer-country ;
tut_northwind:contactName customers.ContactName
as virtrdf:tutCustomer-contact_name ;
tut_northwind:contactTitle customers.ContactTitle
as virtrdf:tutCustomer-contact_title ;
tut_northwind:address customers.Address
as virtrdf:tutCustomer-address ;
tut_northwind:city customers.City
as virtrdf:tutCustomer-city ;
tut_northwind:dbpedia_city tut_northwind:dbpedia_iri(customers.City)
as virtrdf:tutCustomer-dbpedia_city ;
tut_northwind:region customers.Region
as virtrdf:tutCustomer-region ;
tut_northwind:PostalCode customers.PostalCode
as virtrdf:tutCustomer-postal_code ;
foaf:phone customers.Phone
as virtrdf:tutCustomer-foaf_phone ;
tut_northwind:phone customers.Phone
as virtrdf:tutCustomer-phone ;
tut_northwind:fax customers.Fax
as virtrdf:tutCustomer-fax ;
rdfs:isDefinedBy tut_northwind:customer_iri (customers.CustomerID) ;
rdfs:isDefinedBy tut_northwind:Customer (customers.CustomerID).
tut_northwind:Country (customers.Country)
tut_northwind:is_country_of
tut_northwind:Customer (customers.CustomerID) as virtrdf:tutCustomer-is_country_of .
tut_northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID)
a tut_northwind:Employee
as virtrdf:tutEmployee-EmployeeID2 ;
a foaf:Person
as virtrdf:tutEmployee-EmployeeID ;
foaf:surname employees.LastName
as virtrdf:tutEmployee-foaf_last_name ;
tut_northwind:lastName employees.LastName
as virtrdf:tutEmployee-last_name ;
foaf:firstName employees.FirstName
as virtrdf:tutEmployee-foaf_first_name ;
tut_northwind:firstName employees.FirstName
as virtrdf:tutEmployee-first_name ;
foaf:title employees.Title
as virtrdf:tutEmployee-title ;
tut_northwind:titleOfCourtesy employees.TitleOfCourtesy
as virtrdf:tutEmployee-title_of_courtesy ;
foaf:birthday employees.BirthDate
as virtrdf:tutEmployee-foaf_birth_date ;
tut_northwind:birthday employees.BirthDate
as virtrdf:tutEmployee-birth_date ;
tut_northwind:hireDate employees.HireDate
as virtrdf:tutEmployee-hire_date ;
tut_northwind:address employees.Address
as virtrdf:tutEmployee-address ;
tut_northwind:city employees.City
as virtrdf:tutEmployee-city ;
tut_northwind:dbpedia_city tut_northwind:dbpedia_iri(employees.City)
as virtrdf:tutEmployee-dbpedia_city ;
tut_northwind:region employees.Region
as virtrdf:tutEmployee-region ;
tut_northwind:postalCode employees.PostalCode
as virtrdf:tutEmployee-postal_code ;
tut_northwind:country tut_northwind:Country (employees.Country)
as virtrdf:tutEmployee-country ;
foaf:phone employees.HomePhone
as virtrdf:tutEmployee-home_phone ;
tut_northwind:extension employees.Extension
as virtrdf:tutEmployee-extension ;
tut_northwind:notes employees.Notes
as virtrdf:tutEmployee-notes ;
tut_northwind:reportsTo tut_northwind:Employee(employees.FirstName, employees.LastName, employees.ReportsTo) where (^{employees.}^.ReportsTo = ^{employees.}^.EmployeeID)
as virtrdf:tutEmployee-reports_to ;
foaf:img tut_northwind:EmployeePhoto(employees.EmployeeID)
as virtrdf:tutEmployee-employees.EmployeePhoto ;
rdfs:isDefinedBy tut_northwind:employee_iri (employees.EmployeeID) ;
rdfs:isDefinedBy tut_northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID).
tut_northwind:EmployeePhoto(employees.EmployeeID)
a tut_northwind:EmployeePhoto
as virtrdf:tut_Employee-employees.EmployeePhotoId ;
rdfs:isDefinedBy tut_northwind:employeephoto_iri (employees.EmployeeID) ;
rdfs:isDefinedBy tut_northwind:EmployeePhoto (employees.EmployeeID).
tut_northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID)
tut_northwind:is_salesrep_of
tut_northwind:Order (orders.OrderID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID) as virtrdf:tutOrder-is_salesrep_of .
tut_northwind:Country (employees.Country)
tut_northwind:is_country_of
tut_northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID) as virtrdf:tutEmployee-is_country_of .
tut_northwind:Order (orders.OrderID)
a tut_northwind:Order
as virtrdf:tutOrder-Order ;
tut_northwind:has_customer tut_northwind:Customer (orders.CustomerID)
as virtrdf:tutOrder-order_has_customer ;
tut_northwind:has_salesrep tut_northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID)
as virtrdf:tutCustomer-has_salesrep ;
tut_northwind:has_employee tut_northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID)
as virtrdf:tutOrder-order_has_employee ;
tut_northwind:orderDate orders.OrderDate
as virtrdf:tutOrder-order_date ;
tut_northwind:requiredDate orders.RequiredDate
as virtrdf:tutOrder-required_date ;
tut_northwind:shippedDate orders.ShippedDate
as virtrdf:tutOrder-shipped_date ;
tut_northwind:order_ship_via tut_northwind:Shipper (orders.ShipVia)
as virtrdf:tutOrder-order_ship_via ;
tut_northwind:freight orders.Freight
as virtrdf:tutOrder-freight ;
tut_northwind:shipName orders.ShipName
as virtrdf:tutOrder-ship_name ;
tut_northwind:shipAddress orders.ShipAddress
as virtrdf:tutOrder-ship_address ;
tut_northwind:shipCity orders.ShipCity
as virtrdf:tutOrder-ship_city ;
tut_northwind:dbpedia_shipCity tut_northwind:dbpedia_iri(orders.ShipCity)
as virtrdf:tutOrder-ship_dbpedia_city ;
tut_northwind:shipRegion orders.ShipRegion
as virtrdf:tutOrder-ship_region ;
tut_northwind:shipPostal_code orders.ShipPostalCode
as virtrdf:tutOrder-ship_postal_code ;
tut_northwind:shipCountry tut_northwind:Country(orders.ShipCountry)
as virtrdf:tutship_country ;
rdfs:isDefinedBy tut_northwind:order_iri (orders.OrderID) ;
rdfs:isDefinedBy tut_northwind:Order (orders.OrderID).
tut_northwind:Country (orders.ShipCountry)
tut_northwind:is_ship_country_of
tut_northwind:Order (orders.OrderID) as virtrdf:tutOrder-is_country_of .
tut_northwind:Customer (orders.CustomerID)
tut_northwind:has_order tut_northwind:Order (orders.OrderID) as virtrdf:tutOrder-has_order .
tut_northwind:Shipper (orders.ShipVia)
tut_northwind:ship_order tut_northwind:Order (orders.OrderID) as virtrdf:tutOrder-ship_order .
tut_northwind:OrderLine (order_lines.OrderID, order_lines.ProductID)
a tut_northwind:OrderLine
as virtrdf:tutOrderLine-OrderLines ;
tut_northwind:has_order_id tut_northwind:Order (order_lines.OrderID)
as virtrdf:tutorder_lines_has_order_id ;
tut_northwind:has_product_id tut_northwind:Product (order_lines.ProductID)
as virtrdf:tutorder_lines_has_product_id ;
tut_northwind:unitPrice order_lines.UnitPrice
as virtrdf:tutOrderLine-unit_price ;
tut_northwind:quantity order_lines.Quantity
as virtrdf:tutOrderLine-quantity ;
tut_northwind:discount order_lines.Discount
as virtrdf:tutOrderLine-discount ;
rdfs:isDefinedBy tut_northwind:orderline_iri (order_lines.OrderID, order_lines.ProductID) ;
rdfs:isDefinedBy tut_northwind:OrderLine (order_lines.OrderID, order_lines.ProductID).
tut_northwind:Order (orders.OrderID)
tut_northwind:is_order_of
tut_northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) where (^{orders.}^.OrderID = ^{order_lines.}^.OrderID) as virtrdf:tutOrder-is_order_of .
tut_northwind:Product (products.ProductID)
tut_northwind:is_product_of
tut_northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) where (^{products.}^.ProductID = ^{order_lines.}^.ProductID) as virtrdf:tutProduct-is_product_of .
tut_northwind:Country (countries.Name)
a tut_northwind:Country
as virtrdf:tutCountry-Type2 ;
a wgs:SpatialThing
as virtrdf:tutCountry-Type ;
owl:sameAs tut_northwind:dbpedia_iri (countries.Name) ;
tut_northwind:name countries.Name
as virtrdf:tutCountry-Name ;
tut_northwind:code countries.Code
as virtrdf:tutCountry-Code ;
tut_northwind:smallFlagDAVResourceName countries.SmallFlagDAVResourceName
as virtrdf:tutCountry-SmallFlagDAVResourceName ;
tut_northwind:largeFlagDAVResourceName countries.LargeFlagDAVResourceName
as virtrdf:tutCountry-LargeFlagDAVResourceName ;
tut_northwind:smallFlagDAVResourceURI tut_northwind:Flag(countries.SmallFlagDAVResourceURI)
as virtrdf:tutCountry-SmallFlagDAVResourceURI ;
tut_northwind:largeFlagDAVResourceURI tut_northwind:Flag(countries.LargeFlagDAVResourceURI)
as virtrdf:tutCountry-LargeFlagDAVResourceURI ;
wgs:lat countries.Lat
as virtrdf:tutCountry-Lat ;
wgs:long countries.Lng
as virtrdf:tutCountry-Lng ;
rdfs:isDefinedBy tut_northwind:country_iri (countries.Name) ;
rdfs:isDefinedBy tut_northwind:Country (countries.Name).
tut_northwind:Country (countries.Name)
tut_northwind:has_province
tut_northwind:Province (provinces.CountryCode, provinces.Province) where (^{provinces.}^.CountryCode = ^{countries.}^.Code) as virtrdf:tutCountry-has_province .
tut_northwind:Province (provinces.CountryCode, provinces.Province)
a tut_northwind:Province
as virtrdf:tutProvince-Provinces ;
tut_northwind:has_country_code provinces.CountryCode
as virtrdf:tuthas_country_code ;
tut_northwind:provinceName provinces.Province
as virtrdf:tutProvince-ProvinceName ;
rdfs:isDefinedBy tut_northwind:province_iri (provinces.CountryCode, provinces.Province) ;
rdfs:isDefinedBy tut_northwind:Province (provinces.CountryCode, provinces.Province).
tut_northwind:Province (provinces.CountryCode, provinces.Province)
tut_northwind:is_province_of
tut_northwind:Country (countries.Name) where (^{countries.}^.Code = ^{provinces.}^.CountryCode) as virtrdf:tutProvince-country_of .
} .
} .
;
DELETE FROM db.dba.url_rewrite_rule_list where urrl_list like 'tut_nw%';
DELETE FROM db.dba.url_rewrite_rule where urr_rule like 'tut_nw%';
create procedure DB.DBA.install_run ()
{
declare file_text, uriqa varchar;
uriqa := registry_get('URIQADefaultHost');
file_text := (SELECT blob_to_string (RES_CONTENT) FROM WS.WS.SYS_DAV_RES where RES_FULL_PATH='/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.isparql');
file_text := replace(file_text, 'URIQA_MACRO', concat('http://', uriqa, '/tutorial/Northwind'));
update WS.WS.SYS_DAV_RES set RES_CONTENT=file_text where RES_FULL_PATH='/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.isparql';
}
;
DB.DBA.install_run()
;
drop procedure DB.DBA.install_run
;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tut_nw_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/tutorial/Northwind%%3E+WHERE+{+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tut_nw_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/rdfbrowser/index.html?uri=http%%3A//^{URIQADefaultHost}^%U%%23this',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'tut_nw_rule3',
1,
'(/[^#]*)/\x24',
vector('path'),
1,
'%s',
vector('path'),
null,
null,
0,
null
);
create procedure DB.DBA.REMOVE_TUT_DEMO_RDF_DET()
{
declare colid int;
colid := DAV_SEARCH_ID('/DAV/VAD/tutorial/rdfview/rd_v_1/', 'C');
if (colid < 0)
return;
update WS.WS.SYS_DAV_COL set COL_DET=null where COL_ID = colid;
}
;
DB.DBA.REMOVE_TUT_DEMO_RDF_DET();
drop procedure DB.DBA.REMOVE_TUT_DEMO_RDF_DET;
create procedure DB.DBA.TUT_NORTHWIND_MAKE_RDF_DET()
{
declare uriqa_str varchar;
uriqa_str := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
uriqa_str := 'http://' || uriqa_str || '/tutorial/Northwind';
DB.DBA."RDFData_MAKE_DET_COL" ('/DAV/VAD/tutorial/rdfview/rd_v_1/RDFData/', uriqa_str, NULL);
VHOST_REMOVE (lpath=>'/tutorial/Northwind/data/rdf');
DB.DBA.VHOST_DEFINE (lpath=>'/tutorial/Northwind/data/rdf', ppath=>'/DAV/VAD/tutorial/rdfview/rd_v_1/RDFData/All/', is_dav=>1, vsp_user=>'dba');
}
;
DB.DBA.TUT_NORTHWIND_MAKE_RDF_DET();
drop procedure DB.DBA.TUT_NORTHWIND_MAKE_RDF_DET;
-- procedure to convert path to DET resource name
create procedure DB.DBA.TUT_NORTHWIND_DET_REF (in par varchar, in fmt varchar, in val varchar)
{
declare res, iri any;
declare uriqa_str varchar;
uriqa_str := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
uriqa_str := 'http://' || uriqa_str || '/tutorial/Northwind';
iri := uriqa_str || val;
res := sprintf ('iid (%d).rdf', iri_id_num (iri_to_id (iri)));
return sprintf (fmt, res);
}
;
DB.DBA.URLREWRITE_CREATE_REGEX_RULE ('tut_nw_rdf', 1,
'/tutorial/Northwind/(.*)', vector('path'), 1,
'/tutorial/Northwind/data/rdf/%U', vector('path'),
'DB.DBA.TUT_NORTHWIND_DET_REF',
'application/rdf.xml',
2,
303);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'tut_nw_rule_list1',
1,
vector (
'tut_nw_rule1',
'tut_nw_rule2',
'tut_nw_rule3',
'tut_nw_rdf'
));
VHOST_REMOVE (lpath=>'/tutorial/Northwind');
DB.DBA.VHOST_DEFINE (lpath=>'/tutorial/Northwind', ppath=>'/DAV/VAD/tutorial/rdfview/rd_v_1/', vsp_user=>'dba', is_dav=>1, def_page=>'sfront.vspx',
is_brws=>0, opts=>vector ('url_rewrite', 'tut_nw_rule_list1'));
create procedure DB.DBA.LOAD_TUTNW_ONTOLOGY_FROM_DAV()
{
declare content, urihost varchar;
whenever not found goto endpoint;
SELECT cast (RES_CONTENT as varchar) into content FROM WS.WS.SYS_DAV_RES where RES_FULL_PATH = '/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.owl';
if (content is null or content = '')
goto endpoint;
DB.DBA.RDF_LOAD_RDFXML (content, 'http://demo.openlinksw.com/schemas/tutorial/northwind#', 'http://demo.openlinksw.com/schemas/TutorialNorthwindOntology/1.0/');
if (urihost = 'demo.openlinksw.com')
{
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/tutorial/northwind#');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/tutorial/northwind#', ppath=>'/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/tutorial/northwind');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/tutorial/northwind', ppath=>'/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
}
endpoint:
;
}
;
DB.DBA.LOAD_TUTNW_ONTOLOGY_FROM_DAV()
;
drop procedure DB.DBA.LOAD_TUTNW_ONTOLOGY_FROM_DAV
;
create procedure DB.DBA.LOAD_TUTNW_ONTOLOGY_FROM_DAV2()
{
declare urihost varchar;
sparql base <http://demo.openlinksw.com/schemas/tutorial/northwind#> load bif:concat ("http://", bif:registry_get("URIQADefaultHost"), "/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.owl")
into graph <http://demo.openlinksw.com/schemas/TutorialNorthwindOntology/1.0/>;
urihost := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
if (urihost = 'demo.openlinksw.com')
{
DB.DBA.VHOST_REMOVE (lpath=>'/tutorial/northwind#');
DB.DBA.VHOST_DEFINE (lpath=>'/tutorial/northwind#', ppath=>'/DAV/VAD/tutorial/rdfview/rd_v_1/rd_v_1.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
}
}
;
--DB.DBA.LOAD_TUTNW_ONTOLOGY_FROM_DAV2();
drop procedure DB.DBA.LOAD_TUTNW_ONTOLOGY_FROM_DAV2
;
DB.DBA.XML_SET_NS_DECL ('tut_northwind', 'http://demo.openlinksw.com/schemas/tutorial/northwind#', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterprsn">
<title>SQL Server's Northwind Demo Database</title>
<programlisting><![CDATA[
use DB;
DB.DBA.exec_stmt ('UPDATE WS.WS.SYS_DAV_RES set RES_TYPE=\'image/jpeg\' where RES_FULL_PATH like \'/DAV/VAD/demo/sql/CAT%\'', 0)
;
DB.DBA.exec_stmt ('UPDATE WS.WS.SYS_DAV_RES set RES_TYPE=\'image/jpeg\' where RES_FULL_PATH like \'/DAV/VAD/demo/sql/EMP%\'', 0)
;
GRANT SELECT ON "Demo"."demo"."Products" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Suppliers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Shippers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Categories" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Customers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Employees" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Orders" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Order_Details" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Countries" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Provinces" TO "SPARQL";
SPARQL drop quad map graph iri("http://^{URIQADefaultHost}^/Northwind") .
;
SPARQL drop quad map virtrdf:NorthwindDemo .
;
SPARQL
prefix northwind: <http://demo.openlinksw.com/schemas/northwind#>
drop iri class northwind:Category .
drop iri class northwind:CategoryDoc .
drop iri class northwind:Shipper .
drop iri class northwind:ShipperDoc .
drop iri class northwind:Supplier .
drop iri class northwind:SupplierDoc .
drop iri class northwind:Product .
drop iri class northwind:ProductDoc .
drop iri class northwind:Customer .
drop iri class northwind:CustomerDoc .
drop iri class northwind:Employee .
drop iri class northwind:EmployeeDoc .
drop iri class northwind:Order .
drop iri class northwind:OrderDoc .
drop iri class northwind:CustomerContact .
drop iri class northwind:CustomerContactDoc .
drop iri class northwind:OrderLine .
drop iri class northwind:OrderLineDoc .
drop iri class northwind:Province .
drop iri class northwind:ProvinceDoc .
drop iri class northwind:Country .
drop iri class northwind:CountryDoc .
drop iri class northwind:Flag .
drop iri class northwind:FlagDoc .
drop iri class northwind:dbpedia_iri2 .
drop iri class northwind:EmployeePhoto .
drop iri class northwind:CategoryPhoto .
drop iri class northwind:category_iri .
drop iri class northwind:categorydoc_iri .
drop iri class northwind:shipper_iri .
drop iri class northwind:shipperdoc_iri .
drop iri class northwind:supplier_iri .
drop iri class northwind:supplierdoc_iri .
drop iri class northwind:product_iri .
drop iri class northwind:productdoc_iri .
drop iri class northwind:customer_iri .
drop iri class northwind:customerdoc_iri .
drop iri class northwind:employee_iri .
drop iri class northwind:employeedoc_iri .
drop iri class northwind:order_iri .
drop iri class northwind:orderdoc_iri .
drop iri class northwind:customercontact_iri .
drop iri class northwind:customercontactdoc_iri .
drop iri class northwind:orderline_iri .
drop iri class northwind:orderlinedoc_iri .
drop iri class northwind:province_iri .
drop iri class northwind:provincedoc_iri .
drop iri class northwind:country_iri .
drop iri class northwind:countrydoc_iri .
drop iri class northwind:employeephoto_iri .
drop iri class northwind:categoryphoto_iri .
drop iri class northwind:flag_iri .
drop iri class northwind:flagdoc_iri .
;
SPARQL
prefix northwind: <http://demo.openlinksw.com/schemas/northwind#>
create iri class northwind:Category "http://^{URIQADefaultHost}^/Northwind/Category/%d#this" (in category_id integer not null) .
create iri class northwind:CategoryDoc "http://^{URIQADefaultHost}^/Northwind/Category/%d" (in category_id integer not null) .
create iri class northwind:Shipper "http://^{URIQADefaultHost}^/Northwind/Shipper/%d#this" (in shipper_id integer not null) .
create iri class northwind:ShipperDoc "http://^{URIQADefaultHost}^/Northwind/Shipper/%d" (in shipper_id integer not null) .
create iri class northwind:Supplier "http://^{URIQADefaultHost}^/Northwind/Supplier/%d#this" (in supplier_id integer not null) .
create iri class northwind:SupplierDoc "http://^{URIQADefaultHost}^/Northwind/Supplier/%d" (in supplier_id integer not null) .
create iri class northwind:Product "http://^{URIQADefaultHost}^/Northwind/Product/%d#this" (in product_id integer not null) .
create iri class northwind:ProductDoc "http://^{URIQADefaultHost}^/Northwind/Product/%d" (in product_id integer not null) .
create iri class northwind:Customer "http://^{URIQADefaultHost}^/Northwind/Customer/%U#this" (in customer_id varchar not null) .
create iri class northwind:CustomerDoc "http://^{URIQADefaultHost}^/Northwind/Customer/%U" (in customer_id varchar not null) .
create iri class northwind:Employee "http://^{URIQADefaultHost}^/Northwind/Employee/%U_%U_%d#this" (in employee_firstname varchar not null, in employee_lastname varchar not null, in employee_id integer not null) .
create iri class northwind:EmployeeDoc "http://^{URIQADefaultHost}^/Northwind/Employee/%U_%U_%d" (in employee_firstname varchar not null, in employee_lastname varchar not null, in employee_id integer not null) .
create iri class northwind:Order "http://^{URIQADefaultHost}^/Northwind/Order/%d#this" (in order_id integer not null) .
create iri class northwind:OrderDoc "http://^{URIQADefaultHost}^/Northwind/Order/%d" (in order_id integer not null) .
create iri class northwind:CustomerContact "http://^{URIQADefaultHost}^/Northwind/CustomerContact/%U#this" (in customer_id varchar not null) .
create iri class northwind:CustomerContactDoc "http://^{URIQADefaultHost}^/Northwind/CustomerContact/%U" (in customer_id varchar not null) .
create iri class northwind:OrderLine "http://^{URIQADefaultHost}^/Northwind/OrderLine/%d/%d#this" (in order_id integer not null, in product_id integer not null) .
create iri class northwind:OrderLineDoc "http://^{URIQADefaultHost}^/Northwind/OrderLine/%d/%d" (in order_id integer not null, in product_id integer not null) .
create iri class northwind:Province "http://^{URIQADefaultHost}^/Northwind/Province/%U/%U#this" (in country_name varchar not null, in province_name varchar not null) .
create iri class northwind:ProvinceDoc "http://^{URIQADefaultHost}^/Northwind/Province/%U/%U" (in country_name varchar not null, in province_name varchar not null) .
create iri class northwind:Country "http://^{URIQADefaultHost}^/Northwind/Country/%U#this" (in country_name varchar not null) .
create iri class northwind:CountryDoc "http://^{URIQADefaultHost}^/Northwind/Country/%U" (in country_name varchar not null) .
create iri class northwind:Flag "http://^{URIQADefaultHost}^%U#this" (in flag_path varchar not null) .
create iri class northwind:FlagDoc "http://^{URIQADefaultHost}^%U" (in flag_path varchar not null) .
create iri class northwind:dbpedia_iri2 "http://dbpedia.org/resource/%U" (in uname varchar not null) .
create iri class northwind:EmployeePhoto "http://^{URIQADefaultHost}^/DAV/VAD/demo/sql/EMP%d#this" (in emp_id varchar not null) .
create iri class northwind:CategoryPhoto "http://^{URIQADefaultHost}^/DAV/VAD/demo/sql/CAT%d#this" (in category_id varchar not null) .
create iri class northwind:Phone "tel:%s" (in phone_number varchar) .
create iri class northwind:Fax "fax:%s" (in fax_number varchar) .
;
SPARQL
prefix northwind: <http://demo.openlinksw.com/schemas/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
alter quad storage virtrdf:DefaultQuadStorage
FROM Demo.demo.Products as products
FROM Demo.demo.Suppliers as suppliers
FROM Demo.demo.Shippers as shippers
FROM Demo.demo.Categories as categories
FROM Demo.demo.Customers as customers
FROM Demo.demo.Employees as employees
FROM Demo.demo.Orders as orders
FROM Demo.demo.Order_Details as order_lines
FROM Demo.demo.Countries as countries
FROM Demo.demo.Provinces as provinces
where (^{suppliers.}^.Country = ^{countries.}^.Name)
where (^{customers.}^.Country = ^{countries.}^.Name)
where (^{employees.}^.Country = ^{countries.}^.Name)
where (^{orders.}^.ShipCountry = ^{countries.}^.Name)
{
create virtrdf:NorthwindDemo as graph iri ("http://^{URIQADefaultHost}^/Northwind") option (exclusive)
{
northwind:CustomerContact (customers.CustomerID)
a foaf:Person
as virtrdf:CustomerContact-foaf_Person .
northwind:CustomerContact (customers.CustomerID)
a northwind:CustomerContact
as virtrdf:CustomerContact-CustomerContact;
foaf:name customers.ContactName
as virtrdf:CustomerContact-contact_name ;
foaf:phone northwind:Phone (customers.Phone)
as virtrdf:CustomerContact-foaf_phone ;
northwind:is_contact_at northwind:Customer (customers.CustomerID)
as virtrdf:CustomerContact-is_contact_at ;
northwind:country northwind:Country (customers.Country)
as virtrdf:CustomerContact-country ;
rdfs:isDefinedBy northwind: .
northwind:CustomerContactDoc (customers.CustomerID)
a northwind:CustomerContactDoc
as virtrdf:CustomerContactDoc-CustomerID ;
a foaf:Document
as virtrdf:CustomerContactDoc-foaf_DocCustomerID ;
foaf:primaryTopic northwind:CustomerContact (customers.CustomerID)
as virtrdf:CustomerContactDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Country (customers.Country)
northwind:is_country_of
northwind:CustomerContact (customers.CustomerID) as virtrdf:CustomerContact-is_country_of .
northwind:Product (products.ProductID)
a northwind:Product
as virtrdf:Product-ProductID ;
northwind:has_category northwind:Category (products.CategoryID)
as virtrdf:Product-product_has_category ;
northwind:has_supplier northwind:Supplier (products.SupplierID)
as virtrdf:Product-product_has_supplier ;
northwind:productName products.ProductName
as virtrdf:Product-name_of_product ;
northwind:quantityPerUnit products.QuantityPerUnit
as virtrdf:Product-quantity_per_unit ;
northwind:unitPrice products.UnitPrice
as virtrdf:Product-unit_price ;
northwind:unitsInStock products.UnitsInStock
as virtrdf:Product-units_in_stock ;
northwind:unitsOnOrder products.UnitsOnOrder
as virtrdf:Product-units_on_order ;
northwind:reorderLevel products.ReorderLevel
as virtrdf:Product-reorder_level ;
northwind:discontinued products.Discontinued
as virtrdf:Product-discontinued ;
rdfs:isDefinedBy northwind: .
northwind:ProductDoc (products.ProductID)
a northwind:ProductDoc
as virtrdf:ProductDoc-ProductID ;
a foaf:Document
as virtrdf:ProductDoc-foaf_DocProductID ;
foaf:primaryTopic northwind:Product (products.ProductID)
as virtrdf:ProductDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Category (products.CategoryID)
northwind:category_of northwind:Product (products.ProductID) as virtrdf:Product-category_of .
northwind:Supplier (products.SupplierID)
northwind:supplier_of northwind:Product (products.ProductID) as virtrdf:Product-supplier_of .
northwind:Supplier (suppliers.SupplierID)
a northwind:Supplier
as virtrdf:Supplier-SupplierID ;
northwind:companyName suppliers.CompanyName
as virtrdf:Supplier-company_name ;
northwind:contactName suppliers.ContactName
as virtrdf:Supplier-contact_name ;
northwind:contactTitle suppliers.ContactTitle
as virtrdf:Supplier-contact_title ;
northwind:address suppliers.Address
as virtrdf:Supplier-address ;
northwind:city northwind:dbpedia_iri2(suppliers.City)
as virtrdf:Supplier-dbpediacity ;
northwind:region suppliers.Region
as virtrdf:Supplier-region ;
northwind:postalCode suppliers.PostalCode
as virtrdf:Supplier-postal_code ;
northwind:country northwind:Country(suppliers.Country)
as virtrdf:Supplier-country ;
northwind:phone northwind:Phone (suppliers.Phone)
as virtrdf:Supplier-phone ;
northwind:fax northwind:Fax (suppliers.Fax)
as virtrdf:Supplier-fax ;
northwind:homePage suppliers.HomePage
as virtrdf:Supplier-home_page ;
rdfs:isDefinedBy northwind: .
northwind:SupplierDoc (suppliers.SupplierID)
a northwind:SupplierDoc
as virtrdf:SupplierDoc-SupplierID ;
a foaf:Document
as virtrdf:SupplierDoc-foaf_DocSupplierID ;
foaf:primaryTopic northwind:Supplier (suppliers.SupplierID)
as virtrdf:SupplierDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Country (suppliers.Country)
northwind:is_country_of
northwind:Supplier (suppliers.SupplierID) as virtrdf:Supplier-is_country_of .
northwind:Category (categories.CategoryID)
a northwind:Category
as virtrdf:Category-CategoryID ;
northwind:categoryName categories.CategoryName
as virtrdf:Category-home_page ;
northwind:description categories.Description
as virtrdf:Category-description ;
foaf:img northwind:CategoryPhoto(categories.CategoryID)
as virtrdf:Category-categories.CategoryPhoto ;
rdfs:isDefinedBy northwind: .
northwind:CategoryDoc (categories.CategoryID)
a northwind:CategoryDoc
as virtrdf:CategoryDoc-CategoryID ;
a foaf:Document
as virtrdf:CategoryDoc-foaf_DocCategoryID ;
foaf:primaryTopic northwind:Category (categories.CategoryID)
as virtrdf:CategoryDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:CategoryPhoto(categories.CategoryID)
a northwind:CategoryPhoto
as virtrdf:Category-categories.CategoryPhotoID ;
rdfs:isDefinedBy northwind: .
northwind:Shipper (shippers.ShipperID)
a northwind:Shipper
as virtrdf:Shipper-ShipperID ;
northwind:companyName shippers.CompanyName
as virtrdf:Shipper-company_name ;
northwind:phone northwind:Phone (shippers.Phone)
as virtrdf:Shipper-phone ;
rdfs:isDefinedBy northwind: .
northwind:ShipperDoc (shippers.ShipperID)
a northwind:ShipperDoc
as virtrdf:ShipperDoc-ShipperID ;
a foaf:Document
as virtrdf:ShipperDoc-foaf_DocShipperID ;
foaf:primaryTopic northwind:Shipper (shippers.ShipperID)
as virtrdf:ShipperDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Customer (customers.CustomerID)
a northwind:Customer
as virtrdf:Customer-CustomerID2 ;
a foaf:Organization
as virtrdf:Customer-CustomerID ;
foaf:name customers.CompanyName
as virtrdf:Customer-foaf_name ;
northwind:companyName customers.CompanyName
as virtrdf:Customer-company_name ;
northwind:has_contact northwind:CustomerContact (customers.CustomerID)
as virtrdf:Customer-contact ;
northwind:country northwind:Country (customers.Country)
as virtrdf:Customer-country ;
northwind:contactName customers.ContactName
as virtrdf:Customer-contact_name ;
northwind:contactTitle customers.ContactTitle
as virtrdf:Customer-contact_title ;
northwind:address customers.Address
as virtrdf:Customer-address ;
northwind:city northwind:dbpedia_iri2(customers.City)
as virtrdf:Customer-dbpediacity ;
northwind:region customers.Region
as virtrdf:Customer-region ;
northwind:PostalCode customers.PostalCode
as virtrdf:Customer-postal_code ;
foaf:phone northwind:Phone (customers.Phone)
as virtrdf:Customer-foaf_phone ;
northwind:phone northwind:Phone (customers.Phone)
as virtrdf:Customer-phone ;
northwind:fax northwind:Fax (customers.Fax)
as virtrdf:Customer-fax ;
rdfs:isDefinedBy northwind: .
northwind:CustomerDoc (customers.CustomerID)
a northwind:CustomerDoc
as virtrdf:CustomerDoc-CustomerID2 ;
a foaf:Document
as virtrdf:CustomerDoc-CustomerID3 ;
foaf:primaryTopic northwind:Customer (customers.CustomerID)
as virtrdf:CustomerDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Country (customers.Country)
northwind:is_country_of
northwind:Customer (customers.CustomerID) as virtrdf:Customer-is_country_of .
northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID)
a northwind:Employee
as virtrdf:Employee-EmployeeID2 ;
a foaf:Person
as virtrdf:Employee-EmployeeID ;
foaf:surname employees.LastName
as virtrdf:Employee-foaf_last_name ;
northwind:lastName employees.LastName
as virtrdf:Employee-last_name ;
foaf:firstName employees.FirstName
as virtrdf:Employee-foaf_first_name ;
northwind:firstName employees.FirstName
as virtrdf:Employee-first_name ;
foaf:title employees.Title
as virtrdf:Employee-title ;
northwind:titleOfCourtesy employees.TitleOfCourtesy
as virtrdf:Employee-title_of_courtesy ;
foaf:birthday employees.BirthDate
as virtrdf:Employee-foaf_birth_date ;
northwind:birthday employees.BirthDate
as virtrdf:Employee-birth_date ;
northwind:hireDate employees.HireDate
as virtrdf:Employee-hire_date ;
northwind:address employees.Address
as virtrdf:Employee-address ;
northwind:city northwind:dbpedia_iri2(employees.City)
as virtrdf:Employee-dbpediacity ;
northwind:region employees.Region
as virtrdf:Employee-region ;
northwind:postalCode employees.PostalCode
as virtrdf:Employee-postal_code ;
northwind:country northwind:Country(employees.Country)
as virtrdf:Employee-country ;
foaf:phone employees.HomePhone
as virtrdf:Employee-home_phone ;
northwind:extension employees.Extension
as virtrdf:Employee-extension ;
northwind:notes employees.Notes
as virtrdf:Employee-notes ;
northwind:reportsTo northwind:Employee(employees.FirstName, employees.LastName, employees.ReportsTo) where (^{employees.}^.ReportsTo = ^{employees.}^.EmployeeID)
as virtrdf:Employee-reports_to ;
foaf:img northwind:EmployeePhoto(employees.EmployeeID)
as virtrdf:Employee-employees.EmployeePhoto ;
rdfs:isDefinedBy northwind: .
northwind:EmployeeDoc (employees.FirstName, employees.LastName, employees.EmployeeID)
a northwind:EmployeeDoc
as virtrdf:EmployeeDoc-EmployeeID2 ;
a foaf:Document
as virtrdf:EmployeeDoc-EmployeeID3 ;
foaf:primaryTopic northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID)
as virtrdf:EmployeeDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:EmployeePhoto(employees.EmployeeID)
a northwind:EmployeePhoto
as virtrdf:Employee-employees.EmployeePhotoId ;
rdfs:isDefinedBy northwind: .
northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID)
northwind:is_salesrep_of
northwind:Order (orders.OrderID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID) as virtrdf:Order-is_salesrep_of .
northwind:Country (employees.Country)
northwind:is_country_of
northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID) as virtrdf:Employee-is_country_of .
northwind:Order (orders.OrderID)
a northwind:Order
as virtrdf:Order-Order ;
northwind:has_customer northwind:Customer (orders.CustomerID)
as virtrdf:Order-order_has_customer ;
northwind:has_salesrep northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID)
as virtrdf:Customer-has_salesrep ;
northwind:has_employee northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID)
as virtrdf:Order-order_has_employee ;
northwind:orderDate orders.OrderDate
as virtrdf:Order-order_date ;
northwind:requiredDate orders.RequiredDate
as virtrdf:Order-required_date ;
northwind:shippedDate orders.ShippedDate
as virtrdf:Order-shipped_date ;
northwind:order_ship_via northwind:Shipper (orders.ShipVia)
as virtrdf:Order-order_ship_via ;
northwind:freight orders.Freight
as virtrdf:Order-freight ;
northwind:shipName orders.ShipName
as virtrdf:Order-ship_name ;
northwind:shipAddress orders.ShipAddress
as virtrdf:Order-ship_address ;
northwind:shipCity northwind:dbpedia_iri2(orders.ShipCity)
as virtrdf:Order-dbpediaship_city ;
northwind:shipRegion orders.ShipRegion
as virtrdf:Order-ship_region ;
northwind:shipPostal_code orders.ShipPostalCode
as virtrdf:Order-ship_postal_code ;
northwind:shipCountry northwind:Country(orders.ShipCountry)
as virtrdf:ship_country ;
rdfs:isDefinedBy northwind: .
northwind:OrderDoc (orders.OrderID)
a northwind:OrderDoc
as virtrdf:OrderDoc-OrderID2 ;
a foaf:Document
as virtrdf:OrderDoc-OrderID3 ;
foaf:primaryTopic northwind:Order (orders.OrderID)
as virtrdf:OrderDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Country (orders.ShipCountry)
northwind:is_ship_country_of
northwind:Order (orders.OrderID) as virtrdf:Order-is_country_of .
northwind:Customer (orders.CustomerID)
northwind:has_order northwind:Order (orders.OrderID) as virtrdf:Order-has_order .
northwind:Shipper (orders.ShipVia)
northwind:ship_order northwind:Order (orders.OrderID) as virtrdf:Order-ship_order .
northwind:OrderLine (order_lines.OrderID, order_lines.ProductID)
a northwind:OrderLine
as virtrdf:OrderLine-OrderLines ;
northwind:has_order_id northwind:Order (order_lines.OrderID)
as virtrdf:order_lines_has_order_id ;
northwind:has_product_id northwind:Product (order_lines.ProductID)
as virtrdf:order_lines_has_product_id ;
northwind:unitPrice order_lines.UnitPrice
as virtrdf:OrderLine-unit_price ;
northwind:quantity order_lines.Quantity
as virtrdf:OrderLine-quantity ;
northwind:discount order_lines.Discount
as virtrdf:OrderLine-discount ;
rdfs:isDefinedBy northwind: .
northwind:OrderLineDoc (order_lines.OrderID, order_lines.ProductID)
a northwind:OrderLineDoc
as virtrdf:OrderLineDoc-OrderLineID2 ;
a foaf:Document
as virtrdf:OrderLineDoc-OrderLineID3 ;
foaf:primaryTopic northwind:OrderLine (order_lines.OrderID, order_lines.ProductID)
as virtrdf:OrderLineDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Order (orders.OrderID)
northwind:is_order_of
northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) where (^{orders.}^.OrderID = ^{order_lines.}^.OrderID) as virtrdf:Order-is_order_of .
northwind:Product (products.ProductID)
northwind:is_product_of
northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) where (^{products.}^.ProductID = ^{order_lines.}^.ProductID) as virtrdf:Product-is_product_of .
northwind:Country (countries.Name)
a northwind:Country
as virtrdf:Country-Type2 ;
a wgs:SpatialThing
as virtrdf:Country-Type ;
owl:sameAs northwind:dbpedia_iri2 (countries.Name) ;
northwind:name countries.Name
as virtrdf:Country-Name ;
northwind:code countries.Code
as virtrdf:Country-Code ;
northwind:smallFlagDAVResourceName countries.SmallFlagDAVResourceName
as virtrdf:Country-SmallFlagDAVResourceName ;
northwind:largeFlagDAVResourceName countries.LargeFlagDAVResourceName
as virtrdf:Country-LargeFlagDAVResourceName ;
northwind:smallFlagDAVResourceURI northwind:Flag(countries.SmallFlagDAVResourceURI)
as virtrdf:Country-SmallFlagDAVResourceURI ;
northwind:largeFlagDAVResourceURI northwind:Flag(countries.LargeFlagDAVResourceURI)
as virtrdf:Country-LargeFlagDAVResourceURI ;
wgs:lat countries.Lat
as virtrdf:Country-Lat ;
wgs:long countries.Lng
as virtrdf:Country-Lng ;
rdfs:isDefinedBy northwind: .
northwind:CountryDoc (countries.Name)
a northwind:CountryDoc
as virtrdf:CountryDoc-CountryID2 ;
a foaf:Document
as virtrdf:CountryDoc-CountryID3 ;
foaf:primaryTopic northwind:Country (countries.Name)
as virtrdf:CountryDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Country (countries.Name)
northwind:has_province
northwind:Province (provinces.CountryCode, provinces.Province) where (^{provinces.}^.CountryCode = ^{countries.}^.Code) as virtrdf:Country-has_province .
northwind:Province (provinces.CountryCode, provinces.Province)
a northwind:Province
as virtrdf:Province-Provinces ;
owl:sameAs northwind:dbpedia_iri2 (provinces.Province) ;
northwind:has_country_code provinces.CountryCode
as virtrdf:has_country_code ;
northwind:provinceName provinces.Province
as virtrdf:Province-ProvinceName ;
rdfs:isDefinedBy northwind: .
northwind:ProvinceDoc (provinces.CountryCode, provinces.Province)
a northwind:ProvinceDoc
as virtrdf:ProvinceDoc-ProvinceID2 ;
a foaf:Document
as virtrdf:ProvinceDoc-ProvinceID3 ;
foaf:primaryTopic northwind:Province (provinces.CountryCode, provinces.Province)
as virtrdf:ProvinceDoc-foaf_primarytopic ;
rdfs:isDefinedBy northwind: .
northwind:Province (provinces.CountryCode, provinces.Province)
northwind:is_province_of
northwind:Country (countries.Name) where (^{countries.}^.Code = ^{provinces.}^.CountryCode) as virtrdf:Province-country_of .
}.
}.
;
delete FROM DB.DBA.URL_REWRITE_RULE_LIST where urrl_list like 'demo_nw%';
delete FROM DB.DBA.URL_REWRITE_RULE where urr_rule like 'demo_nw%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'demo_nw_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%23this%%3E+%%3Chttp%%3A//^{URIQADefaultHost}^%U%%3E+FROM+%%3Chttp%%3A//^{URIQADefaultHost}^/Northwind%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'demo_nw_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'demo_nw_rule_list1',
1,
vector (
'demo_nw_rule1',
'demo_nw_rule2'
));
VHOST_REMOVE (lpath=>'/Northwind');
DB.DBA.VHOST_DEFINE (lpath=>'/Northwind', ppath=>'/DAV/home/demo/', vsp_user=>'dba', is_dav=>1,
is_brws=>0, opts=>vector ('url_rewrite', 'demo_nw_rule_list1'));
create procedure DB.DBA.LOAD_NW_ONTOLOGY_FROM_DAV()
{
declare content1, urihost varchar;
SELECT cast (RES_CONTENT as varchar) into content1 FROM WS.WS.SYS_DAV_RES where RES_FULL_PATH = '/DAV/VAD/demo/sql/nw.owl';
DB.DBA.RDF_LOAD_RDFXML (content1, 'http://demo.openlinksw.com/schemas/northwind#', 'http://demo.openlinksw.com/schemas/NorthwindOntology/1.0/');
urihost := cfg_item_value(virtuoso_ini_path(), 'URIQA','DefaultHost');
if (urihost = 'demo.openlinksw.com')
{
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/northwind');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/northwind', ppath=>'/DAV/VAD/demo/sql/nw.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
DB.DBA.VHOST_REMOVE (lpath=>'/schemas/northwind#');
DB.DBA.VHOST_DEFINE (lpath=>'/schemas/northwind#', ppath=>'/DAV/VAD/demo/sql/nw.owl', vsp_user=>'dba', is_dav=>1, is_brws=>0);
}
};
DB.DBA.LOAD_NW_ONTOLOGY_FROM_DAV();
drop procedure DB.DBA.LOAD_NW_ONTOLOGY_FROM_DAV;
DB.DBA.XML_SET_NS_DECL ('northwind', 'http://demo.openlinksw.com/schemas/northwind#', 2);
]]></programlisting>
<para><emphasis>Basic Northwind Ontology</emphasis></para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="utf-8"?>
<!--
-
-
- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
- project.
-
- Copyright (C) 1998-2007 OpenLink Software
-
- This project is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; only version 2 of the License, dated June 1991.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-->
<rdf:RDF xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl ="http://www.w3.org/2002/07/owl#"
xmlns:virtrdf="http://www.openlinksw.com/schemas/virtrdf#"
xml:base="http://demo.openlinksw.com/schemas/northwind#">
<owl:Ontology rdf:about="http://demo.openlinksw.com/schemas/northwind#">
<rdfs:label>Northwind</rdfs:label>
<rdfs:comment>Northwind database classes and properties</rdfs:comment>
<virtrdf:catName>Northwind</virtrdf:catName>
<virtrdf:version>1.00</virtrdf:version>
</owl:Ontology>
<rdfs:Class rdf:ID="Product">
<rdfs:label>Product</rdfs:label>
</rdfs:Class>
<rdf:Property rdf:ID="has_category">
<rdfs:range rdf:resource="#Category"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Category</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="has_supplier">
<rdfs:range rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Supplier</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProductName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ProductName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="QuantityPerUnit">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>QuantityPerUnit</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="UnitPrice">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:domain rdf:resource="#OrderLine"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>UnitPrice</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="UnitsInStock">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>UnitsInStock</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="UnitsOnOrder">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>UnitsOnOrder</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ReorderLevel">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ReorderLevel</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Discontinued">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#Product"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Discontinued</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="Supplier">
<rdfs:label>Supplier</rdfs:label>
</rdfs:Class>
<rdf:Property rdf:ID="CompanyName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Shipper"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>CompanyName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ContactName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/name"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#CustomerContact"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ContactName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ContactTitle">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/title"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ContactTitle</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Address">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Address</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="City">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>City</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Region">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Region</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="PostalCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>PostalCode</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="CountryName">
<rdfs:range rdf:resource="#Country"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#CustomerContact"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Country</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Phone">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/phone"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Shipper"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#CustomerContact"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Phone</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Fax">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:domain rdf:resource="#Customer"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Fax</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="HomePage">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Supplier"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>HomePage</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="Category">
<rdfs:label>Category</rdfs:label>
</rdfs:Class>
<rdf:Property rdf:ID="CategoryName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Category"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>CategoryName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Description">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Category"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Description</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="Shipper">
<rdfs:label>Shipper</rdfs:label>
</rdfs:Class>
<rdfs:Class rdf:ID="CustomerContact">
<rdfs:label>CustomerContact</rdfs:label>
<rdfs:subClassOf rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
</rdfs:Class>
<rdfs:Class rdf:ID="Customer">
<rdfs:label>Customer</rdfs:label>
<rdfs:subClassOf rdf:resource="http://xmlns.com/foaf/0.1/Organization"/>
</rdfs:Class>
<rdfs:Class rdf:ID="Employee">
<rdfs:label>Employee</rdfs:label>
<rdfs:subClassOf rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
</rdfs:Class>
<rdf:Property rdf:ID="LastName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/surname"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>LastName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="FirstName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/firstName"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>FirstName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Title">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/title"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Title</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="TitleOfCourtesy">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>TitleOfCourtesy</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="BirthDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/birthday"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>BirthDate</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="HireDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>HireDate</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Extension">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Extension</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Notes">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Notes</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ReportsTo">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#Employee"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ReportsTo</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="Order">
<rdfs:label>Order</rdfs:label>
</rdfs:Class>
<rdf:Property rdf:ID="has_customer">
<rdfs:range rdf:resource="#Customer"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Customer</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="has_employee">
<rdfs:range rdf:resource="#Employee"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Employee</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="OrderDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>OrderDate</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="RequiredDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>RequiredDate</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShippedDate">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShippedDate</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="order_ship_via">
<rdfs:range rdf:resource="#Shipper"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Shipper</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Freight">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Freight</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShipName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShipName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShipAddress">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShipAddress</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShipCity">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShipCity</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShipRegion">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShipRegion</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShipPostalCode">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShipPostalCode</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ShipCountry">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Order"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ShipCountry</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="OrderLine">
<rdfs:label>OrderLine</rdfs:label>
</rdfs:Class>
<rdf:Property rdf:ID="has_order_id">
<rdfs:range rdf:resource="#Order"/>
<rdfs:domain rdf:resource="#OrderLine"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Order</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="has_product_id">
<rdfs:range rdf:resource="#Product"/>
<rdfs:domain rdf:resource="#OrderLine"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Product</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Quantity">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
<rdfs:domain rdf:resource="#OrderLine"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Quantity</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Discount">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#double"/>
<rdfs:domain rdf:resource="#OrderLine"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Discount</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="Country">
<rdfs:label>Country</rdfs:label>
<rdfs:subClassOf rdf:resource="http://www.w3.org/2003/01/geo/wgs84_pos#SpatialThing"/>
</rdfs:Class>
<rdf:Property rdf:ID="Name">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Name</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Code">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Code</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="SmallFlagDAVResourceName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>SmallFlagDAVResourceName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="LargeFlagDAVResourceName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>LargeFlagDAVResourceName</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="SmallFlagDAVResourceURI">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>SmallFlagDAVResourceURI</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="LargeFlagDAVResourceURI">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>LargeFlagDAVResourceURI</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Lat">
<rdfs:range rdf:resource="ttp://www.w3.org/2003/01/geo/wgs84_pos#lat"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Lat</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="Lng">
<rdfs:range rdf:resource="ttp://www.w3.org/2003/01/geo/wgs84_pos#lng"/>
<rdfs:domain rdf:resource="#Country"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Lng</rdfs:label>
</rdf:Property>
<rdfs:Class rdf:ID="Province">
<rdfs:label>Province</rdfs:label>
</rdfs:Class>
<rdf:Property rdf:ID="has_country_code">
<rdfs:range rdf:resource="#Country"/>
<rdfs:domain rdf:resource="#Provinces"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>Country Code</rdfs:label>
</rdf:Property>
<rdf:Property rdf:ID="ProvinceName">
<rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#string"/>
<rdfs:domain rdf:resource="#Province"/>
<rdfs:cardinality>1</rdfs:cardinality>
<rdfs:label>ProvinceName</rdfs:label>
</rdf:Property>
</rdf:RDF>
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterohr">
<title>Oracle Demonstration 'HR' Database </title>
<para><emphasis>Live links to a sample instance</emphasis></para>
<itemizedlist mark="bullet">
<listitem><ulink url="http://demo.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=%20prefix%20hr%3A%20%3Chttp%3A%2F%2Fdemo.openlinksw.com%2Fschemas%2Foraclehr%2F%3E%20select%20*%20from%20%3Chttp%3A%2F%2Fdemo.openlinksw.com%2Foraclehr%3E%20WHERE%20%7B%3Fs%20a%20hr%3Aemployees%7D&format=text%2Fhtml&debug=on">list all employee URIs</ulink></listitem>
<listitem><ulink url="http://demo.openlinksw.com/about/html/http/demo.openlinksw.com/oraclehr/employees/105">description of employee 105</ulink></listitem>
</itemizedlist>
<para><emphasis>Script to set up your own instance</emphasis></para>
<programlisting><![CDATA[
-- Setup script for RDF views of Oracle 10 Human Resources Sample Database --
GRANT SELECT ON HR.orama.COUNTRIES TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.REGIONS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.DEPARTMENTS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.LOCATIONS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.EMPLOYEES TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.JOBS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.JOB_HISTORY TO "SPARQL", "SPARQL_UPDATE";
-------------------------------------------------------------------
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix hr: <http://localhost:8890/schemas/oraclehr/> .
hr:countries a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "COUNTRIES" ;
rdfs:comment "Oracle HR COUNTRIES table" .
hr:country_id a rdf:Property ;
rdfs:domain hr:countries ;
rdfs:range xsd:string ;
rdfs:label "COUNTRY ID" .
hr:country_name a rdf:Property ;
rdfs:domain hr:countries ;
rdfs:range xsd:string ;
rdfs:label "COUNTRY NAME" .
hr:region_id a rdf:Property ;
rdfs:domain hr:countries ;
rdfs:range hr:regions ;
rdfs:label "REGION ID" .
hr:regions a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "REGIONS" ;
rdfs:comment "Oracle HR REGIONS table" .
hr:region_id a rdf:Property ;
rdfs:domain hr:regions ;
rdfs:range xsd:integer ;
rdfs:label "REGION ID" .
hr:region_name a rdf:Property ;
rdfs:domain hr:regions ;
rdfs:range xsd:string ;
rdfs:label "REGION NAME" .
hr:departments a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "DEPARTMENTS" ;
rdfs:comment "Oracle HR DEPARTMENT table" .
hr:department_id a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range xsd:integer ;
rdfs:label "DEPARTMENT ID" .
hr:department_name a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range xsd:string ;
rdfs:comment "DEPARTMENT NAME" .
hr:manager_id a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range hr:employees ;
rdfs:comment "MANAGER ID" .
hr:location_id a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range hr:locations ;
rdfs:comment "LOCATION ID" .
hr:employees a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "employees" ;
rdfs:comment "Oracle HR EMPLOYEES table" .
hr:employee_id a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range xsd:integer ;
rdfs:label "EMPLOYEE ID" .
hr:first_name a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range xsd:string ;
rdfs:label "FIRST NAME" .
hr:last_name a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:string ;
rdfs:label "LAST NAME" .
hr:email a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range xsd:string ;
rdfs:label "EMAIL" .
hr:phone_number a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:string ;
rdfs:label "PHONE NUMBER" .
hr:hire_date a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:date ;
rdfs:label "HIRE DATE" .
hr:job_id a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range hr:jobs ;
rdfs:label "JOB ID" .
hr:salary a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:integer ;
rdfs:label "SALARY" .
hr:commission_pct a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:integer ;
rdfs:label "COMMISSION PCT" .
hr:manager_id a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:string ;
rdfs:label "MANAGER ID" .
hr:department_id a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range hr:departments ;
rdfs:label "DEPARTMENT ID" .
hr:jobs a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "JOBS" ;
rdfs:comment "Oracle HR JOBS table" .
hr:job_id a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:string ;
rdfs:label "JOB ID" .
hr:job_title a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:string ;
rdfs:label "JOB TITLE" .
hr:min_salary a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:number;
rdfs:label "MIN SALARY" .
hr:max_salary a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:number;
rdfs:label "MAXSALARY" .
hr:job_history a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "JOB HISTORY" ;
rdfs:comment "Oracle HR JOB HISTORY table" .
hr:employee_id a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range hr:employees ;
rdfs:label "EMPLOYEE ID" .
hr:start_date a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range xsd:date ;
rdfs:label "START DATE" .
hr:end_date a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range xsd:date ;
rdfs:label "END DATE" .
hr:job_id a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range hr:jobs ;
rdfs:label "JOB ID" .
hr:department_id a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range hr:departments ;
rdfs:label "DEPARTMENT ID" .
hr:locations a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "LOCATIONS" ;
rdfs:comment "Oracle HR JOB LOCATIONS table" .
hr:location_id a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:number ;
rdfs:label "LOCATION ID" .
hr:street_address a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "STREET ADDRESS" .
hr:postal_code a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "POSTAL CODE" .
hr:city a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "CITY" .
hr:state_province a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "STATE PROVINCE" .
hr:country_id a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range hr:countries ;
rdfs:label "COUNTRY" .
', '', 'http://localhost:8890/schemas/oraclehr', 0);
---------------------------------------------------------------
----------- Create IRI Classes -------------
create function DB.DBA.JOB_HISTORY (in EMPLOYEE_ID integer, in
START_DATE date) returns varchar
{
return sprintf_or_null
('http://localhost:8890/oraclehr/job_history/%d_%s#this',
EMPLOYEE_ID, cast (START_DATE as varchar) );
}
;
create function DB.DBA.JOB_HISTORY_INV_1 (in id varchar) returns integer
{
return sprintf_inverse (id,
'http://localhost:8890/oraclehr/job_history/%d_%s#this',
2)[0];
}
;
create function DB.DBA.JOB_HISTORY_INV_2 (in id varchar) returns date
{
declare exit handler for sqlstate '*' { return NULL; };
return cast (sprintf_inverse (id,
'http://localhost:8890/oraclehr/job_history/%d_%s#this',
2)[1] as date);
}
;
GRANT EXECUTE ON DB.DBA.JOB_HISTORY TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON DB.DBA.JOB_HISTORY_URI_INV_1 TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON DB.DBA.JOB_HISTORY_URI_INV_2 TO "SPARQL", "SPARQL_UPDATE";
SPARQL
create iri class <http://localhost:8890/schemas/oraclehr/countries_iri>
"http://^{URIQADefaultHost}^/oraclehr/countries/%s#this"
(in COUNTRY_ID varchar not null) .
create iri class <http://localhost:8890/schemas/oraclehr/regions_iri>
"http://^{URIQADefaultHost}^/oraclehr/regions/%d#this"
(in REGION_ID integer not null) .
create iri class <http://localhost:8890/schemas/oraclehr/departments_iri>
"http://^{URIQADefaultHost}^/oraclehr/departments/%d#this"
(in DEPARTMENT_ID integer not null) .
create iri class <http://localhost:8890/schemas/oraclehr/employees_iri>
"http://^{URIQADefaultHost}^/oraclehr/employees/%d#this"
(in EMPLOYEE_ID integer not null) .
create iri class <http://localhost:8890/schemas/oraclehr/jobs_iri>
"http://^{URIQADefaultHost}^/oraclehr/jobs/%s#this"
(in JOB_ID varchar not null) .
create iri class <http://localhost:8890/schemas/oraclehr/job_history_iri>
using function DB.DBA.JOB_HISTORY (in EMPLOYEE_ID integer not null, in
START_DATE date not null) returns varchar not null,
function DB.DBA.JOB_HISTORY_INV_1 (in id varchar) returns integer,
function DB.DBA.JOB_HISTORY_INV_2 (in id varchar) returns date
option (bijection, returns
"http://localhost:8890/oraclehr/job_history/%d_%s#this") .
create iri class <http://localhost:8890/schemas/oraclehr/locations_iri>
"http://^{URIQADefaultHost}^/oraclehr/locations/%d#this"
(in LOCATION_ID integer not null) .
;
--------------------------------------------------------------------
------------- Create Quad Store ------------------------------------
SPARQL
prefix hr: <http://localhost:8890/schemas/oraclehr/>
alter quad storage virtrdf:DefaultQuadStorage
FROM HR.orama.COUNTRIES as countries_tbl
FROM HR.orama.REGIONS as regions_tbl
FROM HR.orama.DEPARTMENTS as departments_tbl
FROM HR.orama.EMPLOYEES as employees_tbl
FROM HR.orama.EMPLOYEES as employees_tbl_1 ### alias required to represent recursive FK relationship (hr: has_manager ) below.
FROM HR.orama.JOBS as jobs_tbl
FROM HR.orama.JOB_HISTORY as job_history_tbl
FROM HR.orama.LOCATIONS as locations_tbl
{
create virtrdf:oraclehr as
graph <http://localhost:8890/oraclehr>
{
hr:countries_iri(countries_tbl.COUNTRY_ID) a hr:countries as virtrdf:countires_country_id ;
hr:country_name countries_tbl.COUNTRY_NAME as virtrdf:countries_country_name ;
hr:region_id hr:regions_iri(regions_tbl.REGION_ID) where (^{countries_tbl.}^.REGION_ID = ^{regions_tbl.}^.REGION_ID) as virtrdf:countries_region_id .
hr:regions_iri(regions_tbl.REGION_ID) a hr:regions as virtrdf:regions_region_id ;
hr:region_name regions_tbl.REGION_NAME as virtrdf:regions_region_name .
hr:departments_iri(departments_tbl.DEPARTMENT_ID) a hr:departments as virtrdf:departments_department_id ;
hr:department_name departments_tbl.DEPARTMENT_NAME as virtrdf:departments_department_name ;
hr:location_id hr:locations_iri(locations_tbl.LOCATION_ID) where (^{departments_tbl.}^.LOCATION_ID = ^{locations_tbl.}^.LOCATION_ID) as virtrdf:departments_location_id ;
hr:manager_id hr:employees_iri(employees_tbl.EMPLOYEE_ID) where (^{departments_tbl.}^.MANAGER_ID = ^{employees_tbl.}^.EMPLOYEE_ID) as virtrdf:departments_manager_id .
hr:employees_iri(employees_tbl.EMPLOYEE_ID) a hr:employees as virtrdf:employees_employee_id ;
hr:department_id hr:departments_iri(departments_tbl.DEPARTMENT_ID) where (^{employees_tbl.}^.DEPARTMENT_ID = ^{departments_tbl.}^.DEPARTMENT_ID) as virtrdf:employees_department_id ;
hr:job_id hr:jobs_iri(jobs_tbl.JOB_ID) where (^{employees_tbl.}^.JOB_ID = ^{jobs_tbl.}^.JOB_ID) as virtrdf:employees_job_id ;
hr:manager_id employees_tbl.MANAGER_ID as virtrdf:employees_manager_id ;
hr:commissin_pct employees_tbl.COMMISSION_PCT as virtrdf:employees_commission_pct ;
hr:email employees_tbl.EMAIL as virtrdf:employees_email ;
hr:first_name employees_tbl.FIRST_NAME as virtrdf:employees_first_name ;
hr:hire_date employees_tbl.HIRE_DATE as virtrdf:employees_hire_date ;
hr:last_name employees_tbl.LAST_NAME as virtrdf:employees_last_name ;
hr:phone_number employees_tbl.PHONE_NUMBER as virtrdf:employees_phone_number ;
hr:salary employees_tbl.SALARY as virtrdf:employees_salary ;
hr:has_job_history hr:job_history_iri(job_history_tbl.EMPLOYEE_ID, job_history_tbl.START_DATE) where (^{employees_tbl.}^.EMPLOYEE_ID = ^{job_history_tbl.}^.EMPLOYEE_ID) as virtrdf:employees_has_job_history;
hr:has_manager hr:employees_iri(employees_tbl_1.EMPLOYEE_ID) where (^{employees_tbl.}^.MANAGER_ID = ^{employees_tbl_1.}^.EMPLOYEE_ID) as virtrdf:employees_has_manager.
hr:locations_iri(locations_tbl.LOCATION_ID) a hr:locations as virtrdf:locations_location_id ;
hr:country_id hr:countries_iri(countries_tbl.COUNTRY_ID) where (^{locations_tbl.}^.COUNTRY_ID = ^{countries_tbl.}^.COUNTRY_ID) as virtrdf:locations_country_id ;
hr:city locations_tbl.CITY as virtrdf:locations_city ;
hr:postal_code locations_tbl.POSTAL_CODE as virtrdf:locations_postal_code ;
hr:state_province locations_tbl.STATE_PROVINCE as virtrdf:locations_state_province ;
hr:street_address locations_tbl.STREET_ADDRESS as virtrdf:locations_street_address .
hr:jobs_iri(jobs_tbl.JOB_ID) a hr:jobs as virtrdf:jobs_job_id ;
hr:job_title jobs_tbl.JOB_TITLE as virtrdf:jobs_job_title ;
hr:max_salary jobs_tbl.MAX_SALARY as virtrdf:jobs_max_salary ;
hr:min_salary jobs_tbl.MIN_SALARY as virtrdf:jobs_min_salary .
hr:job_history_iri(job_history_tbl.EMPLOYEE_ID, job_history_tbl.START_DATE) a hr:job_history as virtrdf:job_history_pk ;
hr:employee_id hr:employees_iri(employees_tbl.EMPLOYEE_ID) where (^{job_history_tbl.}^.EMPLOYEE_ID = ^{employees_tbl.}^.EMPLOYEE_ID) as virtrdf:job_history_employee_id ;
hr:department_id hr:departments_iri(departments_tbl.DEPARTMENT_ID) where (^{job_history_tbl.}^.DEPARTMENT_ID = ^{departments_tbl.}^.DEPARTMENT_ID) as virtrdf:job_history_department_id ;
hr:job_id hr:jobs_iri(jobs_tbl.JOB_ID) where (^{job_history_tbl.}^.JOB_ID = ^{jobs_tbl.}^.JOB_ID) as virtrdf:job_history_job_id ;
hr:start_date job_history_tbl.START_DATE as virtrdf:job_history_start_date ;
hr:end_date job_history_tbl.END_DATE as virtrdf:job_history_end_date .
}.
}.
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'oraclehr_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'oraclehr_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oraclehr_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oraclehr_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/oraclehr%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'oraclehr_rule_list1',
1,
vector (
'oraclehr_rule1',
'oraclehr_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/oraclehr');
VHOST_DEFINE (
lpath=>'/oraclehr',
ppath=>'/DAV/oraclehr/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'oraclehr_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'oracle_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'oracle_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oracle_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oracle_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/oraclehr%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'oracle_schemas_rule_list1',
1,
vector (
'oracle_schemas_rule1',
'oracle_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schema/oraclehr');
VHOST_DEFINE (
lpath=>'/schemas/oraclehr',
ppath=>'/DAV/schemas/oraclehr/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'oracle_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('hr', 'http://^{URIQADefaultHost}^/schemas/oraclehr/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterprohd">
<title>Oracle using the demonstration 'Human Resources' database</title>
<para><emphasis>Live links to a sample instance</emphasis></para>
<itemizedlist mark="bullet">
<listitem><ulink url="http://demo.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=%20prefix%20hr%3A%20%3Chttp%3A%2F%2Fdemo.openlinksw.com%2Fschemas%2Foraclehr%2F%3E%20select%20*%20from%20%3Chttp%3A%2F%2Fdemo.openlinksw.com%2Foraclehr%3E%20WHERE%20%7B%3Fs%20a%20hr%3Aemployees%7D&format=text%2Fhtml&debug=on">list all employee URIs</ulink></listitem>
<listitem><ulink url="http://demo.openlinksw.com/about/html/http/demo.openlinksw.com/oraclehr/employees/105">description of employee 105</ulink></listitem>
</itemizedlist>
<para><emphasis>Script to set up your own instance</emphasis></para>
<programlisting><![CDATA[
-- Setup script for RDF views of Oracle 10 Human Resources Sample Database --
GRANT SELECT ON HR.orama.COUNTRIES TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.REGIONS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.DEPARTMENTS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.LOCATIONS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.EMPLOYEES TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.JOBS TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON HR.orama.JOB_HISTORY TO "SPARQL", "SPARQL_UPDATE";
-------------------------------------------------------------------
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix hr: <http://localhost:8890/schemas/oraclehr/> .
hr:countries a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "COUNTRIES" ;
rdfs:comment "Oracle HR COUNTRIES table" .
hr:country_id a rdf:Property ;
rdfs:domain hr:countries ;
rdfs:range xsd:string ;
rdfs:label "COUNTRY ID" .
hr:country_name a rdf:Property ;
rdfs:domain hr:countries ;
rdfs:range xsd:string ;
rdfs:label "COUNTRY NAME" .
hr:region_id a rdf:Property ;
rdfs:domain hr:countries ;
rdfs:range hr:regions ;
rdfs:label "REGION ID" .
hr:regions a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "REGIONS" ;
rdfs:comment "Oracle HR REGIONS table" .
hr:region_id a rdf:Property ;
rdfs:domain hr:regions ;
rdfs:range xsd:integer ;
rdfs:label "REGION ID" .
hr:region_name a rdf:Property ;
rdfs:domain hr:regions ;
rdfs:range xsd:string ;
rdfs:label "REGION NAME" .
hr:departments a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "DEPARTMENTS" ;
rdfs:comment "Oracle HR DEPARTMENT table" .
hr:department_id a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range xsd:integer ;
rdfs:label "DEPARTMENT ID" .
hr:department_name a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range xsd:string ;
rdfs:comment "DEPARTMENT NAME" .
hr:manager_id a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range hr:employees ;
rdfs:comment "MANAGER ID" .
hr:location_id a rdf:Property ;
rdfs:domain hr:departments ;
rdfs:range hr:locations ;
rdfs:comment "LOCATION ID" .
hr:employees a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "employees" ;
rdfs:comment "Oracle HR EMPLOYEES table" .
hr:employee_id a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range xsd:integer ;
rdfs:label "EMPLOYEE ID" .
hr:first_name a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range xsd:string ;
rdfs:label "FIRST NAME" .
hr:last_name a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:string ;
rdfs:label "LAST NAME" .
hr:email a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range xsd:string ;
rdfs:label "EMAIL" .
hr:phone_number a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:string ;
rdfs:label "PHONE NUMBER" .
hr:hire_date a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:date ;
rdfs:label "HIRE DATE" .
hr:job_id a rdf:Property ;
rdfs:domain hr:employees;
rdfs:range hr:jobs ;
rdfs:label "JOB ID" .
hr:salary a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:integer ;
rdfs:label "SALARY" .
hr:commission_pct a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:integer ;
rdfs:label "COMMISSION PCT" .
hr:manager_id a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range xsd:string ;
rdfs:label "MANAGER ID" .
hr:department_id a rdf:Property ;
rdfs:domain hr:employees ;
rdfs:range hr:departments ;
rdfs:label "DEPARTMENT ID" .
hr:jobs a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "JOBS" ;
rdfs:comment "Oracle HR JOBS table" .
hr:job_id a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:string ;
rdfs:label "JOB ID" .
hr:job_title a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:string ;
rdfs:label "JOB TITLE" .
hr:min_salary a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:number;
rdfs:label "MIN SALARY" .
hr:max_salary a rdf:Property ;
rdfs:domain hr:jobs ;
rdfs:range xsd:number;
rdfs:label "MAXSALARY" .
hr:job_history a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "JOB HISTORY" ;
rdfs:comment "Oracle HR JOB HISTORY table" .
hr:employee_id a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range hr:employees ;
rdfs:label "EMPLOYEE ID" .
hr:start_date a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range xsd:date ;
rdfs:label "START DATE" .
hr:end_date a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range xsd:date ;
rdfs:label "END DATE" .
hr:job_id a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range hr:jobs ;
rdfs:label "JOB ID" .
hr:department_id a rdf:Property ;
rdfs:domain hr:job_history ;
rdfs:range hr:departments ;
rdfs:label "DEPARTMENT ID" .
hr:locations a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/oraclehr> ;
rdfs:label "LOCATIONS" ;
rdfs:comment "Oracle HR JOB LOCATIONS table" .
hr:location_id a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:number ;
rdfs:label "LOCATION ID" .
hr:street_address a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "STREET ADDRESS" .
hr:postal_code a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "POSTAL CODE" .
hr:city a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "CITY" .
hr:state_province a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range xsd:string ;
rdfs:label "STATE PROVINCE" .
hr:country_id a rdf:Property ;
rdfs:domain hr:locations ;
rdfs:range hr:countries ;
rdfs:label "COUNTRY" .
', '', 'http://localhost:8890/schemas/oraclehr', 0);
---------------------------------------------------------------
----------- Create IRI Classes -------------
create function DB.DBA.JOB_HISTORY (in EMPLOYEE_ID integer, in
START_DATE date) returns varchar
{
return sprintf_or_null
('http://localhost:8890/oraclehr/job_history/%d_%s#this',
EMPLOYEE_ID, cast (START_DATE as varchar) );
}
;
create function DB.DBA.JOB_HISTORY_INV_1 (in id varchar) returns integer
{
return sprintf_inverse (id,
'http://localhost:8890/oraclehr/job_history/%d_%s#this',
2)[0];
}
;
create function DB.DBA.JOB_HISTORY_INV_2 (in id varchar) returns date
{
declare exit handler for sqlstate '*' { return NULL; };
return cast (sprintf_inverse (id,
'http://localhost:8890/oraclehr/job_history/%d_%s#this',
2)[1] as date);
}
;
GRANT EXECUTE ON DB.DBA.JOB_HISTORY TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON DB.DBA.JOB_HISTORY_URI_INV_1 TO "SPARQL", "SPARQL_UPDATE";
GRANT EXECUTE ON DB.DBA.JOB_HISTORY_URI_INV_2 TO "SPARQL", "SPARQL_UPDATE";
SPARQL
create iri class <http://localhost:8890/schemas/oraclehr/countries_iri>
"http://^{URIQADefaultHost}^/oraclehr/countries/%s#this"
(in COUNTRY_ID varchar not null) .
create iri class <http://localhost:8890/schemas/oraclehr/regions_iri>
"http://^{URIQADefaultHost}^/oraclehr/regions/%d#this"
(in REGION_ID integer not null) .
create iri class <http://localhost:8890/schemas/oraclehr/departments_iri>
"http://^{URIQADefaultHost}^/oraclehr/departments/%d#this"
(in DEPARTMENT_ID integer not null) .
create iri class <http://localhost:8890/schemas/oraclehr/employees_iri>
"http://^{URIQADefaultHost}^/oraclehr/employees/%d#this"
(in EMPLOYEE_ID integer not null) .
create iri class <http://localhost:8890/schemas/oraclehr/jobs_iri>
"http://^{URIQADefaultHost}^/oraclehr/jobs/%s#this"
(in JOB_ID varchar not null) .
create iri class <http://localhost:8890/schemas/oraclehr/job_history_iri>
using function DB.DBA.JOB_HISTORY (in EMPLOYEE_ID integer not null, in
START_DATE date not null) returns varchar not null,
function DB.DBA.JOB_HISTORY_INV_1 (in id varchar) returns integer,
function DB.DBA.JOB_HISTORY_INV_2 (in id varchar) returns date
option (bijection, returns
"http://localhost:8890/oraclehr/job_history/%d_%s#this") .
create iri class <http://localhost:8890/schemas/oraclehr/locations_iri>
"http://^{URIQADefaultHost}^/oraclehr/locations/%d#this"
(in LOCATION_ID integer not null) .
;
--------------------------------------------------------------------
------------- Create Quad Store ------------------------------------
SPARQL
prefix hr: <http://localhost:8890/schemas/oraclehr/>
alter quad storage virtrdf:DefaultQuadStorage
from HR.orama.COUNTRIES as countries_tbl
from HR.orama.REGIONS as regions_tbl
from HR.orama.DEPARTMENTS as departments_tbl
from HR.orama.EMPLOYEES as employees_tbl
from HR.orama.EMPLOYEES as employees_tbl_1 ### alias required to represent recursive FK relationship (hr: has_manager ) below.
from HR.orama.JOBS as jobs_tbl
from HR.orama.JOB_HISTORY as job_history_tbl
from HR.orama.LOCATIONS as locations_tbl
{
create virtrdf:oraclehr as
graph <http://localhost:8890/oraclehr>
{
hr:countries_iri(countries_tbl.COUNTRY_ID) a hr:countries as virtrdf:countires_country_id ;
hr:country_name countries_tbl.COUNTRY_NAME as virtrdf:countries_country_name ;
hr:region_id hr:regions_iri(regions_tbl.REGION_ID) where (^{countries_tbl.}^.REGION_ID = ^{regions_tbl.}^.REGION_ID) as virtrdf:countries_region_id .
hr:regions_iri(regions_tbl.REGION_ID) a hr:regions as virtrdf:regions_region_id ;
hr:region_name regions_tbl.REGION_NAME as virtrdf:regions_region_name .
hr:departments_iri(departments_tbl.DEPARTMENT_ID) a hr:departments as virtrdf:departments_department_id ;
hr:department_name departments_tbl.DEPARTMENT_NAME as virtrdf:departments_department_name ;
hr:location_id hr:locations_iri(locations_tbl.LOCATION_ID) where (^{departments_tbl.}^.LOCATION_ID = ^{locations_tbl.}^.LOCATION_ID) as virtrdf:departments_location_id ;
hr:manager_id hr:employees_iri(employees_tbl.EMPLOYEE_ID) where (^{departments_tbl.}^.MANAGER_ID = ^{employees_tbl.}^.EMPLOYEE_ID) as virtrdf:departments_manager_id .
hr:employees_iri(employees_tbl.EMPLOYEE_ID) a hr:employees as virtrdf:employees_employee_id ;
hr:department_id hr:departments_iri(departments_tbl.DEPARTMENT_ID) where (^{employees_tbl.}^.DEPARTMENT_ID = ^{departments_tbl.}^.DEPARTMENT_ID) as virtrdf:employees_department_id ;
hr:job_id hr:jobs_iri(jobs_tbl.JOB_ID) where (^{employees_tbl.}^.JOB_ID = ^{jobs_tbl.}^.JOB_ID) as virtrdf:employees_job_id ;
hr:manager_id employees_tbl.MANAGER_ID as virtrdf:employees_manager_id ;
hr:commissin_pct employees_tbl.COMMISSION_PCT as virtrdf:employees_commission_pct ;
hr:email employees_tbl.EMAIL as virtrdf:employees_email ;
hr:first_name employees_tbl.FIRST_NAME as virtrdf:employees_first_name ;
hr:hire_date employees_tbl.HIRE_DATE as virtrdf:employees_hire_date ;
hr:last_name employees_tbl.LAST_NAME as virtrdf:employees_last_name ;
hr:phone_number employees_tbl.PHONE_NUMBER as virtrdf:employees_phone_number ;
hr:salary employees_tbl.SALARY as virtrdf:employees_salary ;
hr:has_job_history hr:job_history_iri(job_history_tbl.EMPLOYEE_ID, job_history_tbl.START_DATE) where (^{employees_tbl.}^.EMPLOYEE_ID = ^{job_history_tbl.}^.EMPLOYEE_ID) as virtrdf:employees_has_job_history;
hr:has_manager hr:employees_iri(employees_tbl_1.EMPLOYEE_ID) where (^{employees_tbl.}^.MANAGER_ID = ^{employees_tbl_1.}^.EMPLOYEE_ID) as virtrdf:employees_has_manager.
hr:locations_iri(locations_tbl.LOCATION_ID) a hr:locations as virtrdf:locations_location_id ;
hr:country_id hr:countries_iri(countries_tbl.COUNTRY_ID) where (^{locations_tbl.}^.COUNTRY_ID = ^{countries_tbl.}^.COUNTRY_ID) as virtrdf:locations_country_id ;
hr:city locations_tbl.CITY as virtrdf:locations_city ;
hr:postal_code locations_tbl.POSTAL_CODE as virtrdf:locations_postal_code ;
hr:state_province locations_tbl.STATE_PROVINCE as virtrdf:locations_state_province ;
hr:street_address locations_tbl.STREET_ADDRESS as virtrdf:locations_street_address .
hr:jobs_iri(jobs_tbl.JOB_ID) a hr:jobs as virtrdf:jobs_job_id ;
hr:job_title jobs_tbl.JOB_TITLE as virtrdf:jobs_job_title ;
hr:max_salary jobs_tbl.MAX_SALARY as virtrdf:jobs_max_salary ;
hr:min_salary jobs_tbl.MIN_SALARY as virtrdf:jobs_min_salary .
hr:job_history_iri(job_history_tbl.EMPLOYEE_ID, job_history_tbl.START_DATE) a hr:job_history as virtrdf:job_history_pk ;
hr:employee_id hr:employees_iri(employees_tbl.EMPLOYEE_ID) where (^{job_history_tbl.}^.EMPLOYEE_ID = ^{employees_tbl.}^.EMPLOYEE_ID) as virtrdf:job_history_employee_id ;
hr:department_id hr:departments_iri(departments_tbl.DEPARTMENT_ID) where (^{job_history_tbl.}^.DEPARTMENT_ID = ^{departments_tbl.}^.DEPARTMENT_ID) as virtrdf:job_history_department_id ;
hr:job_id hr:jobs_iri(jobs_tbl.JOB_ID) where (^{job_history_tbl.}^.JOB_ID = ^{jobs_tbl.}^.JOB_ID) as virtrdf:job_history_job_id ;
hr:start_date job_history_tbl.START_DATE as virtrdf:job_history_start_date ;
hr:end_date job_history_tbl.END_DATE as virtrdf:job_history_end_date .
} .
} .
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'oraclehr_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'oraclehr_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oraclehr_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oraclehr_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/oraclehr%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'oraclehr_rule_list1',
1,
vector (
'oraclehr_rule1',
'oraclehr_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/oraclehr');
VHOST_DEFINE (
lpath=>'/oraclehr',
ppath=>'/DAV/oraclehr/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'oraclehr_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'oracle_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'oracle_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oracle_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'oracle_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/oraclehr%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'oracle_schemas_rule_list1',
1,
vector (
'oracle_schemas_rule1',
'oracle_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schema/oraclehr');
VHOST_DEFINE (
lpath=>'/schemas/oraclehr',
ppath=>'/DAV/schemas/oraclehr/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'oracle_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('hr', 'http://^{URIQADefaultHost}^/schemas/oraclehr/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterprdb">
<title>DB2 using the demonstration 'Sample' database</title>
<para><emphasis>Version defined using explicit host - localhost:8890</emphasis></para>
<programlisting><![CDATA[
-- $Id: rdfandsparql.xml,v 1.95.2.36 2010/07/08 15:18:23 source Exp $
-- Setup script for RDF view of portions of DB2 SAMPLE database included
-- in DB2 Express Edition v9.5
--
-- The script assumes external DB2 tables are linked into Virtuoso using
-- local schema name db2sample.
DB..vd_remote_data_source ('db2ma-smpl', '', '<uid>','<pwd>);
ATTACH TABLE "DB2ADMIN"."ACT" PRIMARY KEY ("ACTNO") AS "DB"."db2sample"."ACT" FROM 'db2ma-smpl';
ATTACH TABLE "DB2ADMIN"."DEPARTMENT" PRIMARY KEY ("DEPTNO") AS "DB"."db2sample"."DEPARTMENT" FROM 'db2ma-smpl';
ATTACH TABLE "DB2ADMIN"."EMPLOYEE" PRIMARY KEY ("EMPNO") AS "DB"."db2sample"."EMPLOYEE" FROM 'db2ma-smpl';
ATTACH TABLE "DB2ADMIN"."EMPPROJACT" PRIMARY KEY ("EMPNO", "PROJNO", "ACTNO", "EMSTDATE") AS "DB"."db2sample"."EMPPROJACT" FROM 'db2ma-smpl';
ATTACH TABLE "DB2ADMIN"."EMP_RESUME" PRIMARY KEY ("EMPNO", "RESUME_FORMAT) AS "DB"."db2sample"."EMP_RESUME" FROM 'db2ma-smpl';
ATTACH TABLE "DB2ADMIN"."PROJACT" PRIMARY KEY ("PROJNO", "ACTNO", "ACSTDATE") AS "DB"."db2sample"."PROJACT" FROM 'db2ma-smpl';
ATTACH TABLE "DB2ADMIN"."PROJECT" PRIMARY KEY ("PROJNO") AS "DB"."db2sample"."PROJECT" FROM 'db2ma-smpl';
COMMIT WORK;
GRANT SELECT ON DB.db2sample.ACT TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON DB.db2sample.DEPARTMENT TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON DB.db2sample.EMPLOYEE TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON DB.db2sample.EMPPROJACT TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON DB.db2sample.EMP_RESUME TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON DB.db2sample.PROJACT TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON DB.db2sample.PROJECT TO "SPARQL", "SPARQL_UPDATE";
create function DB.DBA.PROJ_ACT_IRI (
in proj_no varchar,
in act_no integer,
in ac_st_date date
) returns varchar
{
declare _act_no, _datetime, _date any;
_act_no := cast(act_no as varchar);
_datetime := cast(ac_st_date as varchar);
_date := left(_datetime, 10);
return sprintf('http://localhost:8890/db2sample/proj_act/%s_%s_%s#this',
proj_no, _act_no, _date);
};
create function
DB.DBA.PROJ_ACT_IRI_INV_1 (in proj_act_iri varchar) returns varchar
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (proj_act_iri,
'http://localhost:8890/db2sample/proj_act/%s_%s_%s#this', 1);
if (parts is not null)
{
return parts[0];
}
return NULL;
};
create function
DB.DBA.PROJ_ACT_IRI_INV_2 (in proj_act_iri varchar) returns integer
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (proj_act_iri,
'http://localhost:8890/db2sample/proj_act/%s_%s_%s#this', 1);
if (parts is not null)
{
return cast(parts[1] as integer);
}
return NULL;
};
create function
DB.DBA.PROJ_ACT_IRI_INV_3 (in proj_act_iri varchar) returns date
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (proj_act_iri,
'http://localhost:8890/db2sample/proj_act/%s_%s_%s#this', 1);
if (parts is not null)
{
return cast(parts[2] as date);
}
return NULL;
};
create function DB.DBA.EMP_PROJ_ACT_IRI (
in emp_no varchar,
in proj_no varchar,
in act_no integer,
in emp_start_date date
) returns varchar
{
declare _act_no, _datetime, _date any;
_act_no := cast(act_no as varchar);
_datetime := cast(emp_start_date as varchar);
_date := left(_datetime, 10);
return sprintf(
'http://localhost:8890/db2sample/emp_proj_act/%s_%s_%s_%s#this',
emp_no, proj_no, _act_no, _date);
};
create function
DB.DBA.EMP_PROJ_ACT_IRI_INV_1 (in emp_proj_act_iri varchar) returns varchar
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (emp_proj_act_iri,
'http://localhost:8890/db2sample/emp_proj_act/%s_%s_%s_%s#this', 1);
if (parts is not null)
{
return parts[0];
}
return NULL;
};
create function
DB.DBA.EMP_PROJ_ACT_IRI_INV_2 (in emp_proj_act_iri varchar) returns varchar
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (emp_proj_act_iri,
'http://localhost:8890/db2sample/emp_proj_act/%s_%s_%s_%s#this', 1);
if (parts is not null)
{
return parts[1];
}
return NULL;
};
create function
DB.DBA.EMP_PROJ_ACT_IRI_INV_3 (in emp_proj_act_iri varchar) returns integer
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (emp_proj_act_iri,
'http://localhost:8890/db2sample/emp_proj_act/%s_%s_%s_%s#this', 1);
if (parts is not null)
{
return cast(parts[2] as integer);
}
return NULL;
};
create function
DB.DBA.EMP_PROJ_ACT_IRI_INV_4 (in emp_proj_act_iri varchar) returns date
{
declare exit handler for sqlstate '*' { return NULL; };
declare parts any;
parts := sprintf_inverse (emp_proj_act_iri,
'http://localhost:8890/db2sample/emp_proj_act/%s_%s_%s_%s#this', 1);
if (parts is not null)
{
return cast(parts[3] as date);
}
return NULL;
};
grant execute on DB.DBA.PROJ_ACT_IRI to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.PROJ_ACT_IRI_INV_1 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.PROJ_ACT_IRI_INV_2 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.PROJ_ACT_IRI_INV_3 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.EMP_PROJ_ACT_IRI to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.EMP_PROJ_ACT_IRI_INV_1 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.EMP_PROJ_ACT_IRI_INV_2 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.EMP_PROJ_ACT_IRI_INV_3 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.EMP_PROJ_ACT_IRI_INV_4 to "SPARQL", "SPARQL_UPDATE";
SPARQL drop graph <http://localhost:8890/schemas/db2sample> ;
SPARQL drop graph <http://localhost:8890/db2sample> ;
SPARQL drop quad map virtrdf:db2sample ;
--------------------------
-- RDFS class definitions
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix opl: <http://localhost:8890/schemas/db2sample/> .
opl:Act a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "Act" ;
rdfs:comment "Activity" .
# ACTNO SMALLINT PRIMARY KEY
opl:act_no a rdf:Property ;
rdfs:domain opl:Act ;
rdfs:range xsd:integer ;
rdfs:label "Activity number" .
# ACTKWD VARCHAR(6)
opl:act_kwd a rdf:Property ;
rdfs:domain opl:Act ;
rdfs:range xsd:string ;
rdfs:label "Activity keyword" .
# ACTDESC VARCHAR(20)
opl:act_desc a rdf:Property ;
rdfs:domain opl:Act ;
rdfs:range xsd:string ;
rdfs:label "Activity description" .
#####
opl:Department a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "Department" ;
rdfs:comment "Department" .
# DEPTNO VARCHAR(3) PRIMARY KEY
opl:dept_no a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range xsd:string ;
rdfs:label "Department number" .
# DEPTNAME VARCHAR(36)
opl:dept_name a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range xsd:string ;
rdfs:label "Department name" .
# MGRNO CHAR(6)
opl:dept_manager a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range xsd:Employee ;
rdfs:label "Department manager" .
# ADMRDEPT CHAR(3)
opl:supervising_dept a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range opl:Department ;
rdfs:label "Department reported to" .
# LOCATION CHAR(6)
opl:location a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range xsd:string ;
rdfs:label "Location" .
opl:employee_collection a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range opl:Employee ;
rdfs:label "Department employees" .
opl:dept_project_collection a rdf:Property ;
rdfs:domain opl:Department ;
rdfs:range opl:Project ;
rdfs:label "Department projects" .
#####
opl:Employee a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "Employee" ;
rdfs:comment "Employee" .
# EMPNO VARCHAR(6) PRIMARY KEY
opl:emp_no a rdf:Property ;
rdfs:domain opl:Employee;
rdfs:range xsd:string ;
rdfs:label "Employee number" .
# FIRSTNME VARCHAR(12)
opl:first_name a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:string ;
rdfs:label "First name" .
# MIDINIT VARCHAR(1)
opl:middle_initial a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:string ;
rdfs:label "Middle initial" .
# LASTNAME VARCHAR(15)
opl:last_name a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:string ;
rdfs:label "Last name" .
# WORKDEPT VARCHAR(3)
opl:work_dept a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range opl:Department ;
rdfs:label "Work department" .
# PHONENO VARCHAR(4)
opl:phone_no a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:string ;
rdfs:label "Phone number" .
# HIREDATE DATE
opl:hire_date a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:date ;
rdfs:label "Hire date" .
# JOB VARCHAR(8)
opl:job a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:string ;
rdfs:label "Job" .
# EDLEVEL SMALLINT
opl:education_level a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:integer ;
rdfs:label "Education level" .
# SEX VARCHAR(1)
opl:gender a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:string ;
rdfs:label "Gender" .
# BIRTHDATE DATE
opl:date_of_birth a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:date ;
rdfs:label "Date of birth" .
# SALARY DECIMAL(9,2)
opl:salary a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:decimal ;
rdfs:label "Salary" .
# BONUS DECIMAL(9,2)
opl:bonus a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:decimal ;
rdfs:label "Bonus" .
# COMM DECIMAL(9,2)
opl:commission a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range xsd:decimal ;
rdfs:label "Commission" .
opl:resume_collection a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range opl:EmployeeResume ;
rdfs:label "Employee resumes" .
opl:projects_responsible_for_collection a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range opl:Project ;
rdfs:label "responsible for project" .
opl:activity_collection a rdf:Property ;
rdfs:domain opl:Employee ;
rdfs:range opl:EmpProjAct ;
rdfs:label "project activities" .
#####
opl:EmpProjAct a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "EmpProjAct" ;
rdfs:comment "Employee project activity" .
# EMPNO VARCHAR(6) PRIMARY KEY
opl:epa_emp_no a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range xsd:string ;
rdfs:label "Employee number" .
# PROJNO VARCHAR(6) PRIMARY KEY
opl:epa_proj_no a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range xsd:string ;
rdfs:label "Project number" .
# ACTNO SMALLINT PRIMARY KEY
opl:epa_act_no a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range xsd:string ;
rdfs:label "Activity number" .
# EMSTDATE DATE PRIMARY KEY
opl:emp_start_date a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range xsd:date ;
rdfs:label "Employee activity start date" .
# EMPTIME DECIMAL(5,2)
opl:emp_time a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range xsd:decimal ;
rdfs:label "Employee time" .
# EMENDATE DATE PRIMARY KEY
opl:emp_end_date a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range xsd:date ;
rdfs:label "Employee activity end date" .
opl:assigned_to a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range opl:Employee ;
rdfs:label "Assigned to" .
opl:project_activity a rdf:Property ;
rdfs:domain opl:EmpProjAct ;
rdfs:range opl:ProjAct ;
rdfs:label "Project activity" .
#####
opl:EmployeeResume a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "EmployeeResume" ;
rdfs:comment "Employee resume" .
# EMPNO VARCHAR(6) PRIMARY KEY
opl:er_emp_no a rdf:Property ;
rdfs:domain opl:EmployeeResume ;
rdfs:range xsd:string ;
rdfs:label "Employee number" .
# RESUME_FORMAT VARCHAR(10) PRIMARY KEY
opl:resume_format a rdf:Property ;
rdfs:domain opl:EmployeeResume ;
rdfs:range xsd:string ;
rdfs:label "Resume format" .
# RESUME VARCHAR(5120)
opl:resume a rdf:Property ;
rdfs:domain opl:EmployeeResume ;
rdfs:range xsd:string ;
rdfs:label "Resume" .
opl:resume_of a rdf:Property ;
rdfs:domain opl:EmployeeResume ;
rdfs:range opl:Employee ;
rdfs:label "Resume subject" .
#####
opl:ProjAct a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "ProjAct" ;
rdfs:comment "Project activity" .
# PROJNO VARCHAR(6) PRIMARY KEY
opl:pa_proj_no a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range xsd:string ;
rdfs:label "Project number" .
# ACTNO SMALLINT PRIMARY KEY
opl:pa_act_no a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range xsd:string ;
rdfs:label "Activity number" .
# ACSTDATE DATE PRIMARY KEY
opl:ac_st_date a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range xsd:date ;
rdfs:label "Activity start date" .
# ACSTAFF DECIMAL(5,2)
opl:ac_staff a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range xsd:decimal ;
rdfs:label "Acstaff" .
# ACENDATE DATE
opl:ac_en_date a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range xsd:date ;
rdfs:label "Activity end date" .
opl:project a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range opl:Project ;
rdfs:label "Project" .
opl:activity a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range opl:Act ;
rdfs:label "Activity" .
opl:employee_activity_collection a rdf:Property ;
rdfs:domain opl:ProjAct ;
rdfs:range opl:EmpProjAct ;
rdfs:label "Employee activity collection" .
#####
opl:Project a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/db2sample> ;
rdfs:label "Project" ;
rdfs:comment "Project" .
# PROJNO VARCHAR(6) PRIMARY KEY
opl:proj_no a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range xsd:string ;
rdfs:label "Project number" .
# PROJNAME VARCHAR(24)
opl:proj_name a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range xsd:string ;
rdfs:label "Project name" .
# DEPTNO CHAR(3)
opl:is_project_of_department a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range opl:Department ;
rdfs:label "is project of department" .
# RESPEMP VARCHAR(6)
opl:resp_emp a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range opl:Employee ;
rdfs:label "Employee responsible" .
# PRSTAFF DECIMAL(5,2)
opl:pr_staff a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range xsd:decimal ;
rdfs:label "PrStaff" .
# PRSTDATE DATE
opl:pr_st_date a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range xsd:date ;
rdfs:label "Project start date" .
# PRENDATE DATE
opl:pr_en_date a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range xsd:date ;
rdfs:label "Project end date" .
# MAJPROJ VARCHAR(6)
opl:maj_proj a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range xsd:string ;
rdfs:label "MajProj" .
opl:proj_activity_collection a rdf:Property ;
rdfs:domain opl:Project ;
rdfs:range opl:ProjAct ;
rdfs:label "Project activities" .
', '', 'http://localhost:8890/schemas/db2sample', 0);
--------------------------
SPARQL
prefix opl: <http://localhost:8890/schemas/db2sample/>
create iri class
<http://localhost:8890/schemas/db2sample/act_iri>
"http://localhost:8890/db2sample/act/%d#this"
(
in act_no integer not null
) .
create iri class
<http://localhost:8890/schemas/db2sample/department_iri>
"http://localhost:8890/db2sample/department/%s#this"
(
in dept_no varchar not null
) .
create iri class
<http://localhost:8890/schemas/db2sample/employee_iri>
"http://localhost:8890/db2sample/employee/%s#this"
(
in emp_no varchar not null
) .
create iri class opl:emp_proj_act_iri using
function DB.DBA.EMP_PROJ_ACT_IRI (
in emp_no varchar,
in proj_no varchar,
in act_no integer,
in emp_start_date date
) returns varchar,
function DB.DBA.EMP_PROJ_ACT_IRI_INV_1 (in emp_proj_act_iri varchar)
returns varchar ,
function DB.DBA.EMP_PROJ_ACT_IRI_INV_2 (in emp_proj_act_iri varchar)
returns varchar ,
function DB.DBA.EMP_PROJ_ACT_IRI_INV_3 (in emp_proj_act_iri varchar)
returns integer ,
function DB.DBA.EMP_PROJ_ACT_IRI_INV_4 (in emp_proj_act_iri varchar)
returns date
option (bijection, returns
"http://localhost:8890/db2sample/emp_proj_act/%s_%s_%s_%s#this")
.
create iri class
<http://localhost:8890/schemas/db2sample/employee_resume_iri>
"http://localhost:8890/db2sample/employee_resume/%s_%s#this"
(
in emp_no varchar not null,
in resume_format varchar not null
) .
create iri class opl:proj_act_iri using
function DB.DBA.PROJ_ACT_IRI (
in proj_no varchar,
in act_no integer,
in ac_st_date date
) returns varchar,
function DB.DBA.PROJ_ACT_IRI_INV_1 (in proj_act_iri varchar)
returns varchar ,
function DB.DBA.PROJ_ACT_IRI_INV_2 (in proj_act_iri varchar)
returns integer ,
function DB.DBA.PROJ_ACT_IRI_INV_3 (in proj_act_iri varchar)
returns date
option (bijection, returns
"http://localhost:8890/db2sample/proj_act/%s_%s_%s#this")
.
create iri class
<http://localhost:8890/schemas/db2sample/project_iri>
"http://localhost:8890/db2sample/project/%s#this"
(
in proj_no varchar not null
) .
;
SPARQL
prefix opl: <http://localhost:8890/schemas/db2sample/>
alter quad storage virtrdf:DefaultQuadStorage
from DB.db2sample.ACT as act_tbl
from DB.db2sample.DEPARTMENT as dept_tbl
from DB.db2sample.EMPLOYEE as emp_tbl
from DB.db2sample.EMPPROJACT as emp_proj_act_tbl
from DB.db2sample.EMP_RESUME as emp_resume_tbl
from DB.db2sample.PROJACT as proj_act_tbl
from DB.db2sample.PROJECT as project_tbl
{
create virtrdf:db2sample as
graph <http://localhost:8890/db2sample>
{
opl:act_iri(act_tbl.ACTNO) a opl:Act
as virtrdf:act_id ;
opl:act_no act_tbl.ACTNO
as virtrdf:act_act_no ;
opl:act_kwd act_tbl.ACTKWD
as virtrdf:act_act_kwd ;
opl:act_desc act_tbl.ACTDESC
as virtrdf:act_act_desc .
opl:department_iri(dept_tbl.DEPTNO) a opl:Department
as virtrdf:dept_id ;
opl:dept_no dept_tbl.DEPTNO
as virtrdf:dept_dept_no ;
opl:dept_name dept_tbl.DEPTNAME
as virtrdf:dept_dept_name ;
opl:dept_manager opl:employee_iri(dept_tbl.MGRNO)
as virtrdf:dept_mgr_no ;
opl:supervising_dept opl:department_iri(dept_tbl.ADMRDEPT)
as virtrdf:dept_supervising_dept ;
opl:location dept_tbl.LOCATION
as virtrdf:dept_location ;
opl:employee_collection opl:employee_iri(emp_tbl.EMPNO)
where (^{emp_tbl.}^.WORKDEPT = ^{dept_tbl.}^.DEPTNO)
as virtrdf:dept_employee_collection ;
opl:dept_project_collection opl:project_iri(project_tbl.PROJNO)
where (^{project_tbl.}^.DEPTNO = ^{dept_tbl.}^.DEPTNO)
as virtrdf:dept_project_collection .
opl:employee_iri(emp_tbl.EMPNO) a opl:Employee
as virtrdf:employee_id ;
opl:emp_no emp_tbl.EMPNO
as virtrdf:employee_emp_no ;
opl:first_name emp_tbl.FIRSTNME
as virtrdf:employee_first_name ;
opl:middle_initial emp_tbl.MIDINIT
as virtrdf:employee_middle_initial ;
opl:last_name emp_tbl.LASTNAME
as virtrdf:employee_last_name ;
opl:work_dept opl:department_iri(emp_tbl.WORKDEPT)
as virtrdf:employee_work_dept ;
opl:phone_no emp_tbl.PHONENO
as virtrdf:employee_phone_no ;
opl:hire_date emp_tbl.HIREDATE
as virtrdf:employee_hire_date ;
opl:job emp_tbl.JOB
as virtrdf:employee_job ;
opl:education_level emp_tbl.EDLEVEL
as virtrdf:employee_education_level ;
opl:gender emp_tbl.SEX
as virtrdf:employee_gender ;
opl:date_of_birth emp_tbl.BIRTHDATE
as virtrdf:employee_date_of_birth ;
opl:salary emp_tbl.SALARY
as virtrdf:employee_salary ;
opl:bonus emp_tbl.BONUS
as virtrdf:employee_bonus ;
opl:commission emp_tbl.COMM
as virtrdf:employee_commission ;
opl:resume_collection opl:employee_resume_iri(
emp_resume_tbl.EMPNO,
emp_resume_tbl.RESUME_FORMAT
)
where (^{emp_tbl.}^.EMPNO = ^{emp_resume_tbl.}^.EMPNO)
as virtrdf:employee_resume_collection ;
opl:projects_responsible_for_collection
opl:project_iri(project_tbl.PROJNO)
where (^{project_tbl.}^.RESPEMP = ^{emp_tbl.}^.EMPNO)
as virtrdf:employee_projects_responsible_for_collection ;
opl:activity_collection opl:emp_proj_act_iri(
emp_proj_act_tbl.EMPNO,
emp_proj_act_tbl.PROJNO,
emp_proj_act_tbl.ACTNO,
emp_proj_act_tbl.EMSTDATE
)
where (^{emp_tbl.}^.EMPNO = ^{emp_proj_act_tbl.}^.EMPNO)
as virtrdf:employee_activity_collection .
opl:emp_proj_act_iri(
emp_proj_act_tbl.EMPNO,
emp_proj_act_tbl.PROJNO,
emp_proj_act_tbl.ACTNO,
emp_proj_act_tbl.EMSTDATE
) a opl:EmpProjAct
as virtrdf:empprojact_id ;
opl:epa_emp_no emp_proj_act_tbl.EMPNO
as virtrdf:empprojact_emp_no ;
opl:epa_proj_no emp_proj_act_tbl.PROJNO
as virtrdf:empprojact_proj_no ;
opl:epa_act_no emp_proj_act_tbl.ACTNO
as virtrdf:empprojact_act_no ;
opl:emp_start_date emp_proj_act_tbl.EMSTDATE
as virtrdf:empprojact_emp_start_date ;
opl:emp_time emp_proj_act_tbl.EMPTIME
as virtrdf:empprojact_emp_time ;
opl:emp_end_date emp_proj_act_tbl.EMENDATE
as virtrdf:empprojact_emp_end_date ;
opl:assigned_to opl:employee_iri(emp_proj_act_tbl.EMPNO)
as virtrdf:empprojact_assigned_to ;
opl:project_activity opl:proj_act_iri(
emp_proj_act_tbl.PROJNO,
emp_proj_act_tbl.ACTNO,
emp_proj_act_tbl.EMSTDATE
)
as virtrdf:empprojact_project_activity .
opl:employee_resume_iri(
emp_resume_tbl.EMPNO,
emp_resume_tbl.RESUME_FORMAT
) a opl:EmployeeResume
as virtrdf:employee_resume_id ;
opl:er_emp_no emp_resume_tbl.EMPNO
as virtrdf:employee_resume_emp_no ;
opl:resume_format emp_resume_tbl.RESUME_FORMAT
as virtrdf:employee_resume_resume_format ;
opl:resume emp_resume_tbl.RESUME
as virtrdf:employee_resume_resume ;
opl:resume_of opl:employee_iri(emp_resume_tbl.EMPNO)
as virtrdf:employee_resume_resume_of .
opl:proj_act_iri(
proj_act_tbl.PROJNO,
proj_act_tbl.ACTNO,
proj_act_tbl.ACSTDATE
) a opl:ProjAct
as virtrdf:projact_id;
opl:pa_proj_no proj_act_tbl.PROJNO
as virtrdf:projact_proj_no ;
opl:pa_act_no proj_act_tbl.ACTNO
as virtrdf:projact_act_no ;
opl:ac_st_date proj_act_tbl.ACSTDATE
as virtrdf:projact_ac_st_date ;
opl:ac_staff proj_act_tbl.ACSTAFF
as virtrdf:projact_ac_staff ;
opl:ac_en_date proj_act_tbl.ACENDATE
as virtrdf:projact_ac_en_date ;
opl:project opl:project_iri(proj_act_tbl.PROJNO)
as virtrdf:projact_project ;
opl:activity opl:act_iri(proj_act_tbl.ACTNO)
as virtrdf:projact_activity ;
opl:employee_activity_collection opl:emp_proj_act_iri(
emp_proj_act_tbl.EMPNO,
emp_proj_act_tbl.PROJNO,
emp_proj_act_tbl.ACTNO,
emp_proj_act_tbl.EMSTDATE
)
where (
^{proj_act_tbl.}^.PROJNO = ^{emp_proj_act_tbl.}^.PROJNO AND
^{proj_act_tbl.}^.ACTNO = ^{emp_proj_act_tbl.}^.ACTNO AND
^{proj_act_tbl.}^.ACSTDATE = ^{emp_proj_act_tbl.}^.EMSTDATE
)
as virtrdf:project_employee_activity_collection .
opl:project_iri(project_tbl.PROJNO) a opl:Project
as virtrdf:project_id ;
opl:proj_no project_tbl.PROJNO
as virtrdf:project_proj_no ;
opl:proj_name project_tbl.PROJNAME
as virtrdf:project_proj_name ;
opl:is_project_of_department opl:department_iri(project_tbl.DEPTNO)
as virtrdf:project_is_project_of_department ;
opl:resp_emp opl:employee_iri(project_tbl.RESPEMP)
as virtrdf:project_resp_emp ;
opl:pr_staff project_tbl.PRSTAFF
as virtrdf:project_pr_staff ;
opl:pr_st_date project_tbl.PRSTDATE
as virtrdf:project_pr_st_date ;
opl:pr_en_date project_tbl.PRENDATE
as virtrdf:project_pr_en_date ;
opl:maj_proj project_tbl.MAJPROJ
as virtrdf:project_maj_proj ;
opl:proj_activity_collection opl:proj_act_iri(
proj_act_tbl.PROJNO,
proj_act_tbl.ACTNO,
proj_act_tbl.ACSTDATE
)
where (^{project_tbl.}^.PROJNO = ^{proj_act_tbl.}^.PROJNO)
as virtrdf:project_activity_collection .
} .
} .
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'db2sample_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'db2sample_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'db2sample_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/localhost:8890%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'db2sample_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/db2sample%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'db2sample_rule_list1',
1,
vector (
'db2sample_rule1',
'db2sample_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/db2sample');
VHOST_DEFINE (
lpath=>'/db2sample',
ppath=>'/DAV/db2sample/',
vsp_user=>'dba',
is_dav=>1,
is_brws=>0,
opts=>vector ('url_rewrite', 'db2sample_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'db2sample_schema_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'db2sample_schema_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'db2sample_schema_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/localhost:8890%U',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'db2sample_schema_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/db2sample%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'db2sample_schema_rule_list1',
1,
vector (
'db2sample_schema_rule1',
'db2sample_schema_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schemas/db2sample');
VHOST_DEFINE (
lpath=>'/schemas/db2sample',
ppath=>'/DAV/schemas_db2sample/',
vsp_user=>'dba',
is_dav=>1,
is_brws=>0,
opts=>vector ('url_rewrite', 'db2sample_schema_rule_list1')
);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterprinf">
<title>Informix using demonstration 'Stores' database</title>
<programlisting><![CDATA[
DB..vd_remote_data_source ('inf10_stores_demo_rdf', '', '<uid>','<pwd>');
ATTACH TABLE "informix"."call_type" PRIMARY KEY ("call_code") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."call_type" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."catalog" PRIMARY KEY ("catalog_num") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."catalog" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."cust_calls" PRIMARY KEY ("customer_num", "call_dtime") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."cust_calls" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."customer" PRIMARY KEY ("customer_num") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."customer" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."items" PRIMARY KEY ("item_num", "order_num") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."items" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."manufact" PRIMARY KEY ("manu_code") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."manufact" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."msgs" PRIMARY KEY ("lang", "number", "message") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."msgs" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."orders" PRIMARY KEY ("order_num") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."orders" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."state" PRIMARY KEY ("code", "sname") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."state" FROM 'inf10_stores_demo_rdf';
ATTACH TABLE "informix"."stock" PRIMARY KEY ("stock_num", "manu_code") AS "stores_demo_rdf"."inf10_stores_demo_rdf"."stock" FROM 'inf10_stores_demo_rdf';
COMMIT WORK;
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.items TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.catalog TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.msgs TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.state TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.orders TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.stock TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.customer TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.call_type TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.manufact TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON stores_demo_rdf.inf10_stores_demo_rdf.cust_calls TO "SPARQL", "SPARQL_UPDATE";
GRANT SPARQL_UPDATE to "SPARQL";
create function DB.DBA.CUST_CALLS_IRI (in customer_num integer, in call_dtime datetime) returns varchar
{
declare _call_dtime any;
_call_dtime := cast(call_dtime as varchar);
return sprintf('http://localhost:8890/informix/stores_demo/cust_calls/%d_%U#this', customer_num, _call_dtime);
};
create function DB.DBA.CUST_CALLS_IRI_INV_1 (in cust_calls_iri varchar) returns integer
{
declare parts any;
parts := sprintf_inverse(cust_calls_iri, 'http://localhost:8890/informix/stores_demo/cust_calls/%d_%U#this', 1);
if (parts is not null)
{
return parts[0];
}
return NULL;
};
create function DB.DBA.CUST_CALLS_IRI_INV_2 (in cust_calls_iri varchar) returns datetime
{
declare parts any;
parts := sprintf_inverse(cust_calls_iri, 'http://localhost:8890/informix/stores_demo/cust_calls/%d_%U#this', 1);
if (parts is not null)
{
return parts[1];
}
return NULL;
};
grant execute on DB.DBA.CUST_CALLS_IRI to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.CUST_CALLS_IRI_INV_1 to "SPARQL", "SPARQL_UPDATE";
grant execute on DB.DBA.CUST_CALLS_IRI_INV_2 to "SPARQL", "SPARQL_UPDATE";
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix items: <http://localhost:8890/schemas/informix/stores_demo/items/> .
@prefix catalog: <http://localhost:8890/schemas/informix/stores_demo/catalog/> .
@prefix stock: <http://localhost:8890/schemas/informix/stores_demo/stock/> .
@prefix msgs: <http://localhost:8890/schemas/informix/stores_demo/msgs/> .
@prefix state: <http://localhost:8890/schemas/informix/stores_demo/state/> .
@prefix orders: <http://localhost:8890/schemas/informix/stores_demo/orders/> .
@prefix manuf: <http://localhost:8890/schemas/informix/stores_demo/manufact/> .
@prefix cust: <http://localhost:8890/schemas/informix/stores_demo/customer/> .
@prefix callt: <http://localhost:8890/schemas/informix/stores_demo/call_type/> .
@prefix custc: <http://localhost:8890/schemas/informix/stores_demo/cust_calls/> .
items:Items a rdfs:Class ;
rdfs:label "Items" ;
rdfs:comment "Informix SD items table" .
items:item_num a rdf:Property ;
rdfs:domain items:Items ;
rdfs:range xsd:integer ;
rdfs:label "ITEM NUMBER" .
items:quantity a rdf:Property ;
rdfs:domain items:Items ;
rdfs:range xsd:integer ;
rdfs:label "QUANTITY" .
items:total_price a rdf:Property ;
rdfs:domain items:Items ;
rdfs:range xsd:decimal ;
rdfs:label "TOTAL PRICE" .
items:order_num_fk a rdf:Property ;
rdfs:domain items:Items ;
rdfs:range orders:Orders ;
rdfs:label "ORDER NUMBER" .
items:stock_num_fk a rdf:Property ;
rdfs:domain items:Items ;
rdfs:range stock:Stock ;
rdfs:label "STOCK NUMBER" .
items:manu_code_fk a rdf:Property ;
rdfs:domain items:Items ;
rdfs:range stock:Stock ;
rdfs:label "MANUAL CODE" .
catalog:Catalog a rdfs:Class ;
rdfs:label "Catalog" ;
rdfs:comment "Informix SD catalog table" .
catalog:manu_code a rdf:Property ;
rdfs:domain catalog:Catalog ;
rdfs:range xsd:integer ;
rdfs:label "MANUAL CODE" .
catalog:cat_descr a rdf:Property ;
rdfs:domain catalog:Catalog ;
rdfs:range xsd:string ;
rdfs:label "CATALOG DESCRIPTION" .
catalog:cat_picture a rdf:Property ;
rdfs:domain catalog:Catalog ;
rdfs:range xsd:byte ;
rdfs:label "CATALOG PICTURE" .
catalog:cat_advert a rdf:Property ;
rdfs:domain catalog:Catalog ;
rdfs:range xsd:string ;
rdfs:label "CATALOG ADVERT" .
catalog:catalog_num_fk a rdf:Property ;
rdfs:domain catalog:Catalog ;
rdfs:range stock:Stock ;
rdfs:label "CATALOG NUMBER" .
catalog:stock_num_fk a rdf:Property ;
rdfs:domain catalog:Catalog ;
rdfs:range stock:Stock ;
rdfs:label "STOCK NUMBER" .
msgs:Msgs a rdfs:Class ;
rdfs:label "Msgs" ;
rdfs:comment "Informix SD msgs table" .
msgs:lang a rdf:Property ;
rdfs:domain msgs:Msgs ;
rdfs:range xsd:string ;
rdfs:label "LANGUAGE" .
msgs:number a rdf:Property ;
rdfs:domain msgs:Msgs ;
rdfs:range xsd:integer ;
rdfs:label "NUMBER" .
msgs:message a rdf:Property ;
rdfs:domain msgs:Msgs ;
rdfs:range xsd:string ;
rdfs:label "MESSAGE" .
state:State a rdfs:Class ;
rdfs:label "State" ;
rdfs:comment "Informix SD state table" .
state:code a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "STATE CODE" .
state:sname a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "STATE NAME" .
orders:Orders a rdfs:Class ;
rdfs:label "Orders" ;
rdfs:comment "Informix SD orders table" .
orders:order_num a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:integer ;
rdfs:label "ORDER NUMBER" .
orders:order_date a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:date;
rdfs:label "ORDER DATE" .
orders:ship_instruct a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:string ;
rdfs:label "SHIPPING INSTRUCTION" .
orders:backlog a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:string ;
rdfs:label "BACKLOG" .
orders:po_num a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:string ;
rdfs:label "PURCHASE ORDER NUMBER" .
orders:ship_date a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:date ;
rdfs:label "SHIPPING DATE" .
orders:ship_weight a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:decimal ;
rdfs:label "SHIPPING WEIGHT" .
orders:ship_charge a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:decimal ;
rdfs:label "SHIPPING CHARGE" .
orders:paid_date a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range xsd:date ;
rdfs:label "PAID DATE" .
orders:customer_num_fk a rdf:Property ;
rdfs:domain orders:Orders ;
rdfs:range cust:Customer ;
rdfs:label "CUSTOMER NUMBER" .
stock:Stock a rdfs:Class ;
rdfs:label "Stock" ;
rdfs:comment "Informix SD stock table" .
stock:stock_num a rdf:Property ;
rdfs:domain stock:Stock ;
rdfs:range xsd:integer ;
rdfs:label "STOCK NUMBER" .
stock:description a rdf:Property ;
rdfs:domain stock:Stock ;
rdfs:range xsd:string ;
rdfs:label "DESCRIPTION" .
stock:unit_price a rdf:Property ;
rdfs:domain stock:Stock ;
rdfs:range xsd:decimal ;
rdfs:label "UNIT PRICE" .
stock:unit a rdf:Property ;
rdfs:domain stock:Stock ;
rdfs:range xsd:string ;
rdfs:label "UNIT" .
stock:unit_descr a rdf:Property ;
rdfs:domain stock:Stock ;
rdfs:range xsd:decimal ;
rdfs:label "UNIT DESCRIPTION" .
stock:manu_code_fk a rdf:Property ;
rdfs:domain stock:Stock ;
rdfs:range manuf:Manufact ;
rdfs:label "MANUAL CODE" .
cust:Customer a rdfs:Class ;
rdfs:label "Customer" ;
rdfs:comment "Informix SD customer table" .
cust:customer_num a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:integer ;
rdfs:label "CUSTOMER NUMBER" .
cust:fname a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "FIRST NAME" .
cust:lname a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "LAST NAME" .
cust:company a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "COMPANY" .
cust:address1 a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "ADDRESS1" .
cust:address2 a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "ADDRESS2" .
cust:city a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "CITY" .
cust:state a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "STATE" .
cust:zipcode a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "ZIP CODE" .
cust:phone a rdf:Property ;
rdfs:domain cust:Customer ;
rdfs:range xsd:string ;
rdfs:label "PHONE NUMBER" .
callt:Call_type a rdfs:Class ;
rdfs:label "Call_type" ;
rdfs:comment "Informix SD call_type table" .
callt:call_code a rdf:Property ;
rdfs:domain callt:Call_type ;
rdfs:range xsd:string ;
rdfs:label "CALL CODE" .
callt:code_descr a rdf:Property ;
rdfs:domain callt:Call_type ;
rdfs:range xsd:string ;
rdfs:label "CODE DESCRIPTION" .
manuf:Manufact a rdfs:Class ;
rdfs:label "Manufact" ;
rdfs:comment "Informix SD manufact table" .
manuf:manu_code a rdf:Property ;
rdfs:domain manuf:Manufact ;
rdfs:range xsd:string ;
rdfs:label "MANUFACTURE CODE" .
manuf:manu_name a rdf:Property ;
rdfs:domain manuf:Manufact ;
rdfs:range xsd:string ;
rdfs:label "MANUFACTURE NAME" .
manuf:lead_time a rdf:Property ;
rdfs:domain manuf:Manufact ;
rdfs:range xsd:integer ;
rdfs:label "LEAD TIME" .
custc:Cust_calls a rdfs:Class ;
rdfs:label "Cust_calls" ;
rdfs:comment "Informix SD cust_calls table" .
custc:call_dtime a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range xsd:datetime ;
rdfs:label "CALL TIME" .
custc:user_id a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range xsd:string ;
rdfs:label "USER ID" .
custc:call_descr a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range xsd:string ;
rdfs:label "CALL DESCRIPTION" .
custc:res_dtime a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range xsd:datetime ;
rdfs:label "RES TIME" .
custc:res_descr a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range xsd:string ;
rdfs:label "RES DESCRIPTION" .
custc:customer_num_fk a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range cust:Customer ;
rdfs:label "CUSTOMER NUM" .
custc:call_code_fk a rdf:Property ;
rdfs:domain manuf:Cust_calls ;
rdfs:range callt:Call_type ;
rdfs:label "CALL CODE" .
', '', 'http://localhost:8890/schemas/informix/stores_demo', 0);
----------- Create IRI Classes -------------
SPARQL
prefix items: <http://localhost:8890/schemas/informix/stores_demo/items/>
prefix catalog: <http://localhost:8890/schemas/informix/stores_demo/catalog/>
prefix stock: <http://localhost:8890/schemas/informix/stores_demo/stock/>
prefix msgs: <http://localhost:8890/schemas/informix/stores_demo/msgs/>
prefix state: <http://localhost:8890/schemas/informix/stores_demo/state/>
prefix orders: <http://localhost:8890/schemas/informix/stores_demo/orders/>
prefix manuf: <http://localhost:8890/schemas/informix/stores_demo/manufact/>
prefix cust: <http://localhost:8890/schemas/informix/stores_demo/customer/>
prefix callt: <http://localhost:8890/schemas/informix/stores_demo/call_type/>
prefix custc: <http://localhost:8890/schemas/informix/stores_demo/cust_calls/>
create iri class items:items_iri
"http://localhost:8890/informix/stores_demo/items/%d_%d#this"
(in item_num integer not null, in order_num integer not null) .
create iri class catalog:catalog_iri
"http://localhost:8890/informix/stores_demo/catalog/%d#this"
(in catalog_num integer not null) .
create iri class msgs:msgs_iri
"http://localhost:8890/informix/stores_demo/msgs/%U_%d_%U#this"
(in _lang varchar not null, in number integer not null, in message varchar not null) .
create iri class state:state_iri
"http://localhost:8890/informix/stores_demo/state/%U#this"
(in code varchar not null) .
create iri class orders:orders_iri
"http://localhost:8890/informix/stores_demo/orders/%d#this"
(in order_num integer not null) .
create iri class stock:stock_iri
"http://localhost:8890/informix/stores_demo/stock/%d_%U#this"
(in stock_num integer not null, in manu_code varchar not null) .
create iri class cust:customer_iri
"http://localhost:8890/informix/stores_demo/customer/%d#this"
(in customer_num integer not null) .
create iri class callt:call_type_iri
"http://localhost:8890/informix/stores_demo/call_type/%U#this"
(in call_code varchar not null) .
create iri class manuf:manufact_iri
"http://localhost:8890/informix/stores_demo/manufact/%U#this"
(in manu_code varchar not null) .
create iri class custc:cust_calls_iri using
function DB.DBA.CUST_CALLS_IRI (in customer_num integer, in call_dtime datetime) returns varchar,
function DB.DBA.CUST_CALLS_IRI_INV_1 (in cust_calls_iri varchar) returns integer,
function DB.DBA.CUST_CALLS_IRI_INV_2 (in cust_calls_iri varchar) returns datetime .
;
------------- Create Quad Store ------------------------------------
SPARQL
prefix items: <http://localhost:8890/schemas/informix/stores_demo/items/>
prefix catalog: <http://localhost:8890/schemas/informix/stores_demo/catalog/>
prefix stock: <http://localhost:8890/schemas/informix/stores_demo/stock/>
prefix msgs: <http://localhost:8890/schemas/informix/stores_demo/msgs/>
prefix state: <http://localhost:8890/schemas/informix/stores_demo/state/>
prefix orders: <http://localhost:8890/schemas/informix/stores_demo/orders/>
prefix manuf: <http://localhost:8890/schemas/informix/stores_demo/manufact/>
prefix cust: <http://localhost:8890/schemas/informix/stores_demo/customer/>
prefix callt: <http://localhost:8890/schemas/informix/stores_demo/call_type/>
prefix custc: <http://localhost:8890/schemas/informix/stores_demo/cust_calls/>
alter quad storage virtrdf:DefaultQuadStorage
from stores_demo_rdf.inf10_stores_demo_rdf.items as items_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.catalog as catalog_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.msgs as msgs_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.state as state_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.orders as orders_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.stock as stock_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.customer as customer_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.call_type as call_type_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.manufact as manufact_tbl
from stores_demo_rdf.inf10_stores_demo_rdf.cust_calls as cust_calls_tbl
{
create virtrdf:informix_stores_demo as graph <http://localhost:8890/informix/stores_demo>
{
items:items_iri (items_tbl.item_num, items_tbl.order_num) a items:Items as virtrdf:items_pk ;
items:item_num items_tbl.item_num as virtrdf:items_item_num ;
items:order_num items_tbl.order_num as virtrdf:items_order_num ;
items:stock_num items_tbl.stock_num as virtrdf:items_stock_num ;
items:manu_code items_tbl.manu_code as virtrdf:items_manu_code ;
items:quantity items_tbl.quantity as virtrdf:items_quantity ;
items:total_price items_tbl.total_price as virtrdf:items_total_price ;
items:from_order orders:orders_iri (orders_tbl.order_num) where (^{items_tbl.}^.order_num = ^{orders_tbl.}^.order_num) as virtrdf:Items-from_order ;
items:has_stock stock:stock_iri (stock_tbl.stock_num, stock_tbl.manu_code) where (^{items_tbl.}^.stock_num = ^{stock_tbl.}^.stock_num and ^{items_tbl.}^.manu_code = ^{stock_tbl.}^.manu_code) as virtrdf:Item-has_stock .
catalog:catalog_iri (catalog_tbl.catalog_num) a catalog:Catalog as virtrdf:catalog_num;
catalog:stock_num catalog_tbl.stock_num as virtrdf:catalog_stock_num ;
catalog:manu_code catalog_tbl.manu_code as virtrdf:catalog_manu_code ;
catalog:cat_descr catalog_tbl.cat_descr as virtrdf:catalog_cat_descr ;
catalog:cat_picture catalog_tbl.cat_picture as virtrdf:catalog_cat_picture ;
catalog:cat_advert catalog_tbl.cat_advert as virtrdf:catalog_cat_advert ;
catalog:has_stock stock:stock_iri (stock_tbl.stock_num, stock_tbl.manu_code) where (^{catalog_tbl.}^.stock_num = ^{stock_tbl.}^.stock_num and ^{catalog_tbl.}^.manu_code = ^{stock_tbl.}^.manu_code) as virtrdf:Catalog-has_stock .
msgs:msgs_iri (msgs_tbl.lang, msgs_tbl.number, msgs_tbl.message) a msgs:Msgs as virtrdf:msgs_pk ;
msgs:lang msgs_tbl.lang as virtrdf:msgs_lang ;
msgs:number msgs_tbl.number as virtrdf:msgs_number ;
msgs:message msgs_tbl.message as virtrdf:msgs_message .
state:state_iri (state_tbl.code) a state:State as virtrdf:code ;
state:code state_tbl.code as virtrdf:state_code ;
state:sname state_tbl.sname as virtrdf:state_sname .
orders:orders_iri (orders_tbl.order_num) a orders:Orders as virtrdf:order_num ;
orders:order_num orders_tbl.order_num as virtrdf:orders_order_num ;
orders:order_date orders_tbl.order_date as virtrdf:orders_order_date ;
orders:customer_num orders_tbl.customer_num as virtrdf:orders_customer_num ;
orders:ship_instruct orders_tbl.ship_instruct as virtrdf:orders_ship_instruct ;
orders:backlog orders_tbl.backlog as virtrdf:orders_backlog ;
orders:po_num orders_tbl.po_num as virtrdf:orders_po_num ;
orders:ship_date orders_tbl.ship_date as virtrdf:orders_ship_date ;
orders:ship_weight orders_tbl.ship_weight as virtrdf:orders_ship_weight ;
orders:ship_charge orders_tbl.ship_charge as virtrdf:orders_ship_charge ;
orders:paid_date orders_tbl.paid_date as virtrdf:orders_paid_date ;
orders:has_customer cust:customer_iri (customer_tbl.customer_num) where (^{orders_tbl.}^.customer_num = ^{customer_tbl.}^.customer_num) as virtrdf:Orders-has_customer ;
orders:has_item items:items_iri (items_tbl.item_num, items_tbl.order_num) where (^{orders_tbl.}^.order_num = ^{items_tbl.}^.order_num) as virtrdf:Orders-has_item .
stock:stock_iri (stock_tbl.stock_num, stock_tbl.manu_code) a stock:Stock as virtrdf:stock_pk ;
stock:stock_num stock_tbl.stock_num as virtrdf:stock_stock_num ;
stock:manu_code stock_tbl.manu_code as virtrdf:stock_manu_code ;
stock:description stock_tbl.description as virtrdf:stock_description ;
stock:unit_price stock_tbl.unit_price as virtrdf:stock_unit_price ;
stock:unit stock_tbl.unit as virtrdf:stock_unit ;
stock:unit_descr stock_tbl.unit_descr as virtrdf:stock_unit_descr ;
stock:manufactured_by manuf:manufact_iri (manufact_tbl.manu_code) where (^{stock_tbl.}^.manu_code = ^{manufact_tbl.}^.manu_code) as virtrdf:Stock-manufactured_by ;
stock:in_catalog catalog:catalog_iri (catalog_tbl.catalog_num) where (^{stock_tbl.}^.stock_num = ^{catalog_tbl.}^.stock_num and ^{stock_tbl.}^.manu_code = ^{catalog_tbl.}^.manu_code) as virtrdf:Stock-in_catalog ;
stock:in_item items:items_iri (items_tbl.item_num, items_tbl.order_num) where (^{stock_tbl.}^.stock_num = ^{items_tbl.}^.stock_num and ^{stock_tbl.}^.manu_code = ^{items_tbl.}^.manu_code) as virtrdf:Stock-in_items .
cust:customer_iri (customer_tbl.customer_num) a cust:Customer as virtrdf:customer_num ;
cust:customer_num customer_tbl.customer_num as virtrdf:customer_customer_num ;
cust:fname customer_tbl.fname as virtrdf:customer_fname ;
cust:lname customer_tbl.lname as virtrdf:customer_lname ;
cust:company customer_tbl.company as virtrdf:customer_company ;
cust:address1 customer_tbl.address1 as virtrdf:customer_address1 ;
cust:address2 customer_tbl.address2 as virtrdf:customer_address2 ;
cust:city customer_tbl.city as virtrdf:customer_city ;
cust:state customer_tbl.state as virtrdf:customer_state ;
cust:zipcode customer_tbl.zipcode as virtrdf:customer_zipcode ;
cust:phone customer_tbl.phone as virtrdf:customer_phone ;
cust:placed_order orders:orders_iri (orders_tbl.order_num) where (^{customer_tbl.}^.customer_num = ^{orders_tbl.}^.customer_num) as virtrdf:Customer-placed_order ;
cust:made_call custc:cust_calls_iri (cust_calls_tbl.customer_num, cust_calls_tbl.call_dtime ) where (^{customer_tbl.}^.customer_num = ^{cust_calls_tbl.}^.customer_num) as virtrdf:Cust_calls-made_call .
callt:call_type_iri (call_type_tbl.call_code) a callt:Call_type as virtrdf:call_code ;
callt:call_code call_type_tbl.call_code as virtrdf:call_type_call_code ;
callt:code_descr call_type_tbl.code_descr as virtrdf:call_type_code_descr ;
callt:call_is_type custc:cust_calls_iri (cust_calls_tbl.customer_num, cust_calls_tbl.call_dtime) where (^{call_type_tbl.}^.call_code = ^{cust_calls_tbl.}^.call_code) as virtrdf:Call_type-call_is_type .
manuf:manufact_iri (manufact_tbl.manu_code) a manuf:Manufact as virtrdf:manu_code ;
manuf:manu_code manufact_tbl.manu_code as virtrdf:manufact_tbl_manu_code ;
manuf:manu_name manufact_tbl.manu_name as virtrdf:manufact_tbl_manu_name ;
manuf:lead_time manufact_tbl.lead_time as virtrdf:manufact_tbl_lead_time ;
manuf:manufactures stock:stock_iri (stock_tbl.stock_num, stock_tbl.manu_code) where (^{manufact_tbl.}^.manu_code = ^{stock_tbl.}^.manu_code) as virtrdf:Manufact-manufactures .
custc:cust_calls_iri (cust_calls_tbl.customer_num, cust_calls_tbl.call_dtime) a custc:Cust_calls as virtrdf:cust_calls_pk ;
custc:user_id cust_calls_tbl.user_id as virtrdf:cust_calls_user_id ;
custc:call_code cust_calls_tbl.call_code as virtrdf:cust_calls_call_code ;
custc:call_descr cust_calls_tbl.call_descr as virtrdf:cust_calls_call_descr ;
custc:res_dtime cust_calls_tbl.res_dtime as virtrdf:cust_calls_res_dtime ;
custc:res_descr cust_calls_tbl.res_descr as virtrdf:cust_calls_res_descr ;
custc:made_by_customer cust:customer_iri (customer_tbl.customer_num) where (^{cust_calls_tbl.}^.customer_num = ^{customer_tbl.}^.customer_num) as virtrdf:Cust_calls-made_by_customer ;
custc:is_call_type callt:call_type_iri (call_type_tbl.call_code) where (^{cust_calls_tbl.}^.call_code = ^{call_type_tbl.}^.call_code) as virtrdf:Cust_calls-is_call_type .
} .
} .
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'informix_sd_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'informix_sd_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'informix_sd_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'informix_sd_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/informix/stores_demo%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'informix_sd_rule_list1',
1,
vector (
'informix_sd_rule1',
'informix_sd_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/informix/stores_demo');
VHOST_DEFINE (
lpath=>'/informix/stores_demo',
ppath=>'/DAV/informix/stores_demo/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'informix_sd_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'informix_sd_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'informix_sd_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'informix_sd_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'informix_sd_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/informix/stores_demo%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'informix_sd_schemas_rule_list1',
1,
vector (
'informix_sd_schemas_rule1',
'informix_sd_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schemas/informix/stores_demo');
VHOST_DEFINE (
lpath=>'/schemas/informix/stores_demo',
ppath=>'/DAV/schemas/informix/stores_demo/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'informix_sd_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('items', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/items/', 2);
DB.DBA.XML_SET_NS_DECL ('catalog', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/catalog/', 2);
DB.DBA.XML_SET_NS_DECL ('stock', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/stock/', 2);
DB.DBA.XML_SET_NS_DECL ('msgs', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/msgs/', 2);
DB.DBA.XML_SET_NS_DECL ('state', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/state/', 2);
DB.DBA.XML_SET_NS_DECL ('orders', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/orders/', 2);
DB.DBA.XML_SET_NS_DECL ('manuf', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/manufact/', 2);
DB.DBA.XML_SET_NS_DECL ('cust', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/customer/', 2);
DB.DBA.XML_SET_NS_DECL ('callt', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/call_type/', 2);
DB.DBA.XML_SET_NS_DECL ('custc', 'http://^{URIQADefaultHost}^/schemas/informix/stores_demo/cust_calls/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterpringr">
<title>Ingres using demonstration 'Tutorial' database</title>
<programlisting><![CDATA[
-- Setup script for RDF views of Ingres R3 Tutorial Sample Database --
DB..vd_remote_data_source ('ingiima-tut', '', '<uid>','<pwd>');
ATTACH TABLE "ingres"."book_list" PRIMARY KEY ("book_no") AS "TUT"."ingiima"."book_list" FROM 'ingiima-tut';
ATTACH TABLE "ingres"."book_orders" PRIMARY KEY ("order_no") AS "TUT"."ingiima"."book_orders" FROM 'ingiima-tut';
ATTACH TABLE "ingres"."cust_info" PRIMARY KEY ("cust_no") AS "TUT"."ingiima"."cust_info" FROM 'ingiima-tut';
ATTACH TABLE "ingres"."cust_orders" PRIMARY KEY ("order_no") AS "TUT"."ingiima"."cust_orders" FROM 'ingiima-tut';
COMMIT WORK;
GRANT SELECT ON TUT.ingiima.book_list TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON TUT.ingiima.book_orders TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON TUT.ingiima.cust_info TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON TUT.ingiima.cust_orders TO "SPARQL", "SPARQL_UPDATE";
-------------------------------------------------------------------
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix tut: <http://localhost:8890/schemas/ingrestut/> .
tut:book_list a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/ingrestut> ;
rdfs:label "book_list" ;
rdfs:comment "Ingres Tutorial Database book_list table" .
tut:book_no a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:integer ;
rdfs:label "Book No" .
tut:title a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:string ;
rdfs:label "Title" .
tut:author a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:string ;
rdfs:label "Author" .
tut:price a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:money;
rdfs:label "Price" .
tut:category a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:string ;
rdfs:label "Category" .
tut:stock a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:integer ;
rdfs:label "Stock" .
tut:dist_no a rdf:Property ;
rdfs:domain tut:book_list ;
rdfs:range xsd:integer ;
rdfs:label "Dist No" .
tut:book_orders a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/ingrestut> ;
rdfs:label "Book Orders" ;
rdfs:comment "Ingres Tutorial Database book_orders table" .
tut:order_no a rdf:Property ;
rdfs:domain tut:book_orders ;
rdfs:range xsd:integer ;
rdfs:label "Order No" .
tut:book_no_no a rdf:Property ;
rdfs:domain tut:book_orders ;
rdfs:range tut:book_list ;
rdfs:label "Book No" .
tut:sale_price a rdf:Property ;
rdfs:domain tut:book_orders ;
rdfs:range xsd:money ;
rdfs:label "Sale Price" .
tut:quantity a rdf:Property ;
rdfs:domain tut:book_orders ;
rdfs:range xsd:integer ;
rdfs:label "Quantity" .
tut:extension a rdf:Property ;
rdfs:domain tut:book_orders ;
rdfs:range xsd:money ;
rdfs:label "Extension" .
tut:cust_info a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/ingrestut> ;
rdfs:label "Customer Information" ;
rdfs:comment "Ingres Tutorial Database cust_info table" .
tut:cust_no a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:integer ;
rdfs:label "Customer No" .
tut:name a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string ;
rdfs:label "Name" .
tut:company a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string ;
rdfs:label "Company" .
tut:street a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "Street" .
tut:city a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "City" .
tut:state a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "State" .
tut:city a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "City" .
tut:state a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "State" .
tut:zip a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "Zip Code" .
tut:card_no a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "Card No" .
tut:exp_date a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:date;
rdfs:label "Expire Date" .
tut:ship_to a rdf:Property ;
rdfs:domain tut:cust_info ;
rdfs:range xsd:string;
rdfs:label "Ship To" .
tut:cust_orders a rdfs:Class ;
rdfs:isDefinedBy <http://localhost:8890/schemas/ingrestut> ;
rdfs:label "Customer Orders" ;
rdfs:comment "Ingres Tutorial Database cust_orders table" .
tut:order_no a rdf:Property ;
rdfs:domain tut:cust_orders ;
rdfs:range tut:book_orders ;
rdfs:label "Order No" .
tut:book_no a rdf:Property ;
rdfs:domain tut:cust_orders ;
rdfs:range tut:cust_info ;
rdfs:label "Book No" .
tut:order_date a rdf:Property ;
rdfs:domain tut:cust_orders ;
rdfs:range xsd:date ;
rdfs:label "Order Date" .
tut:status a rdf:Property ;
rdfs:domain tut:cust_orders ;
rdfs:range xsd:string ;
rdfs:label "Status" .
tut:order_total a rdf:Property ;
rdfs:domain tut:cust_orders ;
rdfs:range xsd:money ;
rdfs:label "Order Total" .
', '', 'http://localhost:8890/schemas/ingrestut', 0);
---------------------------------------------------------------
----------- Create IRI Classes -------------
SPARQL
create iri class <http://localhost:8890/schemas/ingrestut/book_list_iri>
"http://^{URIQADefaultHost}^/ingrestut/book_list/%d#this"
(in book_no integer not null) .
create iri class <http://localhost:8890/schemas/ingrestut/book_orders_iri>
"http://^{URIQADefaultHost}^/ingrestut/book_orders/%d_%d#this"
(in order_no integer not null, in book_no integer not null ) .
create iri class <http://localhost:8890/schemas/ingrestut/cust_info_iri>
"http://^{URIQADefaultHost}^/ingrestut/cust_info/%d#this"
(in cust_no integer not null) .
create iri class <http://localhost:8890/schemas/ingrestut/cust_orders_iri>
"http://^{URIQADefaultHost}^/ingrestut/cust_orders/%d#this"
(in order_no integer not null) .
;
--------------------------------------------------------------------
------------- Create Quad Store ------------------------------------
SPARQL
prefix tut: <http://localhost:8890/schemas/ingrestut/>
alter quad storage virtrdf:DefaultQuadStorage
from TUT.ingiima.book_list as book_list_tbl
from TUT.ingiima.book_orders as book_orders_tbl
from TUT.ingiima.cust_info as cust_info_tbl
from TUT.ingiima.cust_orders as cust_orders_tbl
{
create virtrdf:ingrestut as
graph <http://localhost:8890/ingrestut>
{
tut:book_list_iri(book_list_tbl.book_no) a tut:book_list
as virtrdf:book_list_book_no ;
tut:title book_list_tbl.title
as virtrdf:book_list_title;
tut:author book_list_tbl.author
as virtrdf:book_list_author;
tut:price book_list_tbl.price
as virtrdf:book_list_price;
tut:category book_list_tbl.category
as virtrdf:book_list_category;
tut:stock book_list_tbl.stock
as virtrdf:book_list_stock;
tut:dist_no book_list_tbl.dist_no
as virtrdf:book_list_dist_no .
tut:book_orders_iri(book_orders_tbl.order_no, book_orders_tbl.book_no) a tut:book_orders
as virtrdf:book_orders_pk;
tut:order_no book_orders_tbl.order_no
as virtrdf:book_orders_order_no;
tut:book_no tut:book_list_iri(book_list_tbl.book_no)
where(^{book_orders_tbl.}^.book_no = ^{book_list_tbl.}^.book_no)
as virtrdf:book_orders_book_no;
tut:sale_price book_orders_tbl.sale_price
as virtrdf:book_orders_sale_price;
tut:quantity book_orders_tbl.quantity
as virtrdf:book_orders_quantity;
tut:extension book_orders_tbl.extension
as virtrdf:book_orders_extension .
tut:cust_info_iri(cust_info_tbl.cust_no) a tut:cust_info
as virtrdf:cust_info_cust_no;
tut:name cust_info_tbl.name
as virtrdf:cust_info_name;
tut:company cust_info_tbl.company
as virtrdf:cust_info_company;
tut:street cust_info_tbl.street
as virtrdf:cust_info_street;
tut:city cust_info_tbl.city
as virtrdf:cust_info_city;
tut:state cust_info_tbl.state
as virtrdf:cust_info_state;
tut:zip cust_info_tbl.zip
as virtrdf:cust_info_zip;
tut:card_no cust_info_tbl.card_no
as virtrdf:cust_info_card_no;
tut:exp_date cust_info_tbl.exp_date
as virtrdf:cust_info_exp_date;
tut:ship_to cust_info_tbl.ship_to
as virtrdf:cust_info_ship_to .
tut:cust_orders_iri(cust_orders_tbl.order_no) a tut:cust_orders
as virtrdf:cust_orders_order_no;
tut:cust_no tut:cust_info_iri(cust_info_tbl.cust_no)
where (^{cust_orders_tbl.}^.cust_no = ^{cust_info_tbl.}^.cust_no)
as virtrdf:cust_orders_cust_no;
tut:order_date cust_orders_tbl.order_date
as virtrdf:cust_orders_order_date;
tut:status cust_orders_tbl.status
as virtrdf:cust_orders_status;
tut:order_total cust_orders_tbl.order_total
as virtrdf:cust_orders_order_total .
} .
} .
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'ingrestut_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'ingrestut_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ingrestut_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ingrestut_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/ingrestut%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ingrestut_rule_list1',
1,
vector (
'ingrestut_rule1',
'ingrestut_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/ingrestut');
VHOST_DEFINE (
lpath=>'/ingrestut',
ppath=>'/DAV/ingrestut/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'ingrestut_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'ingres_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'ingres_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ingres_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'ingres_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/ingrestut%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'ingres_schemas_rule_list1',
1,
vector (
'ingres_schemas_rule1',
'ingres_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schema/ingrestut');
VHOST_DEFINE (
lpath=>'/schemas/ingrestut',
ppath=>'/DAV/schemas/ingrestut/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'ingres_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('tut', 'http://^{URIQADefaultHost}^/schemas/ingrestut/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterprs89">
<title>Progress (SQL-89) using demonstration 'iSports' database</title>
<programlisting><![CDATA[
ATTACH TABLE "ISPORTS_RDF"."Customer" PRIMARY KEY ("Cust-Num")
AS "isports_rdf"."pro91_isports_rdf"."Customer"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Invoice" PRIMARY KEY ("Invoice-Num")
AS "isports_rdf"."pro91_isports_rdf"."Invoice"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Item" PRIMARY KEY ("Item-num")
AS "isports_rdf"."pro91_isports_rdf"."Item"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Local-Default" PRIMARY KEY ("Country")
AS "isports_rdf"."pro91_isports_rdf"."Local-Default"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Order" PRIMARY KEY ("Order-num")
AS "isports_rdf"."pro91_isports_rdf"."Order"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Order-Line" PRIMARY KEY ("Order-num", "Line-num")
AS "isports_rdf"."pro91_isports_rdf"."Order-Line"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Ref-Call" PRIMARY KEY ("Call-Num")
AS "isports_rdf"."pro91_isports_rdf"."Ref-Call"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."Salesrep" PRIMARY KEY ("Sales-Rep")
AS "isports_rdf"."pro91_isports_rdf"."Salesrep"
FROM 'pro91_isports_rdf';
ATTACH TABLE "ISPORTS_RDF"."State" PRIMARY KEY ("State")
AS "isports_rdf"."pro91_isports_rdf"."State"
FROM 'pro91_isports_rdf';
COMMIT WORK;
GRANT SELECT ON isports_rdf.pro91_isports_rdf.Customer TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf."Order" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.Item TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf."Order-Line" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.Invoice TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf."Local-Default" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf."Ref-Call" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.Salesrep TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.State TO "SPARQL", "SPARQL_UPDATE";
GRANT SPARQL_UPDATE to "SPARQL";
CREATE VIEW isports_rdf.pro91_isports_rdf.VCustomer AS SELECT "Cust-Num" AS Cust_Num, Name, Address, Address2, City, State, Country, Phone, Contact, "Sales-Rep" AS Sales_Rep, Comments, "Credit-Limit" AS Credit_Limit, Balance, Terms, Discount, "Postal-Code" AS Postal_Code FROM "isports_rdf"."pro91_isports_rdf"."Customer";
CREATE VIEW isports_rdf.pro91_isports_rdf.VOrder AS SELECT "Order-num" AS Order_num, "Cust-Num" AS Cust_Num, "Order-Date" AS Order_Date, "Ship-Date" AS Ship_Date, "Promise-Date" AS Promise_Date, Carrier, Instructions, PO, Terms, "Sales-Rep" AS Sales_Rep FROM isports_rdf.pro91_isports_rdf."Order";
CREATE VIEW isports_rdf.pro91_isports_rdf.VItem AS SELECT "Item-num" AS Item_num, "Item-Name" AS Item_Name, "Cat-Page" AS Cat_Page, Price, "Cat-Description" AS Cat_Description, "On-hand" AS On_hand, Allocated, "Re-Order" AS Re_Order, "On-Order" AS On_Order FROM isports_rdf.pro91_isports_rdf.Item;
CREATE VIEW isports_rdf.pro91_isports_rdf.VOrder_Line AS SELECT "Order-num" AS Order_num, "Line-num" AS Line_num, "Item-num" AS Item_num, Price, Qty, Discount, "Extended-Price" AS Extended_Price, Backorder FROM isports_rdf.pro91_isports_rdf."Order-Line";
CREATE VIEW isports_rdf.pro91_isports_rdf.VInvoice AS SELECT "Invoice-Num" AS Invoice_Num, "Cust-Num" AS Cust_Num, "Invoice-Date" AS Invoice_Date, Amount, "Total-Paid" AS Total_Paid, Adjustment, "Order-Num" AS Order_Num, "Ship-Charge" AS Ship_Charge FROM isports_rdf.pro91_isports_rdf.Invoice;
CREATE VIEW isports_rdf.pro91_isports_rdf.VLocal_Default AS SELECT Country, "Region1-Label" AS Region1_Label, "Region2-Label" AS Region2_Label, "Postal-Label" AS Postal_Label, "Postal-Format" AS Postal_Format, "Tel-Format" AS Tel_Format, "Date-Format" AS Date_Format, "Currency-Symbol" AS Currency_Symbol FROM isports_rdf.pro91_isports_rdf."Local-Default";
CREATE VIEW isports_rdf.pro91_isports_rdf.VRef_Call AS SELECT "Call-Num" AS Call_Num, "Cust-Num" AS Cust_Num, "Call-Date" AS Call_Date, "Sales-Rep" AS Sales_Rep, Parent, Txt FROM isports_rdf.pro91_isports_rdf."Ref-Call";
CREATE VIEW isports_rdf.pro91_isports_rdf.VSalesrep AS SELECT "Rep-Name" AS Rep_Name, Region, "Sales-Rep" AS Sales_Rep, "Month-Quota@1" AS Month_Quota_1, "Month-Quota@2" AS Month_Quota_2, "Month-Quota@3" AS Month_Quota_3, "Month-Quota@4" AS Month_Quota_4, "Month-Quota@5" AS Month_Quota_5, "Month-Quota@6" AS Month_Quota_6, "Month-Quota@7" AS Month_Quota_7, "Month-Quota@8" AS Month_Quota_8, "Month-Quota@9" AS Month_Quota_9, "Month-Quota@10" AS Month_Quota_10, "Month-Quota@11" AS Month_Quota_11, "Month-Quota@12" AS Month_Quota_12 FROM isports_rdf.pro91_isports_rdf.Salesrep;
CREATE VIEW isports_rdf.pro91_isports_rdf.VState AS SELECT State, "State-Name" AS State_Name, Region FROM isports_rdf.pro91_isports_rdf.State;
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VCustomer TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VOrder TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VItem TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VOrder_Line TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VInvoice TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VLocal_Default TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VRef_Call TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VSalesrep TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.pro91_isports_rdf.VState TO "SPARQL", "SPARQL_UPDATE";
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix customer: <http://localhost:8890/schemas/progress/isports/customer/> .
@prefix order: <http://localhost:8890/schemas/progress/isports/order/> .
@prefix item: <http://localhost:8890/schemas/progress/isports/item/> .
@prefix orderline: <http://localhost:8890/schemas/progress/isports/order_line/> .
@prefix invoice: <http://localhost:8890/schemas/progress/isports/invoice/> .
@prefix localdefault: <http://localhost:8890/schemas/progress/isports/local_default/> .
@prefix refcall: <http://localhost:8890/schemas/progress/isports/ref_call/> .
@prefix salesrep: <http://localhost:8890/schemas/progress/isports/salesrep/> .
@prefix state: <http://localhost:8890/schemas/progress/isports/state/> .
customer:Customer a rdfs:Class ;
rdfs:label "Customer" ;
rdfs:comment "Progress isports Customer table" .
customer:Cust-Num a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
customer:Name a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Name" .
customer:Address a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Address" .
customer:Address2 a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Address2" .
customer:City a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "City" .
customer:State a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "State" .
customer:Country a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Country" .
customer:Phone a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Phone" .
customer:Contact a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Contact" .
customer:Sales-Rep a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
customer:Comments a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Comments" .
customer:Credit-Limit a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:decimal ;
rdfs:label "Credit-Limit" .
customer:Balance a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:decimal ;
rdfs:label "Balance" .
customer:Terms a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Terms" .
customer:Discount a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:integer ;
rdfs:label "Discount" .
customer:Postal-Code a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Postal-Code" .
order:Order a rdfs:Class ;
rdfs:label "Order" ;
rdfs:comment "Progress isports Order table" .
order:Order-num a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:integer ;
rdfs:label "Order-num" .
order:Cust-Num a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
order:Order-Date a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:date ;
rdfs:label "Order-Date" .
order:Ship-Date a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:date ;
rdfs:label "Ship-Date" .
order:Promise-Date a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:date ;
rdfs:label "Promise-Date" .
order:Carrier a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Carrier" .
order:Instructions a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Instructions" .
order:PO a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "PO" .
order:Terms a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Terms" .
order:Sales-Rep a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
item:Item a rdfs:Class ;
rdfs:label "Item" ;
rdfs:comment "Progress isports Item table" .
item:Item-num a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Item-num" .
item:Item-Name a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:string ;
rdfs:label "Item-Name" .
item:Cat-Page a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Cat-Page" .
item:Price a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:decimal ;
rdfs:label "Price" .
item:Cat-Description a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:string ;
rdfs:label "Cat-Description" .
item:On-hand a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "On-hand" .
item:Allocated a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Allocated" .
item:Re-Order a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Re-Order" .
item:On-Order a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "On-Order" .
orderline:Order-Line a rdfs:Class ;
rdfs:label "Order-Line" ;
rdfs:comment "Progress isports Order-Line table" .
orderline:Order-num a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Order-num" .
orderline:Line-num a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Line-num" .
orderline:Item-num a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Item-num" .
orderline:Price a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:decimal ;
rdfs:label "Price" .
orderline:Qty a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Qty" .
orderline:Discount a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Discount" .
orderline:Extended-Price a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:decimal ;
rdfs:label "Extended-Price" .
orderline:Backorder a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:byte ;
rdfs:label "Backorder" .
invoice:Invoice a rdfs:Class ;
rdfs:label "Invoice" ;
rdfs:comment "Progress isports Invoice table" .
invoice:Invoice-Num a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:integer ;
rdfs:label "Invoice-Num" .
invoice:Cust-Num a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
invoice:Invoice-Date a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:date ;
rdfs:label "Invoice-Date" .
invoice:Amount a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Amount" .
invoice:Total-Paid a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Total-Paid" .
invoice:Adjustment a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Adjustment" .
invoice:Order-Num a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:integer ;
rdfs:label "Order-Num" .
invoice:Ship-Charge a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Ship-Charge" .
localdefault:Local-Default a rdfs:Class ;
rdfs:label "Local-Default" ;
rdfs:comment "Progress isports Local-Default table" .
localdefault:Country a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Country" .
localdefault:Region1-Label a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Region1-Label" .
localdefault:Region2-Label a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Region2-Label" .
localdefault:Postal-Label a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Postal-Label" .
localdefault:Postal-Format a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Postal-Format" .
localdefault:Tel-Format a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Tel-Format" .
localdefault:Date-Format a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Date-Format" .
localdefault:Currency-Symbol a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Currency-Symbol" .
refcall:Ref-Call a rdfs:Class ;
rdfs:label "Ref-Call" ;
rdfs:comment "Progress isports Ref-Call table" .
refcall:Call-Num a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Call-Num" .
refcall:Cust-Num a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
refcall:Call-Date a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:date ;
rdfs:label "Call-Date" .
refcall:Sales-Rep a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
refcall:Parent a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Parent" .
refcall:Txt a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Txt" .
salesrep:Salesrep a rdfs:Class ;
rdfs:label "Salesrep" ;
rdfs:comment "Progress isports Salesrep table" .
salesrep:Sales-Rep a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
salesrep:Rep-Name a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Rep-Name" .
salesrep:Region a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Region" .
salesrep:Month-Quota-1 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@1" .
salesrep:Month-Quota-2 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@2" .
salesrep:Month-Quota-3 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@3" .
salesrep:Month-Quota-4 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@4" .
salesrep:Month-Quota-5 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@5" .
salesrep:Month-Quota-6 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@6" .
salesrep:Month-Quota-7 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@7" .
salesrep:Month-Quota-8 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@8" .
salesrep:Month-Quota-9 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@9" .
salesrep:Month-Quota-10 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@10" .
salesrep:Month-Quota-11 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@11" .
salesrep:Month-Quota-12 a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota@12" .
state:State a rdfs:Class ;
rdfs:label "State" ;
rdfs:comment "Progress isports State table" .
state:State_ a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "State" .
state:State-Name a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "State-Name" .
state:Region a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "Region" .
', '', 'http://localhost:8890/schemas/progress/isports', 0);
----------- Create IRI Classes -------------
SPARQL
prefix customer: <http://localhost:8890/schemas/progress/isports/customer/>
prefix order: <http://localhost:8890/schemas/progress/isports/order/>
prefix item: <http://localhost:8890/schemas/progress/isports/item/>
prefix orderline: <http://localhost:8890/schemas/progress/isports/order_line/>
prefix invoice: <http://localhost:8890/schemas/progress/isports/invoice/>
prefix localdefault: <http://localhost:8890/schemas/progress/isports/local_default/>
prefix refcall: <http://localhost:8890/schemas/progress/isports/ref_call/>
prefix salesrep: <http://localhost:8890/schemas/progress/isports/salesrep/>
prefix state: <http://localhost:8890/schemas/progress/isports/state/>
create iri class customer:customer_iri
"http://localhost:8890/progress/isports/customer/%d#this"
(in Cust_Num integer not null) .
create iri class order:order_iri
"http://localhost:8890/progress/isports/order/%d#this"
(in Order_Num integer not null) .
create iri class item:item_iri
"http://localhost:8890/progress/isports/item/%d#this"
(in Item_num integer not null) .
create iri class orderline:order-line_iri
"http://localhost:8890/progress/isports/order-line/%d_%d#this"
(in Order_num integer not null, in Line_num integer not null) .
create iri class invoice:invoice_iri
"http://localhost:8890/progress/isports/invoice/%d#this"
(in Invoice_Num integer not null) .
create iri class localdefault:local-default_iri
"http://localhost:8890/progress/isports/local-default/%U#this"
(in Country varchar not null) .
create iri class refcall:ref-call_iri
"http://localhost:8890/progress/isports/ref-call/%U#this"
(in Call_Num varchar not null) .
create iri class salesrep:salesrep_iri
"http://localhost:8890/progress/isports/salesrep/%U#this"
(in Sales_Rep varchar not null) .
create iri class state:state_iri
"http://localhost:8890/progress/isports/state/%U#this"
(in State varchar not null) .
;
------------- Create Quad Store ------------------------------------
SPARQL
prefix customer: <http://localhost:8890/schemas/progress/isports/customer/>
prefix order: <http://localhost:8890/schemas/progress/isports/order/>
prefix item: <http://localhost:8890/schemas/progress/isports/item/>
prefix orderline: <http://localhost:8890/schemas/progress/isports/order_line/>
prefix invoice: <http://localhost:8890/schemas/progress/isports/invoice/>
prefix localdefault: <http://localhost:8890/schemas/progress/isports/local_default/>
prefix refcall: <http://localhost:8890/schemas/progress/isports/ref_call/>
prefix salesrep: <http://localhost:8890/schemas/progress/isports/salesrep/>
prefix state: <http://localhost:8890/schemas/progress/isports/state/>
alter quad storage virtrdf:DefaultQuadStorage
from isports_rdf.pro91_isports_rdf.VCustomer as Customer_tbl
from isports_rdf.pro91_isports_rdf.VOrder as Order_tbl
from isports_rdf.pro91_isports_rdf.VItem as Item_tbl
from isports_rdf.pro91_isports_rdf.VOrder_Line as Order_Line_tbl
from isports_rdf.pro91_isports_rdf.VInvoice as Invoice_tbl
from isports_rdf.pro91_isports_rdf.VRef_Call as Ref_Call_tbl
from isports_rdf.pro91_isports_rdf.VRef_Call as Ref_Call_tbl_1
from isports_rdf.pro91_isports_rdf.VLocal_Default as Local_Default_tbl
from isports_rdf.pro91_isports_rdf.VSalesrep as Salesrep_tbl
from isports_rdf.pro91_isports_rdf.VState as State_tbl
{
create virtrdf:progress_isports as graph <http://localhost:8890/progress/isports>
{
customer:customer_iri (Customer_tbl.Cust_Num) a customer:Customer as virtrdf:customer_pk ;
customer:Cust-Num Customer_tbl.Cust_Num as virtrdf:Customer_cust-num ;
customer:Name Customer_tbl.Name as virtrdf:Customer_name ;
customer:Address Customer_tbl.Address as virtrdf:Customer_address ;
customer:Address2 Customer_tbl.Address2 as virtrdf:Customer_address2 ;
customer:City Customer_tbl.City as virtrdf:Customer_city ;
customer:State Customer_tbl.State as virtrdf:Customer_state ;
customer:Country Customer_tbl.Country as virtrdf:Customer_country ;
customer:Phone Customer_tbl.Phone as virtrdf:Customer_phone ;
customer:Contact Customer_tbl.Contact as virtrdf:Customer_contact ;
customer:Sales-Rep Customer_tbl.Sales_Rep as virtrdf:Customer_sales_rep ;
customer:Comments Customer_tbl.Comments as virtrdf:Customer_comments ;
customer:Credit-Limit Customer_tbl.Credit_Limit as virtrdf:Customer_credit-limit ;
customer:Balance Customer_tbl.Balance as virtrdf:Customer_balance ;
customer:Terms Customer_tbl.Terms as virtrdf:Customer_terms ;
customer:Discount Customer_tbl.Discount as virtrdf:Customer_discount ;
customer:Postal-Code Customer_tbl.Postal_Code as virtrdf:Customer_postal-code ;
customer:from_state state:state_iri (State_tbl.State) where ( ^{Customer_tbl.}^.State = ^{State_tbl.}^.State ) as virtrdf:Customer_from_state ;
customer:has_sales_rep salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{Customer_tbl.}^.Sales_Rep = ^{Salesrep_tbl.}^.Sales_Rep ) as virtrdf:Customer_has_sales_rep ;
customer:has_local_default localdefault:local-default_iri (Local_Default_tbl.Country) where ( ^{Customer_tbl.}^.Country = ^{Local_Default_tbl.}^.Country ) as virtrdf:Customer_has_local_default ;
customer:placed_order order:order_iri (Order_tbl.Order_num) where ( ^{Customer_tbl.}^.Cust_Num = ^{Order_tbl.}^.Cust_Num ) as virtrdf:Customer_placed_order ;
customer:has_invoice invoice:invoice_iri (Invoice_tbl.Invoice_Num) where ( ^{Customer_tbl.}^.Cust_Num = ^{Invoice_tbl.}^.Cust_Num ) as virtrdf:Customer_has_invoice ;
customer:ref_call refcall:ref-call_iri (Ref_Call_tbl.Call_Num) where ( ^{Customer_tbl.}^.Cust_Num = ^{Ref_Call_tbl.}^.Cust_Num ) as virtrdf:Customer_ref-call .
order:order_iri (Order_tbl.Order_num) a order:Order as virtrdf:order_pk ;
order:Order-num Order_tbl.Order_num as virtrdf:Order_order-num ;
order:Cust-Num Order_tbl.Cust_Num as virtrdf:Order_cust_num ;
order:Order-Date Order_tbl.Order_Date as virtrdf:Order_order-date ;
order:Ship-Date Order_tbl.Ship_Date as virtrdf:Order_ship-date ;
order:Promise-Date Order_tbl.Promise_Date as virtrdf:Order_promise-date ;
order:Carrier Order_tbl.Carrier as virtrdf:Order_carrier ;
order:Instructions Order_tbl.Instructions as virtrdf:Order_instructions ;
order:PO Order_tbl.PO as virtrdf:Order_po ;
order:Terms Order_tbl.Terms as virtrdf:Order_terms ;
order:placed_by customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Order_tbl.}^.Cust_Num = ^{Customer_tbl.}^.Cust_Num ) as virtrdf:Order_placed_by ;
order:Sales-Rep salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{Order_tbl.}^.Sales_Rep = ^{Salesrep_tbl.}^.Sales_Rep ) as virtrdf:Order_sales_rep ;
order:invoiced_on invoice:invoice_iri (Invoice_tbl.Invoice_Num) where ( ^{Order_tbl.}^.Order_num = ^{Invoice_tbl.}^.Order_Num ) as virtrdf:Order_invoiced_on ;
order:has_lines orderline:order-line_iri (Order_Line_tbl.Order_num, Order_Line_tbl.Line_num) where ( ^{Order_tbl.}^.Order_num = ^{Order_Line_tbl.}^.Order_num ) as virtrdf:Order_has_lines .
item:item_iri (Item_tbl.Item_num) a item:Item as virtrdf:item_pk ;
item:Item-num Item_tbl.Item_num as virtrdf:item_item-num ;
item:Item-Name Item_tbl.Item_Name as virtrdf:Item_item-Name ;
item:Cat-Page Item_tbl.Cat_Page as virtrdf:Item_cat-page ;
item:Price Item_tbl.Price as virtrdf:Item_price ;
item:Cat-Description Item_tbl.Cat_Description as virtrdf:Item_cat-description ;
item:On-hand Item_tbl.On_hand as virtrdf:Item_on-hand ;
item:Allocated Item_tbl.Allocated as virtrdf:Item_allocated ;
item:Re-Order Item_tbl.Re_Order as virtrdf:Item_re-order ;
item:On-Order Item_tbl.On_Order as virtrdf:Item_on-order ;
item:order_line orderline:order-line_iri (Order_Line_tbl.Order_num, Order_Line_tbl.Line_num) where ( ^{Item_tbl.}^.Item_num = ^{Order_Line_tbl.}^.Item_num ) as virtrdf:Item_order_line .
orderline:order-line_iri (Order_Line_tbl.Order_num, Order_Line_tbl.Line_num) a orderline:Order-Line as virtrdf:order-line_pk ;
orderline:Line-num Order_Line_tbl.Line_num as virtrdf:Order-Line_line-num ;
orderline:Price Order_Line_tbl.Price as virtrdf:Order-Line_price ;
orderline:Qty Order_Line_tbl.Qty as virtrdf:Order-Line_qty ;
orderline:Discount Order_Line_tbl.Discount as virtrdf:Order-Line_discount ;
orderline:Extended-Price Order_Line_tbl.Extended_Price as virtrdf:Order-Line_extended-price ;
orderline:Backorder Order_Line_tbl.Backorder as virtrdf:Order-Line_backorder ;
orderline:Order-num order:order_iri (Order_tbl.Order_num) where ( ^{Order_Line_tbl.}^.Order_num = ^{Order_tbl.}^.Order_num ) as virtrdf:Order_Line_order_num ;
orderline:Item-num item:item_iri (Item_tbl.Item_num) where ( ^{Order_Line_tbl.}^.Item_num = ^{Item_tbl.}^.Item_num ) as virtrdf:Order_Line_item_num .
invoice:invoice_iri (Invoice_tbl.Invoice_Num) a invoice:Invoice as virtrdf:invoice_pk ;
invoice:Invoice-Num Invoice_tbl.Invoice_Num as virtrdf:Invoice_invoice-num ;
invoice:Cust-Num Invoice_tbl.Cust_Num as virtrdf:Invoice_cust_num ;
invoice:Invoice-Date Invoice_tbl.Invoice_Date as virtrdf:Invoice_invoice-date ;
invoice:Amount Invoice_tbl.Amount as virtrdf:Invoice_amount ;
invoice:Total-Paid Invoice_tbl.Total_Paid as virtrdf:Invoice_total-paid ;
invoice:Adjustment Invoice_tbl.Adjustment as virtrdf:Invoice_adjustment ;
invoice:Order-Num Invoice_tbl.Order_Num as virtrdf:Invoice_order-num ;
invoice:Ship-Charge Invoice_tbl.Ship_Charge as virtrdf:Invoice_ship-charge ;
invoice:invoiced_to customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Invoice_tbl.}^.Cust_Num = ^{Customer_tbl.}^.Cust_Num ) as virtrdf:Invoice_invoiced_to ;
invoice:Order-Num order:order_iri (Order_tbl.Order_num) where ( ^{Invoice_tbl.}^.Order_Num = ^{Order_tbl.}^.Order_num ) as virtrdf:Invoice_order_num .
localdefault:local-default_iri (Local_Default_tbl.Country) a localdefault:Local-Default as virtrdf:local-default_pk ;
localdefault:Country Local_Default_tbl.Country as virtrdf:local-default_country ;
localdefault:Region1-Label Local_Default_tbl.Region1_Label as virtrdf:Local-Default_region1-label ;
localdefault:Region2-Label Local_Default_tbl.Region2_Label as virtrdf:Local-Default_region2-label ;
localdefault:Postal-Label Local_Default_tbl.Postal_Label as virtrdf:Local-Default_postal-label ;
localdefault:Postal-Format Local_Default_tbl.Postal_Format as virtrdf:Local-Default_postal-format ;
localdefault:Tel-Format Local_Default_tbl.Tel_Format as virtrdf:Local-Default_tel-format ;
localdefault:Date-Format Local_Default_tbl.Date_Format as virtrdf:Local-Default_date-format ;
localdefault:Currency-Symbol Local_Default_tbl.Currency_Symbol as virtrdf:Local-Default_currency-symbol ;
localdefault:has_customer customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Local_Default_tbl.}^.Country = ^{Customer_tbl.}^.Country ) as virtrdf:Local-Default_has_customer .
refcall:ref-call_iri (Ref_Call_tbl.Call_Num) a refcall:Ref-Call as virtrdf:ref-call_pk ;
refcall:Call-Num Ref_Call_tbl.Call_Num as virtrdf:Ref-Call_call-num ;
refcall:Cust-Num Ref_Call_tbl.Cust_Num as virtrdf:Ref-Call_cust-num ;
refcall:Call-Date Ref_Call_tbl.Call_Date as virtrdf:Ref-Call_call-date ;
refcall:Sales-Rep Ref_Call_tbl.Sales_Rep as virtrdf:Ref-sales-rep ;
refcall:Parent Ref_Call_tbl.Parent as virtrdf:Ref-Call_parent ;
refcall:Txt Ref_Call_tbl.Txt as virtrdf:Ref-Call_txt ;
refcall:made_to customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Ref_Call_tbl.}^.Cust_Num = ^{Customer_tbl.}^.Cust_Num ) as virtrdf:Ref-Call_made_to ;
refcall:made_by salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{Ref_Call_tbl.}^.Sales_Rep = ^{Salesrep_tbl.}^.Sales_Rep ) as virtrdf:Ref-Call_made-by ;
refcall:has_parent refcall:ref-call_iri (Ref_Call_tbl_1.Call_Num) where ( ^{Ref_Call_tbl.}^.Parent = ^{Ref_Call_tbl_1.}^.Call_Num ) as virtrdf:Ref-Call_has_parent .
salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) a salesrep:Salesrep as virtrdf:salesrep_pk ;
salesrep:Sales-Rep Salesrep_tbl.Sales_Rep as virtrdf:Salesrep_sales-rep ;
salesrep:Region Salesrep_tbl.Region as virtrdf:Salesrep_region ;
salesrep:Rep-Name Salesrep_tbl.Rep_Name as virtrdf:Salesrep_rep-name ;
salesrep:Month-Quota-1 Salesrep_tbl.Month_Quota_1 as virtrdf:Salesrep_month-quota-1 ;
salesrep:Month-Quota-2 Salesrep_tbl.Month_Quota_2 as virtrdf:Salesrep_month-quota-2 ;
salesrep:Month-Quota-3 Salesrep_tbl.Month_Quota_3 as virtrdf:Salesrep_month-quota-3 ;
salesrep:Month-Quota-4 Salesrep_tbl.Month_Quota_4 as virtrdf:Salesrep_month-quota-4 ;
salesrep:Month-Quota-5 Salesrep_tbl.Month_Quota_5 as virtrdf:Salesrep_month-quota-5 ;
salesrep:Month-Quota-6 Salesrep_tbl.Month_Quota_6 as virtrdf:Salesrep_month-quota-6 ;
salesrep:Month-Quota-7 Salesrep_tbl.Month_Quota_7 as virtrdf:Salesrep_month-quota-7 ;
salesrep:Month-Quota-8 Salesrep_tbl.Month_Quota_8 as virtrdf:Salesrep_month-quota-8 ;
salesrep:Month-Quota-9 Salesrep_tbl.Month_Quota_9 as virtrdf:Salesrep_month-quota-9 ;
salesrep:Month-Quota-10 Salesrep_tbl.Month_Quota_10 as virtrdf:Salesrep_month-quota-10 ;
salesrep:Month-Quota-11 Salesrep_tbl.Month_Quota_11 as virtrdf:Salesrep_month-quota-11 ;
salesrep:Month-Quota-12 Salesrep_tbl.Month_Quota_12 as virtrdf:Salesrep_month-quota-12 ;
salesrep:is_sales_rep_for customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Salesrep_tbl.}^.Sales_Rep = ^{Customer_tbl.}^.Sales_Rep ) as virtrdf:Salesrep_is_sales_rep_for ;
salesrep:has_order order:order_iri (Order_tbl.Order_num) where ( ^{Salesrep_tbl.}^.Sales_Rep = ^{Order_tbl.}^.Sales_Rep ) as virtrdf:Salesrep_has_order ;
salesrep:manages_region state:state_iri (State_tbl.State) where ( ^{Salesrep_tbl.}^.Region = ^{State_tbl.}^.Region ) as virtrdf:Salesrep_manages_region ;
salesrep:made_call refcall:ref-call_iri (Ref_Call_tbl.Call_Num) where ( ^{Salesrep_tbl.}^.Sales_Rep = ^{Ref_Call_tbl.}^.Sales_Rep ) as virtrdf:Ref-Call_made_call .
state:state_iri (State_tbl.State) a state:State as virtrdf:state_pk ;
state:State_ State_tbl.State as virtrdf:State_state ;
state:State-Name State_tbl.State_Name as virtrdf:State_state-name ;
state:Region State_tbl.Region as virtrdf:State_region ;
state:has_customer customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{State_tbl.}^.State = ^{Customer_tbl.}^.State ) as virtrdf:State_has_customer ;
state:has_sales_rep salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{State_tbl.}^.Region = ^{Salesrep_tbl.}^.Region ) as virtrdf:State_has_sales_rep .
} .
} .
;
delete from db.dba.url_rewrite_rule_list where urrl_list like 'progress_isports_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'progress_isports_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/progress/isports%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'progress_isports_rule_list1',
1,
vector (
'progress_isports_rule1',
'progress_isports_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/progress/isports');
VHOST_DEFINE (
lpath=>'/progress/isports',
ppath=>'/DAV/progress/isports/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'progress_isports_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'progress_isports_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'progress_isports_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/progress/isports%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'progress_isports_schemas_rule_list1',
1,
vector (
'progress_isports_schemas_rule1',
'progress_isports_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schemas/progress/isports');
VHOST_DEFINE (
lpath=>'/schemas/progress/isports',
ppath=>'/DAV/schemas/progress/isports/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'progress_isports_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('customer', 'http://^{URIQADefaultHost}^/schemas/progress/isports/customer/', 2);
DB.DBA.XML_SET_NS_DECL ('order', 'http://^{URIQADefaultHost}^/schemas/progress/isports/order/', 2);
DB.DBA.XML_SET_NS_DECL ('item', 'http://^{URIQADefaultHost}^/schemas/progress/isports/item/', 2);
DB.DBA.XML_SET_NS_DECL ('orderline', 'http://^{URIQADefaultHost}^/schemas/progress/isports/order_line/', 2);
DB.DBA.XML_SET_NS_DECL ('invoice', 'http://^{URIQADefaultHost}^/schemas/progress/isports/invoice/', 2);
DB.DBA.XML_SET_NS_DECL ('localdefault', 'http://^{URIQADefaultHost}^/schemas/progress/isports/local_default/', 2);
DB.DBA.XML_SET_NS_DECL ('refcall', 'http://^{URIQADefaultHost}^/schemas/progress/isports/ref_call/', 2);
DB.DBA.XML_SET_NS_DECL ('salesrep', 'http://^{URIQADefaultHost}^/schemas/progress/isports/salesrep/', 2);
DB.DBA.XML_SET_NS_DECL ('state', 'http://^{URIQADefaultHost}^/schemas/progress/isports/state/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewsenterprs92">
<title>Progress (SQL-92) using demonstration 'iSports' database</title>
<programlisting><![CDATA[
ATTACH TABLE "PUB"."Customer" PRIMARY KEY ("Cust-Num") AS "isports_rdf"."prs10_isports_rdf"."Customer" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Invoice" PRIMARY KEY ("Invoice-Num") AS "isports_rdf"."prs10_isports_rdf"."Invoice" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Item" PRIMARY KEY ("Item-num") AS "isports_rdf"."prs10_isports_rdf"."Item" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Local-Default" PRIMARY KEY ("Country") AS "isports_rdf"."prs10_isports_rdf"."Local-Default" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Order" PRIMARY KEY ("Order-num") AS "isports_rdf"."prs10_isports_rdf"."Order" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Order-Line" PRIMARY KEY ("Order-num", "Line-num") AS "isports_rdf"."prs10_isports_rdf"."Order-Line" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Ref-Call" PRIMARY KEY ("Call-Num") AS "isports_rdf"."prs10_isports_rdf"."Ref-Call" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."Salesrep" PRIMARY KEY ("Sales-Rep") AS "isports_rdf"."prs10_isports_rdf"."Salesrep" FROM 'prs10_isports_rdf';
ATTACH TABLE "PUB"."State" PRIMARY KEY ("State") AS "isports_rdf"."prs10_isports_rdf"."State" FROM 'prs10_isports_rdf';
COMMIT WORK;
GRANT SELECT ON isports_rdf.prs10_isports_rdf.Customer TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf."Order" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.Item TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf."Order-Line" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.Invoice TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf."Local-Default" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf."Ref-Call" TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.Salesrep TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.State TO "SPARQL", "SPARQL_UPDATE";
GRANT SPARQL_UPDATE to "SPARQL";
CREATE VIEW isports_rdf.prs10_isports_rdf.VCustomer AS SELECT "Cust-Num" AS Cust_Num, Name, Address, Address2, City, State, Country, Phone, Contact, "Sales-Rep" AS Sales_Rep, Comments, "Credit-Limit" AS Credit_Limit, Balance, Terms, Discount, "Postal-Code" AS Postal_Code FROM isports_rdf.prs10_isports_rdf.Customer;
CREATE VIEW isports_rdf.prs10_isports_rdf.VOrder AS SELECT "Order-num" AS Order_num, "Cust-Num" AS Cust_Num, "Order-Date" AS Order_Date, "Ship-Date" AS Ship_Date, "Promise-Date" AS Promise_Date, Carrier, Instructions, PO, Terms, "Sales-Rep" AS Sales_Rep FROM isports_rdf.prs10_isports_rdf."Order";
CREATE VIEW isports_rdf.prs10_isports_rdf.VItem AS SELECT "Item-num" AS Item_num, "Item-Name" AS Item_Name, "Cat-Page" AS Cat_Page, Price, "Cat-Description" AS Cat_Description, "On-hand" AS On_hand, Allocated, "Re-Order" AS Re_Order, "On-Order" AS On_Order FROM isports_rdf.prs10_isports_rdf.Item;
CREATE VIEW isports_rdf.prs10_isports_rdf.VOrder_Line AS SELECT "Order-num" AS Order_num, "Line-num" AS Line_num, "Item-num" AS Item_num, Price, Qty, Discount, "Extended-Price" AS Extended_Price, Backorder FROM isports_rdf.prs10_isports_rdf."Order-Line";
CREATE VIEW isports_rdf.prs10_isports_rdf.VInvoice AS SELECT "Invoice-Num" AS Invoice_Num, "Cust-Num" AS Cust_Num, "Invoice-Date" AS Invoice_Date, Amount, "Total-Paid" AS Total_Paid, Adjustment, "Order-Num" AS Order_Num, "Ship-Charge" AS Ship_Charge FROM isports_rdf.prs10_isports_rdf.Invoice;
CREATE VIEW isports_rdf.prs10_isports_rdf.VLocal_Default AS SELECT Country, "Region1-Label" AS Region1_Label, "Region2-Label" AS Region2_Label, "Postal-Label" AS Postal_Label, "Postal-Format" AS Postal_Format, "Tel-Format" AS Tel_Format, "Date-Format" AS Date_Format, "Currency-Symbol" AS Currency_Symbol FROM isports_rdf.prs10_isports_rdf."Local-Default";
CREATE VIEW isports_rdf.prs10_isports_rdf.VRef_Call AS SELECT "Call-Num" AS Call_Num, "Cust-Num" AS Cust_Num, "Call-Date" AS Call_Date, "Sales-Rep" AS Sales_Rep, Parent, Txt FROM isports_rdf.prs10_isports_rdf."Ref-Call";
CREATE VIEW isports_rdf.prs10_isports_rdf.VSalesrep AS SELECT "Rep-Name" AS Rep_Name, Region, "Sales-Rep" AS Sales_Rep, "Month-Quota" AS Month_Quota FROM isports_rdf.prs10_isports_rdf.Salesrep;
CREATE VIEW isports_rdf.prs10_isports_rdf.VState AS SELECT State, "State-Name" AS State_Name, Region FROM isports_rdf.prs10_isports_rdf.State;
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VCustomer TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VOrder TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VItem TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VOrder_Line TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VInvoice TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VLocal_Default TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VRef_Call TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VSalesrep TO "SPARQL", "SPARQL_UPDATE";
GRANT SELECT ON isports_rdf.prs10_isports_rdf.VState TO "SPARQL", "SPARQL_UPDATE";
-------- Create rdfs:Class definitions ----------------------------
ttlp (
'
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix customer: <http://localhost:8890/schemas/progress/isports/customer/> .
@prefix order: <http://localhost:8890/schemas/progress/isports/order/> .
@prefix item: <http://localhost:8890/schemas/progress/isports/item/> .
@prefix orderline: <http://localhost:8890/schemas/progress/isports/order_line/> .
@prefix invoice: <http://localhost:8890/schemas/progress/isports/invoice/> .
@prefix localdefault: <http://localhost:8890/schemas/progress/isports/local_default/> .
@prefix refcall: <http://localhost:8890/schemas/progress/isports/ref_call/> .
@prefix salesrep: <http://localhost:8890/schemas/progress/isports/salesrep/> .
@prefix state: <http://localhost:8890/schemas/progress/isports/state/> .
customer:Customer a rdfs:Class ;
rdfs:label "Customer" ;
rdfs:comment "Progress isports Customer table" .
customer:Cust-Num a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
customer:Name a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Name" .
customer:Address a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Address" .
customer:Address2 a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Address2" .
customer:City a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "City" .
customer:State a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "State" .
customer:Country a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Country" .
customer:Phone a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Phone" .
customer:Contact a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Contact" .
customer:Sales-Rep a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
customer:Comments a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Comments" .
customer:Credit-Limit a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:decimal ;
rdfs:label "Credit-Limit" .
customer:Balance a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:decimal ;
rdfs:label "Balance" .
customer:Terms a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Terms" .
customer:Discount a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:integer ;
rdfs:label "Discount" .
customer:Postal-Code a rdf:Property ;
rdfs:domain customer:Customer ;
rdfs:range xsd:string ;
rdfs:label "Postal-Code" .
order:Order a rdfs:Class ;
rdfs:label "Order" ;
rdfs:comment "Progress isports Order table" .
order:Order-num a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:integer ;
rdfs:label "Order-num" .
order:Cust-Num a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
order:Order-Date a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:date ;
rdfs:label "Order-Date" .
order:Ship-Date a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:date ;
rdfs:label "Ship-Date" .
order:Promise-Date a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:date ;
rdfs:label "Promise-Date" .
order:Carrier a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Carrier" .
order:Instructions a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Instructions" .
order:PO a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "PO" .
order:Terms a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Terms" .
order:Sales-Rep a rdf:Property ;
rdfs:domain order:Order ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
item:Item a rdfs:Class ;
rdfs:label "Item" ;
rdfs:comment "Progress isports Item table" .
item:Item-num a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Item-num" .
item:Item-Name a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:string ;
rdfs:label "Item-Name" .
item:Cat-Page a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Cat-Page" .
item:Price a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:decimal ;
rdfs:label "Price" .
item:Cat-Description a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:string ;
rdfs:label "Cat-Description" .
item:On-hand a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "On-hand" .
item:Allocated a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Allocated" .
item:Re-Order a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "Re-Order" .
item:On-Order a rdf:Property ;
rdfs:domain item:Item ;
rdfs:range xsd:integer ;
rdfs:label "On-Order" .
orderline:Order-Line a rdfs:Class ;
rdfs:label "Order-Line" ;
rdfs:comment "Progress isports Order-Line table" .
orderline:Order-num a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Order-num" .
orderline:Line-num a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Line-num" .
orderline:Item-num a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Item-num" .
orderline:Price a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:decimal ;
rdfs:label "Price" .
orderline:Qty a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Qty" .
orderline:Discount a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:integer ;
rdfs:label "Discount" .
orderline:Extended-Price a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:decimal ;
rdfs:label "Extended-Price" .
orderline:Backorder a rdf:Property ;
rdfs:domain orderline:Order-Line ;
rdfs:range xsd:byte ;
rdfs:label "Backorder" .
invoice:Invoice a rdfs:Class ;
rdfs:label "Invoice" ;
rdfs:comment "Progress isports Invoice table" .
invoice:Invoice-Num a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:integer ;
rdfs:label "Invoice-Num" .
invoice:Cust-Num a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
invoice:Invoice-Date a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:date ;
rdfs:label "Invoice-Date" .
invoice:Amount a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Amount" .
invoice:Total-Paid a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Total-Paid" .
invoice:Adjustment a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Adjustment" .
invoice:Order-Num a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:integer ;
rdfs:label "Order-Num" .
invoice:Ship-Charge a rdf:Property ;
rdfs:domain invoice:Invoice ;
rdfs:range xsd:decimal ;
rdfs:label "Ship-Charge" .
localdefault:Local-Default a rdfs:Class ;
rdfs:label "Local-Default" ;
rdfs:comment "Progress isports Local-Default table" .
localdefault:Country a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Country" .
localdefault:Region1-Label a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Region1-Label" .
localdefault:Region2-Label a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Region2-Label" .
localdefault:Postal-Label a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Postal-Label" .
localdefault:Postal-Format a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Postal-Format" .
localdefault:Tel-Format a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Tel-Format" .
localdefault:Date-Format a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Date-Format" .
localdefault:Currency-Symbol a rdf:Property ;
rdfs:domain localdefault:Local-Default ;
rdfs:range xsd:string ;
rdfs:label "Currency-Symbol" .
refcall:Ref-Call a rdfs:Class ;
rdfs:label "Ref-Call" ;
rdfs:comment "Progress isports Ref-Call table" .
refcall:Call-Num a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Call-Num" .
refcall:Cust-Num a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:integer ;
rdfs:label "Cust-Num" .
refcall:Call-Date a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:date ;
rdfs:label "Call-Date" .
refcall:Sales-Rep a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
refcall:Parent a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Parent" .
refcall:Txt a rdf:Property ;
rdfs:domain refcall:Ref-Call ;
rdfs:range xsd:string ;
rdfs:label "Txt" .
salesrep:Salesrep a rdfs:Class ;
rdfs:label "Salesrep" ;
rdfs:comment "Progress isports Salesrep table" .
salesrep:Sales-Rep a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Sales-Rep" .
salesrep:Rep-Name a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Rep-Name" .
salesrep:Region a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Region" .
salesrep:Month-Quota a rdf:Property ;
rdfs:domain salesrep:Salesrep ;
rdfs:range xsd:string ;
rdfs:label "Month-Quota" .
state:State a rdfs:Class ;
rdfs:label "State" ;
rdfs:comment "Progress isports State table" .
state:State_ a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "State" .
state:State-Name a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "State-Name" .
state:Region a rdf:Property ;
rdfs:domain state:State ;
rdfs:range xsd:string ;
rdfs:label "Region" .
', '', 'http://localhost:8890/schemas/progress/isports', 0);
----------- Create IRI Classes -------------
SPARQL
prefix customer: <http://localhost:8890/schemas/progress/isports/customer/>
prefix order: <http://localhost:8890/schemas/progress/isports/order/>
prefix item: <http://localhost:8890/schemas/progress/isports/item/>
prefix orderline: <http://localhost:8890/schemas/progress/isports/order_line/>
prefix invoice: <http://localhost:8890/schemas/progress/isports/invoice/>
prefix localdefault: <http://localhost:8890/schemas/progress/isports/local_default/>
prefix refcall: <http://localhost:8890/schemas/progress/isports/ref_call/>
prefix salesrep: <http://localhost:8890/schemas/progress/isports/salesrep/>
prefix state: <http://localhost:8890/schemas/progress/isports/state/>
create iri class customer:customer_iri
"http://localhost:8890/progress/isports/customer/%d#this"
(in Cust_Num integer not null) .
create iri class order:order_iri
"http://localhost:8890/progress/isports/order/%d#this"
(in Order_Num integer not null) .
create iri class item:item_iri
"http://localhost:8890/progress/isports/item/%d#this"
(in Item_num integer not null) .
create iri class orderline:order-line_iri
"http://localhost:8890/progress/isports/order-line/%d_%d#this"
(in Order_num integer not null, in Line_num integer not null) .
create iri class invoice:invoice_iri
"http://localhost:8890/progress/isports/invoice/%d#this"
(in Invoice_Num integer not null) .
create iri class localdefault:local-default_iri
"http://localhost:8890/progress/isports/local-default/%U#this"
(in Country varchar not null) .
create iri class refcall:ref-call_iri
"http://localhost:8890/progress/isports/ref-call/%U#this"
(in Call_Num varchar not null) .
create iri class salesrep:salesrep_iri
"http://localhost:8890/progress/isports/salesrep/%U#this"
(in Sales_Rep varchar not null) .
create iri class state:state_iri
"http://localhost:8890/progress/isports/state/%U#this"
(in State varchar not null) .
;
------------- Create Quad Store ------------------------------------
SPARQL
prefix customer: <http://localhost:8890/schemas/progress/isports/customer/>
prefix order: <http://localhost:8890/schemas/progress/isports/order/>
prefix item: <http://localhost:8890/schemas/progress/isports/item/>
prefix orderline: <http://localhost:8890/schemas/progress/isports/order_line/>
prefix invoice: <http://localhost:8890/schemas/progress/isports/invoice/>
prefix localdefault: <http://localhost:8890/schemas/progress/isports/local_default/>
prefix refcall: <http://localhost:8890/schemas/progress/isports/ref_call/>
prefix salesrep: <http://localhost:8890/schemas/progress/isports/salesrep/>
prefix state: <http://localhost:8890/schemas/progress/isports/state/>
alter quad storage virtrdf:DefaultQuadStorage
from isports_rdf.prs10_isports_rdf.VCustomer as Customer_tbl
from isports_rdf.prs10_isports_rdf.VOrder as Order_tbl
from isports_rdf.prs10_isports_rdf.VItem as Item_tbl
from isports_rdf.prs10_isports_rdf.VOrder_Line as Order_Line_tbl
from isports_rdf.prs10_isports_rdf.VInvoice as Invoice_tbl
from isports_rdf.prs10_isports_rdf.VRef_Call as Ref_Call_tbl
from isports_rdf.prs10_isports_rdf.VRef_Call as Ref_Call_tbl_1 -- Additional Ref_Call_tbl_1 alias required to represent recursive FK relationship (refcall:has_parent) below.
from isports_rdf.prs10_isports_rdf.VLocal_Default as Local_Default_tbl
from isports_rdf.prs10_isports_rdf.VSalesrep as Salesrep_tbl
from isports_rdf.prs10_isports_rdf.VState as State_tbl
{
create virtrdf:progress_isports as graph <http://localhost:8890/progress/isports>
{
customer:customer_iri (Customer_tbl.Cust_Num) a customer:Customer as virtrdf:customer_pk ;
customer:Cust-Num Customer_tbl.Cust_Num as virtrdf:Customer_cust-num ;
customer:Name Customer_tbl.Name as virtrdf:Customer_name ;
customer:Address Customer_tbl.Address as virtrdf:Customer_address ;
customer:Address2 Customer_tbl.Address2 as virtrdf:Customer_address2 ;
customer:City Customer_tbl.City as virtrdf:Customer_city ;
customer:State Customer_tbl.State as virtrdf:Customer_state ;
customer:Country Customer_tbl.Country as virtrdf:Customer_country ;
customer:Phone Customer_tbl.Phone as virtrdf:Customer_phone ;
customer:Contact Customer_tbl.Contact as virtrdf:Customer_contact ;
customer:Sales-Rep Customer_tbl.Sales_Rep as virtrdf:Customer_sales_rep ;
customer:Comments Customer_tbl.Comments as virtrdf:Customer_comments ;
customer:Credit-Limit Customer_tbl.Credit_Limit as virtrdf:Customer_credit-limit ;
customer:Balance Customer_tbl.Balance as virtrdf:Customer_balance ;
customer:Terms Customer_tbl.Terms as virtrdf:Customer_terms ;
customer:Discount Customer_tbl.Discount as virtrdf:Customer_discount ;
customer:Postal-Code Customer_tbl.Postal_Code as virtrdf:Customer_postal-code ;
customer:from_state state:state_iri (State_tbl.State) where ( ^{Customer_tbl.}^.State = ^{State_tbl.}^.State ) as virtrdf:Customer_from_state ;
customer:has_sales_rep salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{Customer_tbl.}^.Sales_Rep = ^{Salesrep_tbl.}^.Sales_Rep ) as virtrdf:Customer_has_sales_rep ;
customer:has_local_default localdefault:local-default_iri (Local_Default_tbl.Country) where ( ^{Customer_tbl.}^.Country = ^{Local_Default_tbl.}^.Country ) as virtrdf:Customer_has_local_default ;
customer:placed_order order:order_iri (Order_tbl.Order_num) where ( ^{Customer_tbl.}^.Cust_Num = ^{Order_tbl.}^.Cust_Num ) as virtrdf:Customer_placed_order ;
customer:has_invoice invoice:invoice_iri (Invoice_tbl.Invoice_Num) where ( ^{Customer_tbl.}^.Cust_Num = ^{Invoice_tbl.}^.Cust_Num ) as virtrdf:Customer_has_invoice ;
customer:ref_call refcall:ref-call_iri (Ref_Call_tbl.Call_Num) where ( ^{Customer_tbl.}^.Cust_Num = ^{Ref_Call_tbl.}^.Cust_Num ) as virtrdf:Customer_ref-call .
order:order_iri (Order_tbl.Order_num) a order:Order as virtrdf:order_pk ;
order:Order-num Order_tbl.Order_num as virtrdf:Order_order-num ;
order:Cust-Num Order_tbl.Cust_Num as virtrdf:Order_cust_num ;
order:Order-Date Order_tbl.Order_Date as virtrdf:Order_order-date ;
order:Ship-Date Order_tbl.Ship_Date as virtrdf:Order_ship-date ;
order:Promise-Date Order_tbl.Promise_Date as virtrdf:Order_promise-date ;
order:Carrier Order_tbl.Carrier as virtrdf:Order_carrier ;
order:Instructions Order_tbl.Instructions as virtrdf:Order_instructions ;
order:PO Order_tbl.PO as virtrdf:Order_po ;
order:Terms Order_tbl.Terms as virtrdf:Order_terms ;
order:placed_by customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Order_tbl.}^.Cust_Num = ^{Customer_tbl.}^.Cust_Num ) as virtrdf:Order_placed_by ;
order:Sales-Rep salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{Order_tbl.}^.Sales_Rep = ^{Salesrep_tbl.}^.Sales_Rep ) as virtrdf:Order_sales_rep ;
order:invoiced_on invoice:invoice_iri (Invoice_tbl.Invoice_Num) where ( ^{Order_tbl.}^.Order_num = ^{Invoice_tbl.}^.Order_Num ) as virtrdf:Order_invoiced_on ;
order:has_lines orderline:order-line_iri (Order_Line_tbl.Order_num, Order_Line_tbl.Line_num) where ( ^{Order_tbl.}^.Order_num = ^{Order_Line_tbl.}^.Order_num ) as virtrdf:Order_has_lines .
item:item_iri (Item_tbl.Item_num) a item:Item as virtrdf:item_pk ;
item:Item-num Item_tbl.Item_num as virtrdf:item_item-num ;
item:Item-Name Item_tbl.Item_Name as virtrdf:Item_item-Name ;
item:Cat-Page Item_tbl.Cat_Page as virtrdf:Item_cat-page ;
item:Price Item_tbl.Price as virtrdf:Item_price ;
item:Cat-Description Item_tbl.Cat_Description as virtrdf:Item_cat-description ;
item:On-hand Item_tbl.On_hand as virtrdf:Item_on-hand ;
item:Allocated Item_tbl.Allocated as virtrdf:Item_allocated ;
item:Re-Order Item_tbl.Re_Order as virtrdf:Item_re-order ;
item:On-Order Item_tbl.On_Order as virtrdf:Item_on-order ;
item:order_line orderline:order-line_iri (Order_Line_tbl.Order_num, Order_Line_tbl.Line_num) where ( ^{Item_tbl.}^.Item_num = ^{Order_Line_tbl.}^.Item_num ) as virtrdf:Item_order_line .
orderline:order-line_iri (Order_Line_tbl.Order_num, Order_Line_tbl.Line_num) a orderline:Order-Line as virtrdf:order-line_pk ;
orderline:Line-num Order_Line_tbl.Line_num as virtrdf:Order-Line_line-num ;
orderline:Price Order_Line_tbl.Price as virtrdf:Order-Line_price ;
orderline:Qty Order_Line_tbl.Qty as virtrdf:Order-Line_qty ;
orderline:Discount Order_Line_tbl.Discount as virtrdf:Order-Line_discount ;
orderline:Extended-Price Order_Line_tbl.Extended_Price as virtrdf:Order-Line_extended-price ;
orderline:Backorder Order_Line_tbl.Backorder as virtrdf:Order-Line_backorder ;
orderline:Order-num order:order_iri (Order_tbl.Order_num) where ( ^{Order_Line_tbl.}^.Order_num = ^{Order_tbl.}^.Order_num ) as virtrdf:Order_Line_order_num ;
orderline:Item-num item:item_iri (Item_tbl.Item_num) where ( ^{Order_Line_tbl.}^.Item_num = ^{Item_tbl.}^.Item_num ) as virtrdf:Order_Line_item_num .
invoice:invoice_iri (Invoice_tbl.Invoice_Num) a invoice:Invoice as virtrdf:invoice_pk ;
invoice:Invoice-Num Invoice_tbl.Invoice_Num as virtrdf:Invoice_invoice-num ;
invoice:Cust-Num Invoice_tbl.Cust_Num as virtrdf:Invoice_cust_num ;
invoice:Invoice-Date Invoice_tbl.Invoice_Date as virtrdf:Invoice_invoice-date ;
invoice:Amount Invoice_tbl.Amount as virtrdf:Invoice_amount ;
invoice:Total-Paid Invoice_tbl.Total_Paid as virtrdf:Invoice_total-paid ;
invoice:Adjustment Invoice_tbl.Adjustment as virtrdf:Invoice_adjustment ;
invoice:Order-Num Invoice_tbl.Order_Num as virtrdf:Invoice_order-num ;
invoice:Ship-Charge Invoice_tbl.Ship_Charge as virtrdf:Invoice_ship-charge ;
invoice:invoiced_to customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Invoice_tbl.}^.Cust_Num = ^{Customer_tbl.}^.Cust_Num ) as virtrdf:Invoice_invoiced_to ;
invoice:Order-Num order:order_iri (Order_tbl.Order_num) where ( ^{Invoice_tbl.}^.Order_Num = ^{Order_tbl.}^.Order_num ) as virtrdf:Invoice_order_num .
localdefault:local-default_iri (Local_Default_tbl.Country) a localdefault:Local-Default as virtrdf:local-default_pk ;
localdefault:Country Local_Default_tbl.Country as virtrdf:local-default_country ;
localdefault:Region1-Label Local_Default_tbl.Region1_Label as virtrdf:Local-Default_region1-label ;
localdefault:Region2-Label Local_Default_tbl.Region2_Label as virtrdf:Local-Default_region2-label ;
localdefault:Postal-Label Local_Default_tbl.Postal_Label as virtrdf:Local-Default_postal-label ;
localdefault:Postal-Format Local_Default_tbl.Postal_Format as virtrdf:Local-Default_postal-format ;
localdefault:Tel-Format Local_Default_tbl.Tel_Format as virtrdf:Local-Default_tel-format ;
localdefault:Date-Format Local_Default_tbl.Date_Format as virtrdf:Local-Default_date-format ;
localdefault:Currency-Symbol Local_Default_tbl.Currency_Symbol as virtrdf:Local-Default_currency-symbol ;
localdefault:has_customer customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Local_Default_tbl.}^.Country = ^{Customer_tbl.}^.Country ) as virtrdf:Local-Default_has_customer .
refcall:ref-call_iri (Ref_Call_tbl.Call_Num) a refcall:Ref-Call as virtrdf:ref-call_pk ;
refcall:Call-Num Ref_Call_tbl.Call_Num as virtrdf:Ref-Call_call-num ;
refcall:Cust-Num Ref_Call_tbl.Cust_Num as virtrdf:Ref-Call_cust-num ;
refcall:Call-Date Ref_Call_tbl.Call_Date as virtrdf:Ref-Call_call-date ;
refcall:Sales-Rep Ref_Call_tbl.Sales_Rep as virtrdf:Ref-sales-rep ;
refcall:Parent Ref_Call_tbl.Parent as virtrdf:Ref-Call_parent ;
refcall:Txt Ref_Call_tbl.Txt as virtrdf:Ref-Call_txt ;
refcall:made_to customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Ref_Call_tbl.}^.Cust_Num = ^{Customer_tbl.}^.Cust_Num ) as virtrdf:Ref-Call_made_to ;
refcall:made_by salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{Ref_Call_tbl.}^.Sales_Rep = ^{Salesrep_tbl.}^.Sales_Rep ) as virtrdf:Ref-Call_made-by ;
refcall:has_parent refcall:ref-call_iri (Ref_Call_tbl_1.Call_Num) where ( ^{Ref_Call_tbl.}^.Parent = ^{Ref_Call_tbl_1.}^.Call_Num ) as virtrdf:Ref-Call_has_parent .
salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) a salesrep:Salesrep as virtrdf:salesrep_pk ;
salesrep:Sales-Rep Salesrep_tbl.Sales_Rep as virtrdf:Salesrep_sales-rep ;
salesrep:Region Salesrep_tbl.Region as virtrdf:Salesrep_region ;
salesrep:Rep-Name Salesrep_tbl.Rep_Name as virtrdf:Salesrep_rep-name ;
salesrep:Month-Quota Salesrep_tbl.Month_Quota as virtrdf:Salesrep_month-quota ;
salesrep:is_sales_rep_for customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{Salesrep_tbl.}^.Sales_Rep = ^{Customer_tbl.}^.Sales_Rep ) as virtrdf:Salesrep_is_sales_rep_for ;
salesrep:has_order order:order_iri (Order_tbl.Order_num) where ( ^{Salesrep_tbl.}^.Sales_Rep = ^{Order_tbl.}^.Sales_Rep ) as virtrdf:Salesrep_has_order ;
salesrep:manages_region state:state_iri (State_tbl.State) where ( ^{Salesrep_tbl.}^.Region = ^{State_tbl.}^.Region ) as virtrdf:Salesrep_manages_region ;
salesrep:made_call refcall:ref-call_iri (Ref_Call_tbl.Call_Num) where ( ^{Salesrep_tbl.}^.Sales_Rep = ^{Ref_Call_tbl.}^.Sales_Rep ) as virtrdf:Ref-Call_made_call .
state:state_iri (State_tbl.State) a state:State as virtrdf:state_pk ;
state:State_ State_tbl.State as virtrdf:State_state ;
state:State-Name State_tbl.State_Name as virtrdf:State_state-name ;
state:Region State_tbl.Region as virtrdf:State_region ;
state:has_customer customer:customer_iri (Customer_tbl.Cust_Num) where ( ^{State_tbl.}^.State = ^{Customer_tbl.}^.State ) as virtrdf:State_has_customer ;
state:has_sales_rep salesrep:salesrep_iri (Salesrep_tbl.Sales_Rep) where ( ^{State_tbl.}^.Region = ^{Salesrep_tbl.}^.Region ) as virtrdf:State_has_sales_rep .
} .
} .
;
-- Setup re-write rules that enable de-referencing of RDF based descriptions of
-- iSports Entities
-- Cleanup old rules
delete from db.dba.url_rewrite_rule_list where urrl_list like 'progress_isports_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'progress_isports_rule%';
-- Create rules for handling HTML representation of Entity (resource) description requests
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
-- Create rules for handling RDF based representations (N3 or RDF/XML) of Entity (resource) descriptions
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=DESCRIBE+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+%%3Chttp%%3A//localhost%%3A8890%U%%23this%%3E+FROM+%%3Chttp%%3A//localhost%%3A8890/progress/isports%%3E&format=%U',
vector('path', 'path', '*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'progress_isports_rule_list1',
1,
vector (
'progress_isports_rule1',
'progress_isports_rule2'
));
-- Setup OWL ontology data space that describes iSports entities
-- Create Virtual Directory access point
VHOST_REMOVE (lpath=>'/progress/isports');
VHOST_DEFINE (
lpath=>'/progress/isports',
ppath=>'/DAV/progress/isports/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'progress_isports_rule_list1')
);
delete from db.dba.url_rewrite_rule_list where urrl_list like 'progress_isports_schemas_rule%';
delete from db.dba.url_rewrite_rule where urr_rule like 'progress_isports_schemas_rule%';
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_schemas_rule1',
1,
'(/[^#]*)',
vector('path'),
1,
'/about/html/http/^{URIQADefaultHost}^%s',
vector('path'),
null,
'(text/html)|(\\*/\\*)',
0,
303
);
DB.DBA.URLREWRITE_CREATE_REGEX_RULE (
'progress_isports_schemas_rule2',
1,
'(/[^#]*)',
vector('path'),
1,
'/sparql?query=CONSTRUCT+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}%%0D%%0AFROM+%%3Chttp%%3A//localhost%%3A8890/schemas/progress/isports%%3E+%%0D%%0AWHERE+{+%%3Chttp%%3A//localhost%%3A8890%U%%3E+%%3Fp+%%3Fo+}&format=%U',
vector('path','path','*accept*'),
null,
'(text/rdf.n3)|(application/rdf.xml)',
0,
null
);
DB.DBA.URLREWRITE_CREATE_RULELIST (
'progress_isports_schemas_rule_list1',
1,
vector (
'progress_isports_schemas_rule1',
'progress_isports_schemas_rule2'
));
-- ensure a VD for the IRIs which begins with /
VHOST_REMOVE (lpath=>'/schemas/progress/isports');
VHOST_DEFINE (
lpath=>'/schemas/progress/isports',
ppath=>'/DAV/schemas/progress/isports/',
is_dav=>1,
vsp_user=>'dba',
is_brws=>0,
opts=>vector ('url_rewrite', 'progress_isports_schemas_rule_list1')
);
DB.DBA.XML_SET_NS_DECL ('customer', 'http://^{URIQADefaultHost}^/schemas/progress/isports/customer/', 2);
DB.DBA.XML_SET_NS_DECL ('order', 'http://^{URIQADefaultHost}^/schemas/progress/isports/order/', 2);
DB.DBA.XML_SET_NS_DECL ('item', 'http://^{URIQADefaultHost}^/schemas/progress/isports/item/', 2);
DB.DBA.XML_SET_NS_DECL ('orderline', 'http://^{URIQADefaultHost}^/schemas/progress/isports/order_line/', 2);
DB.DBA.XML_SET_NS_DECL ('invoice', 'http://^{URIQADefaultHost}^/schemas/progress/isports/invoice/', 2);
DB.DBA.XML_SET_NS_DECL ('localdefault', 'http://^{URIQADefaultHost}^/schemas/progress/isports/local_default/', 2);
DB.DBA.XML_SET_NS_DECL ('refcall', 'http://^{URIQADefaultHost}^/schemas/progress/isports/ref_call/', 2);
DB.DBA.XML_SET_NS_DECL ('salesrep', 'http://^{URIQADefaultHost}^/schemas/progress/isports/salesrep/', 2);
DB.DBA.XML_SET_NS_DECL ('state', 'http://^{URIQADefaultHost}^/schemas/progress/isports/state/', 2);
]]></programlisting>
</sect4>
<sect4 id="rdfviewnorthwindexample1"><title>Simple Mapping Example -- Northwind RDF View</title>
<para>Here is example of the basic Northwind RDF Views deployment. The sequence of operations is very common for adding SPARQL access to existing application.</para>
<para>There exist few important questions to answer. Who should have access to data behind RDF View? Should someone have access to other sorts of RDF data but not to the new View? What are applications that should be interoperable with the new RDF data source? Are there any applications that produce similar data but that data sould be kept apart from data made by view? How to ensure that deployment the view will not cause problems for other applications?</para>
<para>First of all, we decide whether the default web service endpoint should have access to the data in question. If it should then we have to grant SELECT privileges to the account "SPARQL" that is used for the default endpoint; if it should not but some custom edpoint should then grant to the owner account of that account. Granting access is less trivial that it is usual. On one hand, those who can make SQL SELECT statements on application's tables can also make SPARQL queries on RDF View over that tables, because it makes SQL inside. On the other hand, those who do not intend to query that data at all may get unexpected "permission denied" errors on queries that worked fine before adding an RDF View. If SPARQL compiler can not prove that the query can not access data from the view then it will generate SQL code that will access tables behind the view. In some cases permission problems should be resolved by creating RDF View in a separate <link linkend="rdfviewconfiguringrdfstorages">RDF storage</link>. In this example, data are public:</para>
<programlisting><![CDATA[
use DB;
GRANT SELECT ON "Demo"."demo"."Products" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Suppliers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Shippers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Categories" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Customers" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Employees" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Orders" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Order_Details" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Countries" TO "SPARQL";
GRANT SELECT ON "Demo"."demo"."Provinces" TO "SPARQL";
]]></programlisting>
<para>Interoperability is the next question. The example is not
interoperable with anything so in can provide data of any form, a real
application will probably use some ontology from external
source. Sometimes data should be converted from internal application's
representation to something different (such as metric to imperial or
ATT country code to two-character country id); sometimes composed IRIs
should follow special rules; <link
linkend="rdfviewiriusingfunction">function-based IRI classes</link>
may help in that cases. As this is the first example, only plain
format-string-based IRI classes are used.</para>
<para>We should also ensure that data generated by the new view will
not be accidentally mixed with other data of the database. For that
purpose the example will use a unique graph name that includes both
application name and host name. In addition, the script will drop
declarations that might remain from a previous run of the same script. The
script is executed many times during the development so erasing
previous version is worth writing. It will report an error if there's
nothing to erase but it's better than unpredictable errors due to
writing new declarations over existing ones.</para>
<note><para>Making graph name unique for every host is not needed if
the application is supposed to be "local" and nobody will
access more than one installation of the application. If this is
the case, use some fixed graph IRI, not necessarily starting with
hostname at all; this is much more convenient for querying because you
don't have to calculate the graph name in each query. With fixed graph
in use, it is still possible to clone the RDF View to map to a unique
graph as soon as the application become "public" and requires
merging data from many installations.</para></note>
<programlisting><![CDATA[
SPARQL drop quad map graph iri("http://^{URIQADefaultHost}^/Northwind")
;
SPARQL drop quad map virtrdf:NorthwindDemo
;
]]></programlisting>
<note><para>The <emphasis>^{URIQADefaultHost}^</emphasis> macro is replaced with the value of <emphasis>DefaultHost</emphasis> parameter of <link linkend="ini_URIQA">[URIQA]</link> section of configuration file. The IRI is written as <emphasis>iri("http://^{URIQADefaultHost}^/Northwind")</emphasis>, not as <emphasis><http://^{URIQADefaultHost}^/Northwind></emphasis> because macro of this sort works only inside SPARQL string values.</para></note>
<para>Now it's safe to create IRI classes needed for the view. If
these classes are used only in the view we define then it is safe to
create all of them in a single statement. If some of them are used
across multiple declarations then errors may occur. it is impossible
to redefine an IRI class that is in use; the compiler will try to
avoid reporting errors by checking whether the new declaration is
identical to the existing one and by trying garbage collection in hope
that the IRI class is used only in garbage, but errors may occur
anyway. Thus it is better to declare "shared" IRI classes by
individual statements and group together only "private" IRI
classes of a view. If a "class redefinition" error occurs in
the middle of a group then "undefined class" errors may
occur after because the processing of the group was interrupted before
rest of group was not executed. When in trouble, try <link
linkend="fn_rdf_audit_metadata"><function>DB.DBA.RDF_AUDIT_METADATA</function></link>
procedure.</para>
<programlisting><![CDATA[
SPARQL
create iri class northwind:Category "http://^{URIQADefaultHost}^/Northwind/Category/%d#this" (in category_id integer not null) .
create iri class northwind:Shipper "http://^{URIQADefaultHost}^/Northwind/Shipper/%d#this" (in shipper_id integer not null) .
create iri class northwind:Supplier "http://^{URIQADefaultHost}^/Northwind/Supplier/%d#this" (in supplier_id integer not null) .
create iri class northwind:Product "http://^{URIQADefaultHost}^/Northwind/Product/%d#this" (in product_id integer not null) .
create iri class northwind:Customer "http://^{URIQADefaultHost}^/Northwind/Customer/%U#this" (in customer_id varchar not null) .
create iri class northwind:Employee "http://^{URIQADefaultHost}^/Northwind/Employee/%U%U%d#this" (in employee_firstname varchar not null, in employee_lastname varchar not null, in employee_id integer not null) .
create iri class northwind:Order "http://^{URIQADefaultHost}^/Northwind/Order/%d#this" (in order_id integer not null) .
create iri class northwind:CustomerContact "http://^{URIQADefaultHost}^/Northwind/CustomerContact/%U#this" (in customer_id varchar not null) .
create iri class northwind:OrderLine "http://^{URIQADefaultHost}^/Northwind/OrderLine/%d/%d#this" (in order_id integer not null, in product_id integer not null) .
create iri class northwind:Province "http://^{URIQADefaultHost}^/Northwind/Province/%U/%U#this" (in country_name varchar not null, in province_name varchar not null) .
create iri class northwind:Country "http://^{URIQADefaultHost}^/Northwind/Country/%U#this" (in country_name varchar not null) .
create iri class northwind:Flag "http://^{URIQADefaultHost}^%U#this" (in flag_path varchar not null) .
create iri class northwind:dbpedia_iri "http://dbpedia.org/resource/%U" (in uname varchar not null) .
create iri class northwind:EmployeePhoto "http://^{URIQADefaultHost}^/DAV/VAD/demo/sql/EMP%d#this" (in emp_id varchar not null) .
create iri class northwind:CategoryPhoto "http://^{URIQADefaultHost}^/DAV/VAD/demo/sql/CAT%d#this" (in category_id varchar not null) .
;
]]></programlisting>
<para>One IRI class per subject type; format strings begin with same host but different directory names so this will let the compiler to guess the type of subject by the text of IRI. Most of declarations are <link linkend="rdfviewbijandreturns">bijections</link> and may get <emphasis>option (bijection)</emphasis> hint but these format strings are so simple that the compiler may understand it by itself.
(<emphasis>northwind:Employee</emphasis> is not a bijection because <link linkend="fn_sprintf_inverse"><function>sprintf_inverse</function></link> will be unable to split the tail of IRI string and find the boundary between first and last name.)</para>
<para>The final operation is extending the default quad storage with new tree of quad map patterns.</para>
<programlisting><![CDATA[
SPARQL
prefix northwind: <http://demo.openlinksw.com/schemas/northwind#>
prefix oplsioc: <http://www.openlinksw.com/schemas/oplsioc#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix sioc: <http://rdfs.org/sioc/ns#>
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#>
alter quad storage virtrdf:DefaultQuadStorage
from Demo.demo.Products as products
from Demo.demo.Suppliers as suppliers
from Demo.demo.Shippers as shippers
from Demo.demo.Categories as categories
from Demo.demo.Customers as customers
from Demo.demo.Employees as employees
from Demo.demo.Orders as orders
from Demo.demo.Order_Details as order_lines
from Demo.demo.Countries as countries
from Demo.demo.Provinces as provinces
where (^{suppliers.}^.Country = ^{countries.}^.Name)
where (^{customers.}^.Country = ^{countries.}^.Name)
where (^{employees.}^.Country = ^{countries.}^.Name)
where (^{orders.}^.ShipCountry = ^{countries.}^.Name)
{
create virtrdf:NorthwindDemo as graph iri ("http://^{URIQADefaultHost}^/Northwind") option (exclusive)
{
northwind:CustomerContact (customers.CustomerID)
a foaf:Person
as virtrdf:CustomerContact-foaf_Person .
northwind:CustomerContact (customers.CustomerID)
a northwind:CustomerContact
as virtrdf:CustomerContact-CustomerContact;
foaf:name customers.ContactName
as virtrdf:CustomerContact-contact_name ;
foaf:phone customers.Phone
as virtrdf:CustomerContact-foaf_phone ;
northwind:is_contact_at northwind:Customer (customers.CustomerID)
as virtrdf:CustomerContact-is_contact_at ;
northwind:country northwind:Country (customers.Country)
as virtrdf:CustomerContact-country ;
rdfs:isDefinedBy northwind:customercontact_iri (customers.CustomerID) ;
rdfs:isDefinedBy northwind:CustomerContact (customers.CustomerID) .
northwind:Country (customers.Country)
northwind:is_country_of
northwind:CustomerContact (customers.CustomerID) as virtrdf:CustomerContact-is_country_of .
northwind:Product (products.ProductID)
a northwind:Product
as virtrdf:Product-ProductID ;
northwind:has_category northwind:Category (products.CategoryID)
as virtrdf:Product-product_has_category ;
northwind:has_supplier northwind:Supplier (products.SupplierID)
as virtrdf:Product-product_has_supplier ;
northwind:productName products.ProductName
as virtrdf:Product-name_of_product ;
northwind:quantityPerUnit products.QuantityPerUnit
as virtrdf:Product-quantity_per_unit ;
northwind:unitPrice products.UnitPrice
as virtrdf:Product-unit_price ;
northwind:unitsInStock products.UnitsInStock
as virtrdf:Product-units_in_stock ;
northwind:unitsOnOrder products.UnitsOnOrder
as virtrdf:Product-units_on_order ;
northwind:reorderLevel products.ReorderLevel
as virtrdf:Product-reorder_level ;
northwind:discontinued products.Discontinued
as virtrdf:Product-discontinued ;
rdfs:isDefinedBy northwind:product_iri (products.ProductID) ;
rdfs:isDefinedBy northwind:Product (products.ProductID) .
northwind:Category (products.CategoryID)
northwind:category_of northwind:Product (products.ProductID) as virtrdf:Product-category_of .
northwind:Supplier (products.SupplierID)
northwind:supplier_of northwind:Product (products.ProductID) as virtrdf:Product-supplier_of .
northwind:Supplier (suppliers.SupplierID)
a northwind:Supplier
as virtrdf:Supplier-SupplierID ;
northwind:companyName suppliers.CompanyName
as virtrdf:Supplier-company_name ;
northwind:contactName suppliers.ContactName
as virtrdf:Supplier-contact_name ;
northwind:contactTitle suppliers.ContactTitle
as virtrdf:Supplier-contact_title ;
northwind:address suppliers.Address
as virtrdf:Supplier-address ;
northwind:city suppliers.City
as virtrdf:Supplier-city ;
northwind:dbpedia_city northwind:dbpedia_iri(suppliers.City)
as virtrdf:Supplier-dbpediacity ;
northwind:region suppliers.Region
as virtrdf:Supplier-region ;
northwind:postalCode suppliers.PostalCode
as virtrdf:Supplier-postal_code ;
northwind:country northwind:Country(suppliers.Country)
as virtrdf:Supplier-country ;
northwind:phone suppliers.Phone
as virtrdf:Supplier-phone ;
northwind:fax suppliers.Fax
as virtrdf:Supplier-fax ;
northwind:homePage suppliers.HomePage
as virtrdf:Supplier-home_page ;
rdfs:isDefinedBy northwind:supplier_iri (suppliers.SupplierID) ;
rdfs:isDefinedBy northwind:Supplier (suppliers.SupplierID) .
northwind:Country (suppliers.Country)
northwind:is_country_of
northwind:Supplier (suppliers.SupplierID) as virtrdf:Supplier-is_country_of .
northwind:Category (categories.CategoryID)
a northwind:Category
as virtrdf:Category-CategoryID ;
northwind:categoryName categories.CategoryName
as virtrdf:Category-home_page ;
northwind:description categories.Description
as virtrdf:Category-description ;
foaf:img northwind:CategoryPhoto(categories.CategoryID)
as virtrdf:Category-categories.CategoryPhoto ;
rdfs:isDefinedBy northwind:category_iri (categories.CategoryID) ;
rdfs:isDefinedBy northwind:Category (categories.CategoryID) .
northwind:CategoryPhoto(categories.CategoryID)
a northwind:CategoryPhoto
as virtrdf:Category-categories.CategoryPhotoID ;
rdfs:isDefinedBy northwind:categoryphoto_iri (categories.CategoryID) ;
rdfs:isDefinedBy northwind:CategoryPhoto(categories.CategoryID) .
northwind:Shipper (shippers.ShipperID)
a northwind:Shipper
as virtrdf:Shipper-ShipperID ;
northwind:companyName shippers.CompanyName
as virtrdf:Shipper-company_name ;
northwind:phone shippers.Phone
as virtrdf:Shipper-phone ;
rdfs:isDefinedBy northwind:shipper_iri (shippers.ShipperID) ;
rdfs:isDefinedBy northwind:Shipper (shippers.ShipperID) .
northwind:Customer (customers.CustomerID)
a northwind:Customer
as virtrdf:Customer-CustomerID2 ;
a foaf:Organization
as virtrdf:Customer-CustomerID ;
foaf:name customers.CompanyName
as virtrdf:Customer-foaf_name ;
northwind:companyName customers.CompanyName
as virtrdf:Customer-company_name ;
northwind:has_contact northwind:CustomerContact (customers.CustomerID)
as virtrdf:Customer-contact ;
northwind:country northwind:Country (customers.Country)
as virtrdf:Customer-country ;
northwind:contactName customers.ContactName
as virtrdf:Customer-contact_name ;
northwind:contactTitle customers.ContactTitle
as virtrdf:Customer-contact_title ;
northwind:address customers.Address
as virtrdf:Customer-address ;
northwind:city customers.City
as virtrdf:Customer-city ;
northwind:dbpedia_city northwind:dbpedia_iri(customers.City)
as virtrdf:Customer-dbpediacity ;
northwind:region customers.Region
as virtrdf:Customer-region ;
northwind:PostalCode customers.PostalCode
as virtrdf:Customer-postal_code ;
foaf:phone customers.Phone
as virtrdf:Customer-foaf_phone ;
northwind:phone customers.Phone
as virtrdf:Customer-phone ;
northwind:fax customers.Fax
as virtrdf:Customer-fax ;
rdfs:isDefinedBy northwind:customer_iri (customers.CustomerID) ;
rdfs:isDefinedBy northwind:Customer (customers.CustomerID) .
northwind:Country (customers.Country)
northwind:is_country_of
northwind:Customer (customers.CustomerID) as virtrdf:Customer-is_country_of .
northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID)
a northwind:Employee
as virtrdf:Employee-EmployeeID2 ;
a foaf:Person
as virtrdf:Employee-EmployeeID ;
foaf:surname employees.LastName
as virtrdf:Employee-foaf_last_name ;
northwind:lastName employees.LastName
as virtrdf:Employee-last_name ;
foaf:firstName employees.FirstName
as virtrdf:Employee-foaf_first_name ;
northwind:firstName employees.FirstName
as virtrdf:Employee-first_name ;
foaf:title employees.Title
as virtrdf:Employee-title ;
northwind:titleOfCourtesy employees.TitleOfCourtesy
as virtrdf:Employee-title_of_courtesy ;
foaf:birthday employees.BirthDate
as virtrdf:Employee-foaf_birth_date ;
northwind:birthday employees.BirthDate
as virtrdf:Employee-birth_date ;
northwind:hireDate employees.HireDate
as virtrdf:Employee-hire_date ;
northwind:address employees.Address
as virtrdf:Employee-address ;
northwind:city employees.City
as virtrdf:Employee-city ;
northwind:dbpedia_city northwind:dbpedia_iri(employees.City)
as virtrdf:Employee-dbpediacity ;
northwind:region employees.Region
as virtrdf:Employee-region ;
northwind:postalCode employees.PostalCode
as virtrdf:Employee-postal_code ;
northwind:country northwind:Country(employees.Country)
as virtrdf:Employee-country ;
foaf:phone employees.HomePhone
as virtrdf:Employee-home_phone ;
northwind:extension employees.Extension
as virtrdf:Employee-extension ;
northwind:notes employees.Notes
as virtrdf:Employee-notes ;
northwind:reportsTo northwind:Employee(employees.FirstName, employees.LastName, employees.ReportsTo) where (^{employees.}^.ReportsTo = ^{employees.}^.EmployeeID)
as virtrdf:Employee-reports_to ;
foaf:img northwind:EmployeePhoto(employees.EmployeeID)
as virtrdf:Employee-employees.EmployeePhoto ;
rdfs:isDefinedBy northwind:employee_iri (employees.EmployeeID) ;
rdfs:isDefinedBy northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID) .
northwind:EmployeePhoto(employees.EmployeeID)
a northwind:EmployeePhoto
as virtrdf:Employee-employees.EmployeePhotoId ;
rdfs:isDefinedBy northwind:employeephoto_iri (employees.EmployeeID) ;
rdfs:isDefinedBy northwind:EmployeePhoto (employees.EmployeeID) .
northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID)
northwind:is_salesrep_of
northwind:Order (orders.OrderID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID) as virtrdf:Order-is_salesrep_of .
northwind:Country (employees.Country)
northwind:is_country_of
northwind:Employee (employees.FirstName, employees.LastName, employees.EmployeeID) as virtrdf:Employee-is_country_of .
northwind:Order (orders.OrderID)
a northwind:Order
as virtrdf:Order-Order ;
northwind:has_customer northwind:Customer (orders.CustomerID)
as virtrdf:Order-order_has_customer ;
northwind:has_salesrep northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID)
as virtrdf:Customer-has_salesrep ;
northwind:has_employee northwind:Employee (employees.FirstName, employees.LastName, orders.EmployeeID) where (^{orders.}^.EmployeeID = ^{employees.}^.EmployeeID)
as virtrdf:Order-order_has_employee ;
northwind:orderDate orders.OrderDate
as virtrdf:Order-order_date ;
northwind:requiredDate orders.RequiredDate
as virtrdf:Order-required_date ;
northwind:shippedDate orders.ShippedDate
as virtrdf:Order-shipped_date ;
northwind:order_ship_via northwind:Shipper (orders.ShipVia)
as virtrdf:Order-order_ship_via ;
northwind:freight orders.Freight
as virtrdf:Order-freight ;
northwind:shipName orders.ShipName
as virtrdf:Order-ship_name ;
northwind:shipAddress orders.ShipAddress
as virtrdf:Order-ship_address ;
northwind:shipCity orders.ShipCity
as virtrdf:Order-ship_city ;
northwind:dbpedia_shipCity northwind:dbpedia_iri(orders.ShipCity)
as virtrdf:Order-dbpediaship_city ;
northwind:shipRegion orders.ShipRegion
as virtrdf:Order-ship_region ;
northwind:shipPostal_code orders.ShipPostalCode
as virtrdf:Order-ship_postal_code ;
northwind:shipCountry northwind:Country(orders.ShipCountry)
as virtrdf:ship_country ;
rdfs:isDefinedBy northwind:order_iri (orders.OrderID) ;
rdfs:isDefinedBy northwind:Order (orders.OrderID) .
northwind:Country (orders.ShipCountry)
northwind:is_ship_country_of
northwind:Order (orders.OrderID) as virtrdf:Order-is_country_of .
northwind:Customer (orders.CustomerID)
northwind:has_order northwind:Order (orders.OrderID) as virtrdf:Order-has_order .
northwind:Shipper (orders.ShipVia)
northwind:ship_order northwind:Order (orders.OrderID) as virtrdf:Order-ship_order .
northwind:OrderLine (order_lines.OrderID, order_lines.ProductID)
a northwind:OrderLine
as virtrdf:OrderLine-OrderLines ;
northwind:has_order_id northwind:Order (order_lines.OrderID)
as virtrdf:order_lines_has_order_id ;
northwind:has_product_id northwind:Product (order_lines.ProductID)
as virtrdf:order_lines_has_product_id ;
northwind:unitPrice order_lines.UnitPrice
as virtrdf:OrderLine-unit_price ;
northwind:quantity order_lines.Quantity
as virtrdf:OrderLine-quantity ;
northwind:discount order_lines.Discount
as virtrdf:OrderLine-discount ;
rdfs:isDefinedBy northwind:orderline_iri (order_lines.OrderID, order_lines.ProductID) ;
rdfs:isDefinedBy northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) .
northwind:Order (orders.OrderID)
northwind:is_order_of
northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) where (^{orders.}^.OrderID = ^{order_lines.}^.OrderID) as virtrdf:Order-is_order_of .
northwind:Product (products.ProductID)
northwind:is_product_of
northwind:OrderLine (order_lines.OrderID, order_lines.ProductID) where (^{products.}^.ProductID = ^{order_lines.}^.ProductID) as virtrdf:Product-is_product_of .
northwind:Country (countries.Name)
a northwind:Country
as virtrdf:Country-Type2 ;
a wgs:SpatialThing
as virtrdf:Country-Type ;
owl:sameAs northwind:dbpedia_iri (countries.Name) ;
northwind:name countries.Name
as virtrdf:Country-Name ;
northwind:code countries.Code
as virtrdf:Country-Code ;
northwind:smallFlagDAVResourceName countries.SmallFlagDAVResourceName
as virtrdf:Country-SmallFlagDAVResourceName ;
northwind:largeFlagDAVResourceName countries.LargeFlagDAVResourceName
as virtrdf:Country-LargeFlagDAVResourceName ;
northwind:smallFlagDAVResourceURI northwind:Flag(countries.SmallFlagDAVResourceURI)
as virtrdf:Country-SmallFlagDAVResourceURI ;
northwind:largeFlagDAVResourceURI northwind:Flag(countries.LargeFlagDAVResourceURI)
as virtrdf:Country-LargeFlagDAVResourceURI ;
wgs:lat countries.Lat
as virtrdf:Country-Lat ;
wgs:long countries.Lng
as virtrdf:Country-Lng ;
rdfs:isDefinedBy northwind:country_iri (countries.Name) ;
rdfs:isDefinedBy northwind:Country (countries.Name) .
northwind:Country (countries.Name)
northwind:has_province
northwind:Province (provinces.CountryCode, provinces.Province) where (^{provinces.}^.CountryCode = ^{countries.}^.Code) as virtrdf:Country-has_province .
northwind:Province (provinces.CountryCode, provinces.Province)
a northwind:Province
as virtrdf:Province-Provinces ;
northwind:has_country_code provinces.CountryCode
as virtrdf:has_country_code ;
northwind:provinceName provinces.Province
as virtrdf:Province-ProvinceName ;
rdfs:isDefinedBy northwind:province_iri (provinces.CountryCode, provinces.Province) ;
rdfs:isDefinedBy northwind:Province (provinces.CountryCode, provinces.Province) .
northwind:Province (provinces.CountryCode, provinces.Province)
northwind:is_province_of
northwind:Country (countries.Name) where (^{countries.}^.Code = ^{provinces.}^.CountryCode) as virtrdf:Province-country_of .
}.
}.
;
]]></programlisting>
<para>The created RDF View is sufficient for querying relational data via SPARQL but not for accessing data by dereferencing IRIs of subjects. Making IRIs dereferenceable requires configuring HTTP server; that is explained in <link linkend="rdfsparqlexnpointnorthwindexample">second part of the example</link>.</para>
</sect4>
</sect3>
</sect2>
<sect2 id="rdfspongerprogrammerguide"><title>Sponger Programmers Guide</title>
<para>The Sponger forms part of the extensible RDF framework built into Virtuoso Universal Server. A
key component of the Sponger's pluggable architecture is its support for Sponger Cartridges, which
themselves are comprised of an Entity Extractor and an Ontology Mapper. Virtuoso bundles numerous
pre-written cartridges for RDF data extraction from a wide range of data sources. However, developers
are free to develop their own custom cartridges. This programmer's guide describes how.</para>
<para>The guide is a companion to the <ulink url="http://virtuoso.openlinksw.com/Whitepapers/pdf/sponger_whitepaper_10102007.pdf">Virtuoso Sponger</ulink> whitepaper. The latter describes the Sponger in depth, its architecture, configuration, use and integration with other Virtuoso facilities such as the Open Data Services (ODS) application framework. This guide focuses solely on custom cartridge development.</para>
<sect3 id="virtuosospongeroverviewxmlset">
<title>Configuration of CURIEs used by the sponger</title>
<para>For configuring CURIEs used by the Sponger which is exposed via sponger
clients such as "description.vsp" - the VSP based information resource description utility,
you can use the <link linkend="fn_xml_set_ns_decl"><function>xml_set_ns_decl</function></link> function.</para>
<para>Here is sample example to add curie pattern:</para>
<programlisting><![CDATA[
-- Example link: http://linkeddata.uriburner.com/about/rdf/http://twitter.com/guykawasaki/status/1144945513#this
XML_SET_NS_DECL ('uriburner',
'http://linkeddata.uriburner.com/about/rdf/http://',
2);
]]></programlisting>
</sect3>
<sect3 id="virtuosospongeroverviewcartarch">
<title>Cartridge Architecture</title>
<para>The Sponger is comprised of cartridges which are themselves comprised of an entity extractor
and an ontology mapper. Entities extracted from non-RDF resources are used as the basis for generating
structured data by mapping them to a suitable ontology. A cartridge is invoked through its cartridge hook,
a Virtuoso/PL procedure entry point and binding to the cartridge's entity extractor and ontology mapper.</para>
<para><emphasis>Entity Extractor</emphasis></para>
<para>When an RDF aware client requests data from a network accessible resource via the Sponger the
following events occur:</para>
<itemizedlist mark="bullet">
<listitem>A request is made for data in RDF form (explicitly via HTTP Accept Headers), and if
RDF is returned nothing further happens. </listitem>
<listitem>If RDF isn't returned, the Sponger passes the data through a <emphasis>Entity Extraction Pipeline</emphasis>
(using Entity Extractors). </listitem>
<listitem>The extracted data is transformed into RDF via a <emphasis>Mapping Pipeline</emphasis>. RDF instance data is generated by way of ontology matching and mapping. </listitem>
<listitem>RDF instance data (aka. RDF Structured Linked Data) are returned to the client.</listitem>
</itemizedlist>
<para><emphasis>Extraction Pipeline</emphasis></para>
<para>Depending on the file or format type detected at ingest, the Sponger applies the appropriate
entity extractor. Detection occurs at the time of content negotiation instigated by the retrieval user
agent. The normal extraction pipeline processing is as follows:</para>
<itemizedlist mark="bullet">
<listitem>The Sponger tries to get RDF data (including N3 or Turtle) directly from the dereferenced
URL. If it finds some, it returns it, otherwise, it continues.</listitem>
<listitem>If the URL refers to a HTML file, the Sponger tries to find "link" elements referring to
RDF documents. If it finds one or more of them, it adds their triples into a temporary RDF graph and
continues its processing.</listitem>
<listitem>The Sponger then scans for microformats or GRDDL. If either is found, RDF triples are
generated and added to a temporary RDF graph before continuing.</listitem>
<listitem>If the Sponger finds eRDF or RDFa data in the HTML file, it extracts it from the HTML
file and inserts it into the RDF graph before continuing.</listitem>
<listitem>If the Sponger finds it is talking with a web service such as Google Base, it maps
the API of the web service with an ontology, creates triples from that mapping and includes the triples
into the temporary RDF graph.</listitem>
<listitem>The next fallback is scanning of the HTML header for different Web 2.0 types or RSS
1.1, RSS 2.0, Atom, etc. </listitem>
<listitem>Failing those tests, the scan then uses standard Web 1.0 rules to search in the
header tags for metadata (typically Dublin Core) and transform them to RDF and again add them to the
temporary graph. Other HTTP response header data may also be transformed to RDF.</listitem>
<listitem>If nothing has been retrieved at this point, the ODS-Briefcase metadata
extractor is tried.</listitem>
<listitem>Finally, if nothing is found, the Sponger will return an empty graph.</listitem>
</itemizedlist>
<para><emphasis>Ontology Mapper</emphasis></para>
<para>Sponger ontology mappers peform the the task of generating RDF instance data from
extracted entities (non-RDF) using ontologies associated with a given data source type. They are
typically XSLT (using GRDDL or an in-built Virtuoso mapping scheme) or Virtuoso/PL based. Virtuoso
comes preconfigured with a large range of ontology mappers contained in one or more Sponger
cartridges.</para>
<para><emphasis>Cartridge Registry</emphasis></para>
<para>To be recognized by the SPARQL engine, a Sponger cartridge must be registered in
the Cartridge Registry by adding a record to the table DB.DBA.SYS_RDF_MAPPERS, either manually
via DML, or more easily through Conductor, Virtuoso's browser-based administration console,
which provides a UI for adding your own cartridges. (Sponger configuration using Conductor is
described in detail later.) The SYS_RDF_MAPPERS table definition is as follows:</para>
<programlisting><![CDATA[
create table "DB"."DBA"."SYS_RDF_MAPPERS"
(
"RM_ID" INTEGER IDENTITY, -- cartridge ID. Determines the order of the cartridge's invocation in the Sponger processing chain
"RM_PATTERN" VARCHAR, -- a REGEX pattern to match the resource URL or MIME type
"RM_TYPE" VARCHAR, -- which property of the current resource to match: "MIME" or "URL"
"RM_HOOK" VARCHAR, -- fully qualified Virtuoso/PL function name
"RM_KEY" LONG VARCHAR, -- API specific key to use
"RM_DESCRIPTION" LONG VARCHAR, -- cartridge description (free text)
"RM_ENABLED" INTEGER, -- a 0 or 1 integer flag to exclude or include the cartridge from the Sponger processing chain
"RM_OPTIONS" ANY, -- cartridge specific options
"RM_PID" INTEGER IDENTITY,
PRIMARY KEY ("RM_PATTERN", "RM_TYPE")
);
]]></programlisting>
</sect3>
<sect3 id="virtuosospongeroverviewcartinvo">
<title>Cartridge Invocation</title>
<para>The Virtuoso SPARQL processor supports IRI dereferencing via the Sponger. If a SPARQL query
references non-default graph URIs, the Sponger goes out (via HTTP) to sponge the data source URIs and
inserts the extracted RDF data into the local RDF quad store. The Sponger invokes the appropriate
cartridge for the data source type to produce RDF instance data. If none of the registered cartridges
are capable of handling the received content type, the Sponger will attempt to obtain RDF instance
data via the in-built WebDAV metadata extractor.</para>
<para>Sponger cartridges are invoked as follows:</para>
<para>When the SPARQL processor dereferences a URI, it plays the role of an HTTP user agent
(client) that makes a content type specific request to an HTTP server via the HTTP request's Accept
headers. The following then occurs:</para>
<itemizedlist mark="bullet">
<listitem>If the content type returned is RDF then no further transformation is needed and
the process stops. For instance, when consuming an (X)HTML document with a GRDDL profile, the profile
URI points to a data provider that simply returns RDF instance data.</listitem>
<listitem>If the content type is not RDF (i.e. application/rdf+xml or text/rdf+n3 ), for
instance 'text/plain', the Sponger looks in the Cartridge Registry iterating over every record for
which the RM_ENABLED flag is true, with the look-up sequence ordered on the RM_ID column values.
For each record, the processor tries matching the content type or URL against the RM_PATTERN value
and, if there is match, the function specified in RM_HOOK column is called. If the function doesn't
exist, or signals an error, the SPARQL processor looks at next record.
<itemizedlist mark="bullet">
<listitem>If the hook returns zero, the next cartridge is tried. (A cartridge function
can return zero if it believes a subsequent cartridge in the chain is capable of extracting more
RDF data.)</listitem>
<listitem>If the result returned by the hook is negative, the Sponger is instructed
that no RDF was generated and the process stops. </listitem>
<listitem>If the hook result is positive, the Sponger is informed that structured
data was retrieved and the process stops.</listitem>
</itemizedlist>
</listitem>
<listitem>If none of the cartridges match the source data signature (content type or URL),
the ODS-Briefcase WebDAV metadata extractor and RDF generator is called.</listitem>
</itemizedlist>
<para><emphasis>Meta-Cartridges</emphasis></para>
<para>The above describes the RDF generation process for 'primary' Sponger cartridges. Virtuoso
also supports another cartridge type - a 'meta-cartridge'. Meta-cartridges act as post-processors in
the cartridge pipeline, augmenting entity descriptions in an RDF graph with additional information
gleaned from 'lookup' data sources and web services. Meta-cartridges are described in more detail in
a later section.</para>
<figure id="spong1" float="1">
<title>Meta-Cartridges</title>
<graphic fileref="ui/spong1.png"/>
</figure>
</sect3>
<sect3 id="virtuosospongercatrbundled">
<title>Cartridges Bundled with Virtuoso</title>
<sect4 id="virtuosospongercatrbundledrdfvad">
<title>RDF Mappers VAD</title>
<para>Virtuoso supplies a number of prewritten cartridges for extracting RDF data from a
variety of popular Web resources and file types. The cartridges are bundled as part of the rdf_mappers
VAD (Virtuoso Application Distribution). Appendix B of the Virtuoso Sponger whitepaper briefly
outlines the cartridges contained in the VAD.</para>
<para>To see which cartridges are available, look at the 'RDF Cartridges' screen in
Conductor. This can be reached through the 'RDF' > 'RDF Cartridges' tabbed menu items.</para>
<figure id="spong2" float="1">
<title>RDF Cartridges</title>
<graphic fileref="ui/spong2.png"/>
</figure>
<para>To check which version of the rdf_mappers VAD is installed, or to upgrade it,
refer to Conductor's 'VAD Packages' screen, reachable through the 'System Admin' > 'Packages'
menu items.</para>
<para>The latest VADs for the closed source releases of Virtuoso can be
<ulink url="http://download.openlinksw.com/download/">downloaded</ulink> from the downloads area on the OpenLink website. Select either the 'DBMS (WebDAV) Hosted' or
'File System Hosted' product format from the 'Distributed Collaborative Applications' section,
depending on whether you want the Virtuoso application to use WebDAV or native filesystem storage.
VADs for Virtuoso Open Source edition (VOS) are available for
<ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VOSDownload">download</ulink> from
the VOS Wiki.</para>
</sect4>
<sect4 id="virtuosospongercatrbundledexample">
<title>Example Source Code</title>
<para>For developers wanting example cartridge code, the most authoritative reference is
the rdf_mappers VAD source code itself. This is included as part of the VOS distribution. After
downloading and unpacking the sources, the script used to create the cartridges, and the associated
stylesheets can be found in:</para>
<itemizedlist mark="bullet">
<listitem><vos root>/binsrc/rdf_mappers/rdf_mappers.sql</listitem>
<listitem><vos root>/binsrc/rdf_mappers/xslt/*.xsl</listitem>
</itemizedlist>
<para>Alternatively, you can look at the actual cartridge implementations installed in your
Virtuoso instance by inspecting the cartridge hook function used by a particular cartridge. This is
easily identified from the 'Cartridge name' field of Conductor's 'RDF Cartridges' screen, after
selecting the cartridge of interest. The hook function code can be viewed from the 'Schema Objects'
screen under the 'Database' menu, by locating the function in the 'DB' > 'Procedures' folder.
Stylesheets used by the cartridges are installed in the WebDAV folder DAV/VAD/rdf_mappers/xslt.
This can be explored using Conductor's WebDAV interface. The actual rdf_mappers.sql file installed
with your system can also be found in the DAV/VAD/rdf_mappers folder.</para>
</sect4>
</sect3>
<sect3 id="virtuosospongercatrbundledcusgtomcart">
<title>Custom Cartridge</title>
<para>Virtuoso comes well supplied with a variety of Sponger cartridges and GRDDL filters.
When then is it necessary to write your own cartridge?</para>
<para>In the main, writing a new cartridge should only be necessary to generate RDF from
a REST-style Web service not supported by an existing cartridge, or to customize the output from
an existing cartridge to your own requirements. Apart from these circumstances, the existing
Sponger infrastructure should meet most of your needs. This is particularly the case for
document resources.</para>
<sect4 id="virtuosospongerdocres">
<title>Document Resources</title>
<para>We use the term document resource to identify content which is not being returned
from a Web service. Normally it can broadly be conceived as some form of document, be it a text
based entity or some form of file, for instance an image file.</para>
<para>In these cases, the document either contains RDF, which can be extracted directly,
or it holds metadata in a supported format which can be transformed to RDF using an existing
filter.</para>
<para>The following cases should all be covered by the existing Sponger cartridges:</para>
<itemizedlist mark="bullet">
<listitem>embedded or linked RDF</listitem>
<listitem>RDFa, eRDF and other popular microformats extractable directly or via GRDDL</listitem>
<listitem>popular syndication formats (RSS 2.0 , Atom, OPML , OCS , XBEL)</listitem>
</itemizedlist>
</sect4>
<sect4 id="virtuosospongergrddl">
<title>GRDDL</title>
<para>GRDDL (Gleaning Resource Descriptions from Dialects of Languages) is mechanism for deriving
RDF data from XML documents and in particular XHTML pages. Document authors may associate transformation
algorithms, typically expressed in XSLT, with their documents to transform embedded metadata into RDF.</para>
<para>The rdf_mappers VAD installs a number of GRDDL filters for transforming popular microformats
(such as RDFa, eRDF or hCalendar) into RDF. The available filters can be viewed, or configured, in
Conductor's 'GRDDL Filters for XHTML' screen. Navigate to the 'RDF Cartridges' screen using the
'RDF' > 'RDF Cartridges' menu items, then SELECT the 'GRDDL Mappings' tab to display the 'GRDDL Filters
for XHTML' screen. GRDDL filters are held in the WebDAV folder /DAV/VAD/rdf_cartridges/xslt/ alongside
other XSLT templates. The Conductor interface allows you to add new GRDDL filters should you so wish.</para>
<para>For an introduction to GRDDL, try the <ulink url="http://www.w3.org/TR/grddl-primer/">GRDDL Primer</ulink>. To underline GRDDL's utility, the primer
includes an example of transforming Excel spreadsheet data, saved as XML, into RDF.</para>
<para>A comprehensive <ulink url="http://esw.w3.org/topic/CustomRdfDialects">list of stylesheets</ulink>
for transforming HTML and non-HTML XML dialects is maintained
on the ESW Wiki. The list covers a range of microformats, syndication formats and feedlists.</para>
</sect4>
<para>To see which Web Services are already catered for, view the list of cartridges in Conductor's 'RDF Cartridges' screen.</para>
</sect3>
<sect3 id="virtuosospongercreatecustcartr">
<title>Creating Custom Cartridges</title>
<para>The Sponger is fully extensible by virtue of its pluggable cartridge architecture. New data formats can
be sponged by creating new cartridges. While OpenLink is active in adding cartridges for new data sources,
you are free to develop your own custom cartridges. Entity extractors can be built using Virtuoso PL,
C/C++, Java or any other external language supported by Virtuoso's Server Extension API. Of course,
Virtuoso's own entity extractors are written in Virtuoso PL.</para>
<sect4 id="virtuosospongercreatecustcartran">
<title>The Anatomy of a Cartridge</title>
<para><emphasis>Cartridge Hook Function</emphasis></para>
<para>Every Virtuoso PL hook function used to plug a custom Sponger cartridge into the Virtuoso
SPARQL engine must have a parameter list with the following parameters (the names of the parameters are
not important, but their order and presence are):</para>
<itemizedlist mark="bullet">
<listitem><emphasis>in graph_iri varchar</emphasis>: the IRI of the graph being retrieved/crawled</listitem>
<listitem><emphasis>in new_origin_uri varchar</emphasis>: the URL of the document being retrieved</listitem>
<listitem><emphasis>in dest varchar</emphasis>: the destination/target graph IRI</listitem>
<listitem><emphasis>inout content any</emphasis>: the content of the retrieved document</listitem>
<listitem><emphasis>inout async_queue any</emphasis>: if the PingService initialization parameter
has been configured in the [SPARQL] section of the virtuoso.ini file, this is a pre-allocated asynchronous
queue to be used to call the ping service</listitem>
<listitem><emphasis>inout ping_service any</emphasis>: the URL of a ping service, as assigned
to the PingService parameter in the [SPARQL] section of the virtuoso.ini configuration file.
PingTheSemanticWeb is an example of a such a service. See Appendix A for more details.</listitem>
<listitem><emphasis>inout api_key any</emphasis>: a string value specific to a given cartridge,
contained in the RC_KEY column of the DB.DBA.SYS_RDF_CARTRIDGES table. The value can be a single
string or a serialized array of strings providing cartridge specific data.</listitem>
<listitem><emphasis>inout opts any</emphasis>: cartridge specific options held in a Virtuoso/PL
vector which acts as an array of key-value pairs.</listitem>
</itemizedlist>
<para><emphasis>Return Value</emphasis></para>
<para>If the hook procedure returns zero the next cartridge will be tried. If the result is negative
the sponging process stops, instructing the SPARQL engine that nothing was retrieved. If the result is
positive the process stops, this time instructing the SPARQL engine
that RDF data was successfully retrieved.</para>
<para>If your cartridge should need to test whether other cartridges are configured to handle a
particular data source, the following extract taken from the RDF_LOAD_CALAIS hook procedure illustrates
how you might do this:</para>
<programlisting><![CDATA[
if (xd is not null)
{
-- Sponging successful. Load sponged data in Virtuoso quad store
DB.DBA.RM_RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
flag := 1;
}
declare ord any;
ord := (SELECT RM_ID FROM DB.DBA.SYS_RDF_MAPPERS WHERE
RM_HOOK = 'DB.DBA.RDF_LOAD_CALAIS');
for SELECT RM_PATTERN FROM DB.DBA.SYS_RDF_MAPPERS WHERE
RM_ID > ord and RM_TYPE = 'URL' and RM_ENABLED = 1 ORDER BY RM_ID do
{
if (regexp_match (RM_PATTERN, new_origin_uri) is not null)
-- try next candidate cartridge
flag := 0;
}
return flag;
]]></programlisting>
<para><emphasis>Specifying the Target Graph</emphasis></para>
<para>Two cartridge hook function parameters contain graph IRIs, graph_iri and dest. graph_iri
identifies an input graph being crawled. dest holds the IRI specified in any input:grab-destination
pragma defined to control the SPARQL processor's IRI dereferencing. The pragma overrides the default
behaviour and forces all retrieved triples to be stored in a single graph, irrespective of their graph
of origin.</para>
<para>So, under some circumstances depending on how the Sponger has been invoked and whether
it is being used to crawl an existing RDF graph, or derive RDF data from a non-RDF data source,
dest may be null.</para>
<para>Consequently, when loading sponged RDF data into the quad store, cartridges typically
specify the graph to receive the data using the coalesce function which returns the first non-null
parameter. e.g.</para>
<programlisting><![CDATA[
DB.DBA.RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
]]></programlisting>
<para>Here xd is an RDF/XML string holding the sponged RDF.</para>
<para><emphasis>Specifying & Retrieving Cartridge Specific Options</emphasis></para>
<para>The hook function prototype allows cartridge specific data to be passed to a cartridge
through the RM_OPTIONS parameter, a Virtuoso/PL vector which acts as a heterogeneous array.</para>
<para>In the following example, two options are passed, 'add-html-meta' and 'get-feeds'
with both values set to 'no'.</para>
<programlisting><![CDATA[
insert soft DB.DBA.SYS_RDF_MAPPERS (
RM_PATTERN, RM_TYPE, RM_HOOK, RM_KEY, RM_DESCRIPTION, RM_OPTIONS
)
values (
'(text/html)|(text/xml)|(application/xml)|(application/rdf.xml)',
'MIME', 'DB.DBA.RDF_LOAD_HTML_RESPONSE', null, 'xHTML',
vector ('add-html-meta', 'no', 'get-feeds', 'no')
);
]]></programlisting>
<para>The RM_OPTIONS vector can be handled as an array of key-value pairs using the
get_keyword function. get_keyword performs a case sensitive search for the given keyword at
every even index of the given array. It returns the element following the keyword, i.e.
the keyword value.</para>
<para>Using get_keyword, any options passed to the cartridge can be retrieved
using an approach similar to that below:</para>
<programlisting><![CDATA[
create procedure DB.DBA.RDF_LOAD_HTML_RESPONSE (
in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout ret_body any, inout aq any, inout ps any, inout _key any,
inout opts any )
{
declare get_feeds, add_html_meta;
...
get_feeds := add_html_meta := 0;
if (isarray (opts) and 0 = mod (length(opts), 2))
{
if (get_keyword ('get-feeds', opts) = 'yes')
get_feeds := 1;
if (get_keyword ('add-html-meta', opts) = 'yes')
add_html_meta := 1;
}
...
]]></programlisting>
<para><emphasis>API Keys</emphasis></para>
<para>Some Cartridges require and API account and/or API Key to be
provided for accessing the required service. This can be done from the RDF -> Sponger tab of the
Conductor by selecting the cartridge from the list provided, entering the API Account and API Key
in the dialog at the bottom of the page and click update to save, as indicated in the screenshot
below:</para>
<figure id="catr1" float="1">
<title>Registering API Key</title>
<graphic fileref="ui/cartrapikey.png"/>
</figure>
<para>For example, for the service Flickr developers must register
to obtain a key. See http://developer.yahoo.com/flickr/. In order
to cater for services which require an application key, the Cartridge Registry
SYS_RDF_MAPPERS table includes an RM_KEY column to store any key required for a
particular service. This value is passed to the service's cartridge through the
_key parameter of the cartridge hook function.</para>
<para>Alternatively a cartridge can store a key value in the virtuoso.ini
configuration file and retrieve it in the hook function.</para>
<para>The next example shows an extract from the Flickr cartridge hook function
DB.DBA.RDF_LOAD_FLICKR_IMG and the use of an API key. Also, commented out, is a call to
cfg_item_value() which illustrates how the API key could instead be stored and retrieved
from the SPARQL section of the virtuoso.ini file.
</para>
<programlisting><![CDATA[
create procedure DB.DBA.RDF_LOAD_FLICKR_IMG (
in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout _ret_body any, inout aq any, inout ps any, inout _key any,
inout opts any )
{
declare xd, xt, url, tmp, api_key, img_id, hdr, exif any;
declare exit handler for sqlstate '*'
{
return 0;
};
tmp := sprintf_inverse (new_origin_uri,
'http://farm%s.static.flickr.com/%s/%s_%s.%s', 0);
img_id := tmp[2];
api_key := _key;
--cfg_item_value (virtuoso_ini_path (), 'SPARQL', 'FlickrAPIkey');
if (tmp is null or length (tmp) <> 5 or not isstring (api_key))
return 0;
url := sprintf('http://api.flickr.com/services/rest/?method=flickr.photos.getInfo&photo_id=%s&api_key=%s',img_id, api_key);
tmp := http_get (url, hdr);
]]></programlisting>
<para><emphasis>XSLT - The Fulchrum</emphasis></para>
<para>XSLT is the fulchrum of all OpenLink supplied cartridges. It provides the most convenient
means of converting structured data extracted from web content by a cartridge's Entity Extractor into RDF.</para>
<para><emphasis>Virtuoso's XML Infrastructure & Tools</emphasis></para>
<para>Virtuoso's XML support and XSLT support are covered in detail in the on-line documentation.
Virtuoso includes a highly capable XML parser and supports XPath, XQuery, XSLT and XML Schema validation.</para>
<para>Virtuoso supports extraction of XML documents from SQL datasets. A SQL long varchar, long xml
or xmltype column in a database table can contain XML data as text or in a binary serialized format.
A string representing a well-formed XML entity can be converted into an entity object representing
the root node.</para>
<para>While Sponger cartridges will not normally concern themselves with handling XML extracted
from SQL data, the ability to convert a string into an in-memory XML document is used extensively.
The function xtree_doc(string) converts a string into such a document and returns a reference to the
document's root. This document together with an appropriate stylesheet forms the input for
the transformation of the extracted entities to RDF using XSLT. The input string to xtree_doc
generally contains structured content derived from a web service.</para>
<para><emphasis>Virtuoso XSLT Support</emphasis></para>
<para>Virtuoso implements XSLT 1.0 transformations as SQL callable functions. The xslt() Virtuoso/PL function
applies a given stylesheet to a given source XML document and returns the transformed document. Virtuoso
provides a way to extend the abilities of the XSLT processor by creating user defined XPath functions.
The functions xpf_extension() and xpf_extension_remove() allow addition and removal of XPath extension
functions.</para>
<para><emphasis>General Cartridge Pipeline</emphasis></para>
<para>The broad pipeline outlined here reflects the steps common to most cartridges:</para>
<itemizedlist mark="bullet">
<listitem>Redirect from the requested URL to a Web service which returns XML</listitem>
<listitem>Stream the content into an in-memory XML document</listitem>
<listitem>Convert it to the required RDF/XML, expressed in the chosen ontology, using XSLT</listitem>
<listitem>Encode the RDF/XML as UTF-8</listitem>
<listitem>Load the RDF/XML into the quad store</listitem>
</itemizedlist>
<para>The <ulink url="http://musicbrainz.org/">MusicBrainz</ulink> cartridge typifies this approach. MusicBrainz is a community music
metadatabase which captures information about artists, their recorded works, and the relationships
between them. Artists always have a unique ID, so the URL
http://musicbrainz.org/artist/4d5447d7-c61c-4120-ba1b-d7f471d385b9.html takes you directly to entries
for John Lennon.</para>
<para>If you were to look at this page in your browser, you would see that the information about
the artist contains no RDF data. However, the cartridge is configured to intercept requests to URLs of
the form http://musicbrainz.org/([^/]*)/([^.]*) and redirect to the cartridge to sponge all the
available information on the given artist, release, track or label.</para>
<para>The cartridge extracts entities by redirecting to the MusicBrainz XML Web Service using
as the basis for the initial query the item ID, e.g. an artist or label ID, extracted from the original
URL. Stripped to its essentials, the core of the cartridge is:</para>
<programlisting><![CDATA[
webservice_uri := sprintf ('http://musicbrainz.org/ws/1/%s/%s?type=xml&inc=%U',
kind, id, inc);
content := RDF_HTTP_URL_GET (webservice_uri, '', hdr, 'GET', 'Accept: */*');
xt := xtree_doc (content);
...
xd := DB.DBA.RDF_MAPPER_XSLT (registry_get ('_rdf_mappers_path_') || 'xslt/mbz2rdf.xsl', xt);
...
xd := serialize_to_UTF8_xml (xd);
DB.DBA.RM_RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
]]></programlisting>
<para>In the above outline, RDF_HTTP_URL_GET sends a query to the MusicBrainz web service,
using query parameters appropriate for the original request, and retrieves the response using
HTTP GET.</para>
<para>The returned XML is parsed into an in-memory parse tree by xtree_doc. Virtuoso/PL
function RDF_MAPPER_XSLT is a simple wrapper around the function xslt which sets the current user
to dba before returning an XML document transformed by an XSLT stylesheet, in this case mbz2rdf.xsl.
Function serialize_to_UTF8_xml changes the character set of the in-memory XML document to UTF8.
Finally, RM_RDF_LOAD_RDFXML is a wrapper around RDF_LOAD_RDFXML which parses the content of an
RDF/XML string into a sequence of RDF triples and loads them into the quad store. XSLT stylesheets
are usually held in the DAV/VAD/rdf_mappers/xslt folder of Virtuoso's WebDAV store.
registry_get('rdf_mappers_path') returns the RDF Mappers VAD path, 'DAV/VAD/rdf_mappers', from the
Virtuoso registry.</para>
<para><emphasis>Error Handling with Exit Handlers</emphasis></para>
<para>Virtuoso condition handlers determine the behaviour of a Virtuoso/PL procedure when a
condition occurs. You can declare one or more condition handlers in a Virtuoso/PL procedure for
general SQL conditions or specific SQLSTATE values. If a statement in your procedure raises an
SQLEXCEPTION condition and you declared a handler for the specific SQLSTATE or SQLEXCEPTION
condition the server passes control to that handler. If a statement in your Virtuoso/PL procedure
raises an SQLEXCEPTION condition, and you have not declared a handler for the specific SQLSTATE
or the SQLEXCEPTION condition, the server passes the exception to the calling procedure (if any).
If the procedure call is at the top-level, then the exception is signaled to the calling client.</para>
<para>A number of different condition handler types can be declared (see the <ulink url="http://docs.openlinksw.com/virtuoso/handlingplcondit.html">Virtuoso reference documentation</ulink>
for more details.) Of these, exit handlers are probably all you will need. An example is shown below
which handles any SQLSTATE. Commented out is a debug statement which outputs the message describing
the SQLSTATE.</para>
<programlisting><![CDATA[
create procedure DB.DBA.RDF_LOAD_SOCIALGRAPH (in graph_iri varchar, ...)
{
declare qr, path, hdr any;
...
declare exit handler for sqlstate '*'
{
-- dbg_printf ('%s', __SQL_MESSAGE);
return 0;
};
...
-- data extraction and mapping successful
return 1;
}
]]></programlisting>
<para>Exit handlers are used extensively in the Virtuoso supplied cartridges. They are useful
for ensuring graceful failure when trying to convert content which may not conform to your expectations.
The RDF_LOAD_FEED_SIOC procedure (which is used internally by several cartridges) shown below uses this
approach:</para>
<programlisting><![CDATA[
-- /* convert the feed in rss 1.0 format to sioc */
create procedure DB.DBA.RDF_LOAD_FEED_SIOC (in content any, in iri varchar, in graph_iri varchar, in is_disc int := '')
{
declare xt, xd any;
declare exit handler for sqlstate '*'
{
goto no_sioc;
};
xt := xtree_doc (content);
xd := DB.DBA.RDF_MAPPER_XSLT (
registry_get ('_rdf_mappers_path_') || 'xslt/feed2sioc.xsl', xt,
vector ('base', graph_iri, 'isDiscussion', is_disc));
xd := serialize_to_UTF8_xml (xd);
DB.DBA.RM_RDF_LOAD_RDFXML (xd, iri, graph_iri);
return 1;
no_sioc:
return 0;
}
]]></programlisting>
<para><emphasis>Loading RDF into the Quad Store</emphasis></para>
<para><emphasis>RDF_LOAD_RDFXML & TTLP</emphasis></para>
<para>The two main Virtuoso/PL functions used by the cartridges for loading RDF data into the
Virtuoso quad store are DB.DBA.TTLP and DB.DBA.RDF_LOAD_RDFXML. Multithreaded versions of these functions,
DB.DBA.TTLP_MT and DB.DBA.RDF_LOAD_RDFXML_MT, are also available.</para>
<para>RDF_LOAD_RDFXML parses the content of an RDF/XML string as a sequence of RDF triples and
loads then into the quad store. TTLP parses TTL (Turtle or N3) and places its triples into quad
storage. Ordinarily, cartridges use RDF_LOAD_RDFXML. However there may be occasions where you want
to insert statements written as TTL, rather than RDF/XML, in which case you should use TTLP.</para>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfinsertmethodsapifunct">Loading RDF using API functions</link></listitem>
</itemizedlist>
</tip>
<para><emphasis>Attribution</emphasis></para>
<para>Many of the OpenLink supplied cartridges actually use RM_RDF_LOAD_RDFXML to load data
into the quad store. This is a thin wrapper around RDF_LOAD_RDFXML which includes in the generated
graph an indication of the external ontologies being used. The attribution takes the form:</para>
<programlisting><![CDATA[
<ontologyURI> a opl:DataSource .
<spongedResourceURI> rdfs:isDefinedBy <ontologyURI> .
<ontologyURI> opl:hasNamespacePrefix "<ontologyPrefix>" .
]]></programlisting>
<para>where prefix opl: denotes the ontology http://www.openlinksw.com/schema/attribution#.</para>
<para><emphasis>Deleting Existing Graphs</emphasis></para>
<para>Before loading sponged RDF data into a graph, you may want to delete any existing graph
with the same URI. To do so, select the 'RDF' > 'List of Graphs' menu commands in Conductor, then use
the 'Delete' command for the appropriate graph. Alternatively, you can use one of the following SQL
commands:</para>
<programlisting><![CDATA[
SPARQL CLEAR GRAPH
-- or
DELETE FROM DB.DBA.RDF_QUAD WHERE G = DB.DBA.RDF_MAKE_IID_OF_QNAME (graph_iri)
]]></programlisting>
<para><emphasis>Proxy Service Data Expiration</emphasis></para>
<para>When the Proxy Service is invoked by a user agent, the Sponger records the expiry date
of the imported data in the table DB.DBA.SYS_HTTP_SPONGE. The data invalidation rules conform to those
of traditional HTTP clients (Web browsers). The data expiration time is determined based on subsequent
data fetches of the same resource. The first data retrieval records the 'expires' header. On subsequent
fetches, the current time is compared to the expiration time stored in the local cache. If HTTP 'expires'
header data isn't returned by the source data server, the Sponger will derive its own expiration time by
evaluating the 'date' header and 'last-modified' HTTP headers.</para>
</sect4>
<sect4 id="virtuosospongercreatecustcartrontolg">
<title>Ontology Mapping</title>
<para>After extracting entities from a web resource and converting them to an in-memory XML
document, the entities must be transformed to the target ontology using XSLT and an appropriate stylesheet.
A typical call sequence would be:</para>
<programlisting><![CDATA[
xt := xtree_doc (content);
...
xd := DB.DBA.RDF_MAPPER_XSLT (registry_get ('_rdf_mappers_path_') || 'xslt/mbz2rdf.xsl', xt);
]]></programlisting>
<para>Because of the wide variation in the data mapped by cartridges, it is not possible to present
a typical XSL stylesheet outline. The Examples section presented later includes detailed extracts from the
MusicBrainz? cartridge's stylesheet which provide a good example of how to map to an ontology. Rather than
attempting to be an XSLT tutorial, the material which follows offers some general guidelines.</para>
<para><emphasis>Passing Parameters to the XSLT Processor</emphasis></para>
<para>Virtuoso's XSLT processor will accept default values for global parameters from the optional
third argument of the xslt() function. This argument, if specified, must be a vector of parameter names
and values of the form vector(name1, value1,... nameN, valueN), where name1 ... nameN must be of type
varchar, and value1 ... valueN may be of any Virtuoso datatype, but may not be null.</para>
<para>This extract from the Crunchbase cartridge shows how parameters may be passed to the XSLT
processor. The function RDF_MAPPER_XSLT (in xslt varchar, inout xt any, in params any := null) passes
the parameters vector directly to xslt().</para>
<programlisting><![CDATA[
xt := DB.DBA.RDF_MAPPER_XSLT (
registry_get ('_rdf_mappers_path_') || 'xslt/crunchbase2rdf.xsl', xt,
vector ('baseUri', coalesce (dest, graph_iri), 'base', base, 'suffix', suffix)
);
]]></programlisting>
<para>The corresponding stylesheet crunchbase2rdf.xsl retrieves the parameters baseUri, base and suffix as follows:</para>
<programlisting><![CDATA[
...
<xsl:output method="xml" indent="yes" />
<xsl:variable name="ns">http://www.crunchbase.com/</xsl:variable>
<xsl:param name="baseUri" />
<xsl:param name="base"/>
<xsl:param name="suffix"/>
<xsl:template name="space-name">
...
]]></programlisting>
<para><emphasis>An RDF Description Template</emphasis></para>
<para><emphasis>Defining A Generic Resource Description Wrapper</emphasis></para>
<para>Many of the OpenLink cartridges create a resource description formed to a common "wrapper"
template which describes the relationship between the (usually) non-RDF source resource being sponged
and the RDF description generated by the Sponger. The wrapper is appropriate for resources which can
broadly be conceived as documents. It provides a generic minimal description of the source document,
but also links to the much more detailed description provided by the Sponger. So, instead of just
emitting a resource description, the Sponger factors the container into the generated graph constituting
the RDF description.</para>
<para>The template is depicted below:</para>
<figure id="spong3" float="1">
<title>Template</title>
<graphic fileref="ui/spong3.png"/>
</figure>
<para>To generate an RDF description corresponding to the wrapper template, a stylesheet containing
the following block of instructions is used. This extract is taken from the eBay cartridge's stylesheet,
ebay2rdf.xsl. Many of the OpenLink cartridges follow a similar pattern.</para>
<programlisting><![CDATA[
<xsl:param name="baseUri"/>
...
<xsl:variable name="resourceURL">
<xsl:value-of select="$baseUri"/>
</xsl:variable>
...
<xsl:template match="/">
<rdf:RDF>
<rdf:Description rdf:about="{$resourceURL}">
<rdf:type rdf:resource="Document"/>
<rdf:type rdf:resource="Document"/>
<rdf:type rdf:resource="Container"/>
<sioc:container_of rdf:resource="{vi:proxyIRI ($resourceURL)}"/>
<foaf:primaryTopic rdf:resource="{vi:proxyIRI ($resourceURL)}"/>
<dcterms:subject rdf:resource="{vi:proxyIRI ($resourceURL)}"/>
</rdf:Description>
<rdf:Description rdf:about="{vi:proxyIRI ($resourceURL)}">
<rdf:type rdf:resource="Item"/>
<sioc:has_container rdf:resource="{$resourceURL}"/>
<xsl:apply-templates/>
</rdf:Description>
</rdf:RDF>
</xsl:template>
...
]]></programlisting>
<para><emphasis>Using SIOC as a Generic Container Model</emphasis></para>
<para>The generic resource description wrapper just described uses SIOC to establish the
container/contained relationship between the source resource and the generated graph. Although the most
important classes for the generic wrapper are obviously Container and Item, SIOC provides a generic data
model of containers, items, item types, and associations between items which can be combined with other
vocabularies such as FOAF and Dublin Core.</para>
<para>SIOC defines a number of other classes, such as User, UserGroup, Role, Site, Forum and
Post. A separate SIOC types module (T-SIOC) extends the SIOC Core ontology by defining subclasses and
subproperties of SIOC terms. Subclasses include: AddressBook, BookmarkFolder, Briefcase, EventCalendar,
ImageGallery, Wiki, Weblog, BlogPost, Wiki plus many others.</para>
<para>OpenLink Data Spaces (ODS) uses SIOC extensively as a data space "glue" ontology to
describe the base data and containment hierarchy of all the items managed by ODS applications
(Data Spaces). For example, ODS-Weblog is an application of type sioc:Forum. Each ODS-Weblog
application instance contains blogs of type sioct:Weblog. Each blog is a sioc:container_of posts
of type sioc:Post.</para>
<para>Generally, when deciding how to describe resources handled by your own custom cartridge,
SIOC provides a useful framework for the description which complements the SIOC-based container model
adopted throughout the ODS framework.</para>
<para><emphasis>Naming Conventions for Sponger Generated Descriptions</emphasis></para>
<para>As can be seen from the stylesheet extract just shown, the URI of the resource
description generated by the Sponger to describe the sponged resource is given by the
function {vi:proxyIRI ($resourceURL)} where resourceURL is the URL of the original resource
being sponged. proxyIRI is an XPath extension function defined in rdf_mappers.sql as</para>
<programlisting><![CDATA[
xpf_extension ('http://www.openlinksw.com/virtuoso/xslt/:proxyIRI', 'DB.DBA.RDF_SPONGE_PROXY_IRI');
]]></programlisting>
<para>which maps to the Virtuoso/PL procedure DB.DBA.RDF_SPONGE_PROXY_IRI. This procedure in
turn generates a resource description URI which typically takes the form:
http://<hostName:port>/about/html/http/<resourceURL>#this</para>
</sect4>
<sect4 id="virtuosospongercreatecustcartrrgst">
<title>Registering & Configuring Cartridges</title>
<para>Once you have developed a cartridge, you must register it in the Cartridge Registry
to have the SPARQL processor recognize and use it. You should have compiled your cartridge hook
function first by issuing a "create procedure DB.DBA.RDF_LOAD_xxx ..." command through one of
Virtuoso's SQL interfaces. You can create the required Cartridge Registry entry either by adding
a row to the SYS_REF_MAPPERS table directly using SQL, or by using the Conductor UI.</para>
<para><emphasis>Using SQL</emphasis></para>
<para>If you choose register your cartridge using SQL, possibly as part of a Virtuoso/PL
script, the required SQL will typically mirror one of the following INSERT commands.</para>
<para>Below, a cartridge for OpenCalais is being installed which will be tried when
the MIME type of the data being sponged is one of text/plain, text/xml or text/html.
(The definition of the SYS_RDF_MAPPERS table was introduced earlier in section
'Cartridge Registry'.)</para>
<programlisting><![CDATA[
insert soft DB.DBA.SYS_RDF_MAPPERS (
RM_PATTERN, RM_TYPE, RM_HOOK, RM_KEY, RM_DESCRIPTION, RM_ENABLED)
values (
'(text/plain)|(text/xml)|(text/html)', 'MIME', 'DB.DBA.RDF_LOAD_CALAIS',
null, 'Opencalais', 1);
]]></programlisting>
<para>As an alternative to matching on the content's MIME type,
candidate cartridges to be tried in the conversion pipeline can be identified by matching the
data source URL against a URL pattern stored in the cartridge's entry in the Cartridge Registry.</para>
<programlisting><![CDATA[
insert soft DB.DBA.SYS_RDF_MAPPERS (
RM_PATTERN, RM_TYPE, RM_HOOK, RM_KEY, RM_DESCRIPTION, RM_OPTIONS)
values (
'(http://api.crunchbase.com/v/1/.*)|(http://www.crunchbase.com/.*)', 'URL',
'DB.DBA.RDF_LOAD_CRUNCHBASE', null, 'CrunchBase', null);
]]></programlisting>
<para>The value of RM_ID to set depends on where in the cartridge invocation order you want
to position a particular cartridge. RM_ID should be set lower than 10028 to ensure the cartridge
is tried before the ODS-Briefcase (WebDAV) metadata extractor, which is always the last mapper to
be tried if no preceding cartridge has been successful.</para>
<programlisting><![CDATA[
UPDATE DB.DBA.SYS_RDF_MAPPERS
SET RM_ID = 1000
WHERE RM_HOOK = 'DB.DBA.RDF_LOAD_BIN_DOCUMENT';
]]></programlisting>
<para><emphasis>Using Conductor</emphasis></para>
<para>Cartridges can be added manually using the 'Add' panel of the 'RDF Cartridges' screen.</para>
<figure id="spong4" float="1">
<title>RDF Cartridges</title>
<graphic fileref="ui/spong4.png"/>
</figure>
<figure id="spong5" float="1">
<title>RDF Cartridges</title>
<graphic fileref="ui/spong5.png"/>
</figure>
<para><emphasis>Installing Stylesheets</emphasis></para>
<para>Although you could place your cartridge stylesheet in any folder configured to be accessible
by Virtuoso, the simplest option is to upload them to the DAV/VAD/rdf_mappers/xslt folder using the
WebDAV browser accessible from the Conductor UI.</para>
<figure id="spong6" float="1">
<title>WebDAV browser</title>
<graphic fileref="ui/spong6.png"/>
</figure>
<para>Should you wish to locate your stylesheets elsewhere, ensure
that the DirsAllowed setting in the virtuoso.ini file is configured appropriately.</para>
</sect4>
<sect4 id="virtuosospongercreatecustcartrexmp">
<title>Example - MusicBrainz: A Music Metadatabase</title>
<para>To illustrate some of the material presented so far, we'll delve
deeper into the <ulink url="http://musicbrainz.org/">MusicBrainz</ulink> cartridge mentioned earlier.</para>
<para><emphasis>MusicBrainz XML Web Service</emphasis></para>
<para>The cartridge extracts data through the <ulink url="http://musicbrainz.org/doc/XMLWebService">MusicBrainz XML Web Service</ulink> using, as the basis
for the initial query, an item type and MBID (MusicBrainz ID) extracted from the original URI submitted
to the RDF proxy. A range of item types are supported including artist, release and track.</para>
<para>Using the album "Imagine" by John Lennon as an example, a standard HTML description of
the album (which has an MBID of f237e6a0-4b0e-4722-8172-66f4930198bc) can be retrieved direct from
MusicBrainz using the URL:</para>
<programlisting><![CDATA[
http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html
]]></programlisting>
<para>Alternatively, information can be extracted in XML form through the web service.
A description of the tracks on the album can be obtained with the query:</para>
<programlisting><![CDATA[
http://musicbrainz.org/ws/1/release/f237e6a0-4b0e-4722-8172-66f4930198bc?type=xml&inc=tracks
]]></programlisting>
<para>The XML returned by the web service is shown below (only the first two tracks
are shown for brevity):</para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<metadata xmlns="http://musicbrainz.org/ns/mmd-1.0#"
xmlns:ext="http://musicbrainz.org/ns/ext-1.0#">
<release id="f237e6a0-4b0e-4722-8172-66f4930198bc" type="Album Official" >
<title>Imagine</title>
<text-representation language="ENG" script="Latn"/>
<asin>B0000457L2</asin>
<track-list>
<track id="b88bdafd-e675-4c6a-9681-5ea85ab99446">
<title>Imagine</title>
<duration>182933</duration>
</track>
<track id="b38ce90d-3c47-4ccd-bea2-4718c4d34b0d">
<title>Crippled Inside</title>
<duration>227906</duration>
</track>
. . .
</track-list>
</release>
</metadata>
]]></programlisting>
<para>Although, as shown above, MusicBrainz defines its own <ulink url="http://musicbrainz.org/doc/MusicBrainzXMLMetaData">XML Metadata Format</ulink> to represent
music metadata, the MusicBrainz sponger converts the raw data to a subset of the <ulink url="http://musicontology.com/">Music Ontology</ulink>,
an RDF vocabulary which aims to provide a set of core classes and properties for describing music
on the Semantic Web. Part of the subset used is depicted in the following RDF graph (representing
in this case a John Cale album).</para>
<figure id="spong7" float="1">
<title>RDF graph</title>
<graphic fileref="ui/spong7.png"/>
</figure>
<para>With the prefix mo: denoting the Music Ontology at http://purl.org/ontology/mo/, it can be
seen that artists are represented by instances of class mo:Artist, their albums, records etc. by instances
of class mo:Release and tracks on these releases by class mo:Track. The property foaf:made links an
artist and his/her releases. Property mo:track links a release with the tracks it contains</para>
<para><emphasis>RDF Output</emphasis></para>
<para>An RDF description of the album can be obtained by sponging the same URL, i.e. by submitting it to the Sponger's proxy interface using the URL:</para>
<programlisting><![CDATA[
http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html
]]></programlisting>
<para>The extract below shows part of the (reorganized) RDF output returned by the Sponger
for "Imagine". Only the album's title track is included.</para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
<rdf:Description
rdf:about="http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html">
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Document"/>
</rdf:Description>
<rdf:Description
rdf:about="http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html">
<foaf:primaryTopic xmlns:foaf="http://xmlns.com/foaf/0.1/"
rdf:resource="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html#this"/>
</rdf:Description>
<rdf:Description rdf:about="http://purl.org/ontology/mo/">
<rdf:type rdf:resource="http://www.openlinksw.com/schema/attribution#DataSource"/>
</rdf:Description>
...
<rdf:Description
rdf:about="http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html">
<rdfs:isDefinedBy rdf:resource="http://purl.org/ontology/mo/"/>
</rdf:Description>
...
<!-- Record description -->
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html#this">
<rdf:type rdf:resource="http://purl.org/ontology/mo/Record"/>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html#this">
<dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">Imagine</dc:title>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html#this">
<mo:release_status xmlns:mo="http://purl.org/ontology/mo/" rdf:resource="http://purl.org/ontology/mo/official"/>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html#this">
<mo:release_type xmlns:mo="http://purl.org/ontology/mo/"
rdf:resource="http://purl.org/ontology/mo/album"/>
</rdf:Description>
<!-- Title track description -->
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/release/f237e6a0-4b0e-4722-8172-66f4930198bc.html#this">
<mo:track xmlns:mo="http://purl.org/ontology/mo/"
rdf:resource="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/track/b88bdafd-e675-4c6a-9681-5ea85ab99446.html#this"/>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/track/b88bdafd-e675-4c6a-9681-5ea85ab99446.html#this">
<rdf:type rdf:resource="http://purl.org/ontology/mo/Track"/>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/track/b88bdafd-e675-4c6a-9681-5ea85ab99446.html#this">
<dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">Imagine</dc:title>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/track/b88bdafd-e675-4c6a-9681-5ea85ab99446.html#this">
<mo:track_number xmlns:mo="http://purl.org/ontology/mo/">1</mo:track_number>
</rdf:Description>
<rdf:Description
rdf:about="http://demo.openlinksw.com/about/rdf/http://musicbrainz.org/track/b88bdafd-e675-4c6a-9681-5ea85ab99446.html#this">
<mo:duration xmlns:mo="http://purl.org/ontology/mo/" rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">182933</mo:duration>
</rdf:Description>
</rdf:RDF>
]]></programlisting>
<para><emphasis>Cartridge Hook Function</emphasis></para>
<para>The cartridge's hook function is listed below. It is important to note that MusicBrainz
supports a variety of query types, each of which returns a different set of information, depending
on the item type being queried. Full details can be found on the MusicBrainz? site. The sponger
cartridge is capable of handling all the query types supported by MusicBrainz? and is intended to
be used in a drill-down scenario, as would be the case when using an RDF browser such as the
<ulink url="http://ode.openlinksw.com/">OpenLink Data Explorer (ODE)</ulink>. This example focuses primarily on the types release and track.</para>
<programlisting><![CDATA[
create procedure DB.DBA.RDF_LOAD_MBZ (
in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout _ret_body any, inout aq any, inout ps any, inout _key any,
inout opts any)
{
declare kind, id varchar;
declare tmp, incs any;
declare uri, cnt, hdr, inc, xd, xt varchar;
tmp := regexp_parse ('http://musicbrainz.org/([^/]*)/([^\.]+)', new_origin_uri, 0);
declare exit handler for sqlstate '*'
{
-- dbg_printf ('%s', __SQL_MESSAGE);
return 0;
};
if (length (tmp) < 6)
return 0;
kind := subseq (new_origin_uri, tmp[2], tmp[3]);
id := subseq (new_origin_uri, tmp[4], tmp[5]);
incs := vector ();
if (kind = 'artist')
{
inc := 'aliases artist-rels label-rels release-rels track-rels url-rels';
incs :=
vector (
'sa-Album', 'sa-Single', 'sa-EP', 'sa-Compilation', 'sa-Soundtrack',
'sa-Spokenword', 'sa-Interview', 'sa-Audiobook', 'sa-Live', 'sa-Remix', 'sa-Other'
, 'va-Album', 'va-Single', 'va-EP', 'va-Compilation', 'va-Soundtrack',
'va-Spokenword', 'va-Interview', 'va-Audiobook', 'va-Live', 'va-Remix', 'va-Other'
);
}
else if (kind = 'release')
inc := 'artist counts release-events discs tracks artist-rels label-rels release-rels track-rels url-rels track-level-rels labels';
else if (kind = 'track')
inc := 'artist releases puids artist-rels label-rels release-rels track-rels url-rels';
else if (kind = 'label')
inc := 'aliases artist-rels label-rels release-rels track-rels url-rels';
else
return 0;
if (dest is null)
DELETE FROM DB.DBA.RDF_QUAD WHERE G = DB.DBA.RDF_MAKE_IID_OF_QNAME (graph_iri);
DB.DBA.RDF_LOAD_MBZ_1 (graph_iri, new_origin_uri, dest, kind, id, inc);
DB.DBA.TTLP (sprintf ('<%S> <http://xmlns.com/foaf/0.1/primaryTopic> <%S> .\n<%S> a <http://xmlns.com/foaf/0.1/Document> .',
new_origin_uri, DB.DBA.RDF_SPONGE_PROXY_IRI (new_origin_uri), new_origin_uri),
'', graph_iri);
foreach (any inc1 in incs) do
{
DB.DBA.RDF_LOAD_MBZ_1 (graph_iri, new_origin_uri, dest, kind, id, inc1);
}
return 1;
};
]]></programlisting>
<para>The hook function uses a subordinate procedure RDF_LOAD_MBZ_1:</para>
<programlisting><![CDATA[
create procedure DB.DBA.RDF_LOAD_MBZ_1 (in graph_iri varchar, in new_origin_uri varchar,
in dest varchar, in kind varchar, in id varchar, in inc varchar)
{
declare uri, cnt, xt, xd, hdr any;
uri := sprintf ('http://musicbrainz.org/ws/1/%s/%s?type=xml&inc=%U', kind, id, inc);
cnt := RDF_HTTP_URL_GET (uri, '', hdr, 'GET', 'Accept: */*');
xt := xtree_doc (cnt);
xd := DB.DBA.RDF_MAPPER_XSLT (registry_get ('_rdf_mappers_path_') || 'xslt/mbz2rdf.xsl', xt,
vector ('baseUri', new_origin_uri));
xd := serialize_to_UTF8_xml (xd);
DB.DBA.RM_RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
};
]]></programlisting>
<para><emphasis>XSLT Stylesheet</emphasis></para>
<para>The key sections of the MusicBrainz XSLT template relevant to this example are
listed below. Only the sections relating to an artist, his releases, or the tracks on those
releases, are shown.</para>
<programlisting><![CDATA[
<!DOCTYPE xsl:stylesheet [
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#">
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#">
<!ENTITY mo "http://purl.org/ontology/mo/">
<!ENTITY foaf "http://xmlns.com/foaf/0.1/">
<!ENTITY mmd "http://musicbrainz.org/ns/mmd-1.0#">
<!ENTITY dc "http://purl.org/dc/elements/1.1/">
]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vi="http://www.openlinksw.com/virtuoso/xslt/"
xmlns:rdf=""
xmlns:rdfs=""
xmlns:foaf=""
xmlns:mo=""
xmlns:mmd=""
xmlns:dc=""
>
<xsl:output method="xml" indent="yes" />
<xsl:variable name="base" select="'http://musicbrainz.org/'"/>
<xsl:variable name="uc">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
<xsl:variable name="lc">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:template match="/mmd:metadata">
<rdf:RDF>
<xsl:apply-templates />
</rdf:RDF>
</xsl:template>
...
<xsl:template match="mmd:artist[@type='Person']">
<mo:MusicArtist rdf:about="{vi:proxyIRI (concat($base,'artist/',@id,'.html'))}">
<foaf:name><xsl:value-of select="mmd:name"/></foaf:name>
<xsl:for-each select="mmd:release-list/mmd:release|mmd:relation-list[@target-type='Release']/mmd:relation/mmd:release">
<foaf:made rdf:resource="{vi:proxyIRI (concat($base,'release/',@id,'.html'))}"/>
</xsl:for-each>
</mo:MusicArtist>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="mmd:release">
<mo:Record rdf:about="{vi:proxyIRI (concat($base,'release/',@id,'.html'))}">
<dc:title><xsl:value-of select="mmd:title"/></dc:title>
<mo:release_type rdf:resource="{translate (substring-before (@type, ' '),
$uc, $lc)}"/>
<mo:release_status rdf:resource="{translate (substring-after (@type, ' '), $uc,
$lc)}"/>
<xsl:for-each select="mmd:track-list/mmd:track">
<mo:track rdf:resource="{vi:proxyIRI (concat($base,'track/',@id,'.html'))}"/>
</xsl:for-each>
</mo:Record>
<xsl:apply-templates select="mmd:track-list/mmd:track"/>
</xsl:template>
<xsl:template match="mmd:track">
<mo:Track rdf:about="{vi:proxyIRI (concat($base,'track/',@id,'.html'))}">
<dc:title><xsl:value-of select="mmd:title"/></dc:title>
<mo:track_number><xsl:value-of select="position()"/></mo:track_number>
<mo:duration rdf:datatype="integer">
<xsl:value-of select="mmd:duration"/>
</mo:duration>
<xsl:if test="artist[@id]">
<foaf:maker rdf:resource="{vi:proxyIRI (concat ($base, 'artist/',
artist/@id, '.html'))}"/>
</xsl:if>
<mo:musicbrainz rdf:resource="{vi:proxyIRI (concat ($base, 'track/', @id, '.html'))}"/>
</mo:Track>
</xsl:template>
...
<xsl:template match="text()"/>
</xsl:stylesheet>
]]></programlisting>
</sect4>
<sect4 id="virtuosospongercreatecartentextmapcont">
<title>Entity Extractor & Mapper Component</title>
<para>
Used to extract RDF from a Web Data Source the Virtuoso Sponger Cartridge RDF Extractor consumes services from: Virtuoso PL, C/C++, Java
based RDF Extractors</para>
<para>The RDF mappers provide a way to extract metadata from non-RDF documents such as HTML pages,
images Office documents etc. and pass to SPARQL sponger (crawler which retrieve missing
source graphs). For brevity further in this article the "RDF mapper" we simply will call "mapper".
</para>
<para>The mappers consist of PL procedure (hook) and extractor, where extractor itself can be built
using PL, C or any external language supported by Virtuoso server.</para>
<para>Once the mapper is developed it must be plugged into the SPARQL engine by adding a record
in the table DB.DBA.SYS_RDF_MAPPERS.</para>
<para>If a SPARQL query instructs the SPARQL processor to retrieve target graph into local storage,
then the SPARQL sponger will be invoked. If the target graph IRI represents a dereferenceable URL
then content will be retrieved using content negotiation. The next step is the content type
to be detected:</para>
<itemizedlist>
<listitem>If RDF and no further transformation such as GRDDL is needed, then the process would stop.</listitem>
<listitem>If such as 'text/plain' and is not known to have metadata, then the SPARQL sponger will
look in the DB.DBA.SYS_RDF_MAPPERS table by order of RM_ID and for every matching URL or MIME
type pattern (depends on column RM_TYPE) will call the mapper hook.
<itemizedlist>
<listitem>If hook returns zero the next mapper will be tried;</listitem>
<listitem>If result is negative the process would stop instructing the SPARQL nothing was retrieved;</listitem>
<listitem>If result is positive the process would stop instructing the SPARQL that metadata was retrieved.</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<sect5 id="virtuosospongercartridgesextractorpl">
<title>Virtuoso/PL based Extractors</title>
<para><emphasis>PL hook requirements:</emphasis></para>
<para>Every PL function used to plug a mapper into SPARQL engine must have following parameters in
the same order:</para>
<itemizedlist>
<listitem>in graph_iri varchar: the graph IRI which is currently retrieved</listitem>
<listitem>in new_origin_uri varchar: the URL of the document retrieved</listitem>
<listitem>in destination varchar: the destination graph IRI</listitem>
<listitem>inout content any: the content of the document retrieved by SPARQL sponger </listitem>
<listitem>inout async_queue any: an asynchronous queue, can be used to push something to execute
on background if needed.</listitem>
<listitem>inout ping_service any: the value of [SPARQL] - PingService INI parameter, could be used
to configure a service notification such as pingthesemanticweb.com</listitem>
<listitem>inout api_key any: a plain text id single key value or serialized vector of key structure,
basically the value of RM_KEY column of the DB.DBA.SYS_RDF_MAPPERS table.</listitem>
</itemizedlist>
<para>Note: the names of the parameters are not important, but their order and presence are!</para>
<para><emphasis>Example Implementation:</emphasis></para>
<para>In the example script bellow we implement a basic mapper, which maps a text/plain mime type to an
imaginary ontology, which extends the class Document from FOAF with properties 'txt:UniqueWords'
and 'txt:Chars', where the prefix 'txt:' we specify as 'urn:txt:v0.0:'.</para>
<programlisting><![CDATA[
use DB;
create procedure DB.DBA.RDF_LOAD_TXT_META
(
in graph_iri varchar,
in new_origin_uri varchar,
in dest varchar,
inout ret_body any,
inout aq any,
inout ps any,
inout ser_key any
)
{
declare words, chars int;
declare vtb, arr, subj, ses, str any;
declare ses any;
-- if any error we just say nothing can be done
declare exit handler for sqlstate '*'
{
return 0;
};
subj := coalesce (dest, new_origin_uri);
vtb := vt_batch ();
chars := length (ret_body);
-- using the text index procedures we get a list of words
vt_batch_feed (vtb, ret_body, 1);
arr := vt_batch_strings_array (vtb);
-- the list has 'word' and positions array, so we must divide by 2
words := length (arr) / 2;
ses := string_output ();
-- we compose a N3 literal
http (sprintf ('<%s> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://xmlns.com/foaf/0.1/Document> .\n', subj), ses);
http (sprintf ('<%s> <urn:txt:v0.0:UniqueWords> "%d" .\n', subj, words), ses);
http (sprintf ('<%s> <urn:txt:v0.0:Chars> "%d" .\n', subj, chars), ses);
str := string_output_string (ses);
-- we push the N3 text into the local store
DB.DBA.TTLP (str, new_origin_uri, subj);
return 1;
};
DELETE FROM DB.DBA.SYS_RDF_MAPPERS WHERE RM_HOOK = 'DB.DBA.RDF_LOAD_TXT_META';
INSERT SOFT DB.DBA.SYS_RDF_MAPPERS (RM_PATTERN, RM_TYPE, RM_HOOK, RM_KEY, RM_DESCRIPTION)
VALUES ('(text/plain)', 'MIME', 'DB.DBA.RDF_LOAD_TXT_META', null, 'Text Files (demo)');
-- here we set order to some large number so don't break existing mappers
update DB.DBA.SYS_RDF_MAPPERS
SET RM_ID = 2000
WHERE RM_HOOK = 'DB.DBA.RDF_LOAD_TXT_META';
]]></programlisting>
<para>To test the mapper we just use /sparql endpoint with option 'Retrieve remote RDF data
for all missing source graphs' to execute:</para>
<programlisting><![CDATA[
SELECT *
FROM <URL-of-a-txt-file>
WHERE { ?s ?p ?o }
]]></programlisting>
<para>It is important that the SPARQL_UPDATE role to be granted to "SPARQL" account in order
to allow local repository update via sponge feature.</para>
<para><emphasis>Authentication in Sponger</emphasis></para>
<para>To enable usage of user defined authentication, there are added more parameters to the
/proxy/rdf and /sparql endpoints. So to use it, the RDF browser and iSPARQL should send following
url parameters:</para>
<itemizedlist>
<listitem>for /proxy/rdf endpoint:
<programlisting><![CDATA[
'login=<account name>'
]]></programlisting>
</listitem>
<listitem>for /sparql endpoint:
<programlisting><![CDATA[
get-login=<account name>
]]></programlisting>
</listitem>
</itemizedlist>
</sect5>
<sect5 id="virtuosospongerrdfmappersregistry"><title>Registry</title>
<para>The table DB.DBA.SYS_RDF_MAPPERS is used as registry for registering RDF mappers.</para>
<programlisting><![CDATA[
create table DB.DBA.SYS_RDF_MAPPERS (
RM_ID integer identity, -- mapper ID, designate order of execution
RM_PATTERN varchar, -- a REGEX pattern to match URL or MIME type
RM_TYPE varchar default 'MIME', -- what property of the current resource to match: MIME or URL are supported at present
RM_HOOK varchar, -- fully qualified PL function name e.q. DB.DBA.MY_MAPPER_FUNCTION
RM_KEY long varchar, -- API specific key to use
RM_DESCRIPTION long varchar, -- Mapper description, free text
RM_ENABLED integer default 1, -- a flag 0 or 1 integer to include or exclude the given mapper from processing chain
primary key (RM_TYPE, RM_PATTERN))
;
]]></programlisting>
<para>The current way to register/update/unregister a mapper is just a DML statement e.g.
NSERT/UPDATE/DELETE.</para>
</sect5>
<sect5 id="virtuosospongerrdfmappersexec"><title>Execution order and processing</title>
<para>When SPARQL retrieves a resource with unknown content it will look in the mappers registry
and will loop over every record having RM_ENABLED flag true. The sequence of look-up is based on
ordering by RM_ID column. For every record it will either try matching the MIME type or URL against
RM_PATTERN value and if there is match the function specified in RM_HOOK column will be called.
If the function doesn't exists or signal an error the SPARQL will look at next record.</para>
<para>When it stops looking? It will stop if value returned by mapper function is positive or
negative number, if the return is negative processing stops with meaning no RDF was supplied,
if return is positive the meaning is that RDF data was extracted, if zero integer is returned
then SPARQL will look for next mapper. The mapper function also can return zero if it is expected
next mapper in the chain to get more RDF data.</para>
<para>If none of the mappers matches the signature (MIME type nor URL) the built-in WebDAV
metadata extractor will be called.</para>
</sect5>
<sect5 id="virtuosospongerrdfmappersextfunc"><title>Extension function</title>
<para>The mapper function is a PL stored procedure with following signature:</para>
<programlisting><![CDATA[
THE_MAPPER_FUNCTION_NAME (
in graph_iri varchar,
in origin_uri varchar,
in destination_uri varchar,
inout content varchar,
inout async_notification_queue any,
inout ping_service any,
inout keys any
)
{
-- do processing here
-- return -1, 0 or 1 (as explained above in Execution order and processing section)
}
;
]]></programlisting>
<para><emphasis>Parameters</emphasis></para>
<itemizedlist>
<listitem>graph_iri - the target graph IRI</listitem>
<listitem>origin_uri - the current URI of processing</listitem>
<listitem>destination_uri - get:destination value</listitem>
<listitem>content - the resource content</listitem>
<listitem>async_notification_queue - if INI parameter PingService is specified in SPARQL
section in the INI file, this is a pre-allocated asynchronous queue to be used to call
ping service</listitem>
<listitem>ping_service - the URL of the ping service configured in SPARQL section in the
INI in PingService parameter</listitem>
<listitem>keys - a string value contained in the RM_KEY column for given mapper, can be
single string or serialized array, generally can be used as mapper specific data.</listitem>
</itemizedlist>
<para><emphasis>Return value</emphasis></para>
<itemizedlist>
<listitem>0 - no data was retrieved or some next matching mapper must extract more data</listitem>
<listitem>1 - data is retrieved, stop looking for other mappers</listitem>
<listitem>-1 - no data is retrieved, stop looking for more data</listitem>
</itemizedlist>
</sect5>
<sect5 id="virtuosospongerrdfmapperspackage"><title>RDF Mappers package content</title>
<para>The Virtuoso supply as a rdf_mappers_dav VAD package a cartridge for extracting RDF data
from certain popular Web resources and file types. It can be installed (if not already) using
VAD_INSTALL function, see the VAD chapter in documentation on how to do that.</para>
<para><emphasis>HTTP-in-RDF</emphasis></para>
<para>Maps the HTTP request response to HTTP Vocabulary in RDF, see http://www.w3.org/2006/http#.</para>
<para>This mapper is disabled by default. If it's enabled , it must be first in order of execution.</para>
<para>Also it always will return 0, which means any other mapper should push more data.</para>
<para><emphasis>HTML</emphasis></para>
<para>This mapper is composite, it looking for metadata which can specified in a HTML pages as
follows:</para>
<itemizedlist>
<listitem>Embedded/linked RDF
<itemizedlist>
<listitem>scan for meta in RDF
<programlisting><![CDATA[
<link rel="meta" type="application/rdf+xml"
]]></programlisting></listitem>
<listitem>RDF embedded in xHTML (as markup or inside XML comments)</listitem>
</itemizedlist>
</listitem>
<listitem>Micro-formats
<itemizedlist>
<listitem>GRDDL - GRDDL Data Views: RDF expressed in XHTML and XML: http://www.w3.org/2003/g/data-view#</listitem>
<listitem>eRDF - http://purl.org/NET/erdf/profile</listitem>
<listitem>RDFa</listitem>
<listitem>hCard - http://www.w3.org/2006/03/hcard</listitem>
<listitem>hCalendar - http://dannyayers.com/microformats/hcalendar-profile</listitem>
<listitem>hReview - http://dannyayers.com/micromodels/profiles/hreview</listitem>
<listitem>relLicense - CC license: http://web.resource.org/cc/schema.rdf</listitem>
<listitem>Dublin Core (DCMI) - http://purl.org/dc/elements/1.1/</listitem>
<listitem>geoURL - http://www.w3.org/2003/01/geo/wgs84_pos#</listitem>
<listitem>Google Base - OpenLink Virtuoso specific mapping</listitem>
<listitem>Ning Metadata </listitem>
</itemizedlist>
</listitem>
<listitem>Feeds extraction
<itemizedlist>
<listitem>RSS/RDF - SIOC & AtomOWL</listitem>
<listitem>RSS 1.0 - RSS/RDF, SIOC & AtomOWL</listitem>
<listitem>Atom 1.0 - RSS/RDF, SIOC & AtomOWL</listitem>
</itemizedlist>
</listitem>
<listitem>xHTML metadata transformation using FOAF (foaf:Document) and Dublin Core
properties (dc:title, dc:subject etc.)</listitem>
</itemizedlist>
<para>The HTML page mapper will look for RDF data in order as listed above, it will try to extract
metadata on each step and will return positive flag if any of the above step give a RDF data. In
case where page URL matches some of other RDF mappers listed in registry it will return 0 so
next mapper to extract more data. In order to function properly, this mapper must be executed
before any other specific mappers.</para>
<para><emphasis>Flickr URLs</emphasis></para>
<para>This mapper extracts metadata of the Flickr images, using Flickr REST API. To function
properly it must have configured key. The Flickr mapper extracts metadata using: CC license,
Dublin Core, Dublin Core Metadata Terms, GeoURL, FOAF, EXIF: http://www.w3.org/2003/12/exif/ns/ ontology.
</para>
<para><emphasis>Amazon URLs</emphasis></para>
<para>This mapper extracts metadata for Amazon articles, using Amazon REST API. It needs a Amazon
API key in order to be functional.</para>
<para><emphasis>eBay URLs</emphasis></para>
<para>Implements eBay REST API for extracting metadata of eBay articles, it needs a key and user
name to be configured in order to work.</para>
<para><emphasis>Open Office (OO) documents</emphasis></para>
<para>The OO documents contains metadata which can be extracted using UNZIP, so this extractor
needs Virtuoso unzip plugin to be configured on the server.</para>
<para><emphasis>Yahoo traffic data URLs</emphasis></para>
<para>Implements transformation of the result of Yahoo traffic data to RDF.
</para>
<para><emphasis>iCal files</emphasis></para>
<para>Transform iCal files to RDF as per http://www.w3.org/2002/12/cal/ical# .</para>
<para><emphasis>Binary content, PDF, PowerPoint</emphasis></para>
<para>The unknown binary content, PDF and MS PowerPoint files can be transformed to RDF using
Aperture framework (http://aperture.sourceforge.net/). This mapper needs Virtuoso with Java hosting
support, Aperture framework and MetaExtractor.class installed on the host system in order to work.</para>
<para>The Aperture framework & MetaExtractor.class must be installed on the system before to
install the RDF mappers package. If the package is already installed, then to activate this mapper
you can just re-install the VAD.</para>
<para><emphasis>Setting-up Virtuoso with Java hosting to run Aperture framework</emphasis></para>
<itemizedlist>
<listitem>Install a Virtuoso binary which includes built-in Java hosting support (The executable name will
indicate whether the required hosting support is built in - a suitably enabled executable will include
javavm in the name, for example virtuoso-javavm-t, rather than virtuoso-t).</listitem>
<listitem>Download the Aperture framework from http://aperture.sourceforge.net.</listitem>
<listitem>Unpack the contents of the framework's lib directory into an 'aperture' subdirectory of the
Virtuoso working directory, i.e. of the directory containing the database and virtuoso.ini files.</listitem>
<listitem>Ensure the Virtuoso working directory includes a 'lib' subdirectory containing the file
MetaExtractor.class. (At the current time MetaExtractor.class in not included in the rdf_mappers VAD.
Please contact OpenLink Technical Support to obtain a copy.)</listitem>
<listitem>In the [Parameters] section of the virtuoso.ini configuration file:
<itemizedlist>
<listitem>Add the line (linebreaks have been inserted for clarity):
<programlisting><![CDATA[
JavaClasspath = lib:aperture/DFKIUtils2.jar:aperture/JempBox-0.2.0.jar:aperture/activation-1.0.2-upd2.jar:aperture/aduna-commons-xml-2.0.jar:
aperture/ant-compression-utils-1.7.1.jar:aperture/aperture-1.2.0.jar:aperture/aperture-examples-1.2.0.jar:aperture/aperture-test-1.2.0.jar:
aperture/applewrapper-0.2.jar:aperture/bcmail-jdk14-132.jar:aperture/bcprov-jdk14-132.jar:aperture/commons-codec-1.3.jar:aperture/commons-httpclient-3.1.jar:
aperture/commons-lang-2.3.jar:aperture/demork-2.1.jar:aperture/flickrapi-1.0.jar:aperture/fontbox-0.2.0-dev.jar:aperture/htmlparser-1.6.jar:
aperture/ical4j-1.0-beta4.jar:aperture/infsail-0.1.jar:aperture/jacob-1.10.jar:aperture/jai_codec-1.1.3.jar:aperture/jai_core-1.1.3.jar:aperture/jaudiotagger-1.0.8.jar:
aperture/jcl104-over-slf4j-1.5.0.jar:aperture/jpim-0.1-aperture-1.jar:aperture/junit-3.8.1.jar:aperture/jutf7-0.9.0.jar:aperture/mail-1.4.jar:
aperture/metadata-extractor-2.4.0-beta-1.jar:aperture/mstor-0.9.11.jar:aperture/nrlvalidator-0.1.jar:aperture/openrdf-sesame-2.2.1-onejar-osgi.jar:
aperture/osgi.core-4.0.jar:aperture/pdfbox-0.7.4-dev-20071030.jar:aperture/poi-3.0.2-FINAL-20080204.jar:aperture/poi-scratchpad-3.0.2-FINAL-20080204.jar:
aperture/rdf2go.api-4.6.2.jar:aperture/rdf2go.impl.base-4.6.2.jar:aperture/rdf2go.impl.sesame20-4.6.2.jar:aperture/rdf2go.impl.util-4.6.2.jar:
aperture/slf4j-api-1.5.0.jar:aperture/slf4j-jdk14-1.5.0.jar:aperture/unionsail-0.1.jar:aperture/winlaf-0.5.1.jar
]]></programlisting>
</listitem>
<listitem>Ensure DirsAllowed includes directories /tmp, (or the temporary directory for the host
operating system), lib and aperture.</listitem>
</itemizedlist>
</listitem>
<listitem>Start the Virtuoso server with java hosting support</listitem>
<listitem>Configure the cartridge either by installing the rdf_mappers VAD or, if the VAD is already
installed, by executing procedure DB.DBA.RDF_APERTURE_INIT.</listitem>
<listitem>During the VAD installation process, RDF_APERTURE_INIT() configures the Aperture cartridge. If
you look in the list of available cartridges under the RDF > Sponger tab in Conductor, you should see
an entry for 'Binary Files'.</listitem>
</itemizedlist>
<para>To check the cartridge has been configured, connect with Virtuoso's ISQL tool:</para>
<itemizedlist>
<listitem>Issue the command:
<programlisting><![CDATA[
SQL> SELECT udt_is_available('APERTURE.DBA.MetaExtractor');
]]></programlisting>
</listitem>
<listitem>Copy a test PDF document to the Virtuoso working directory, then execute:
<programlisting><![CDATA[
SQL> SELECT APERTURE.DBA."MetaExtractor"().getMetaFromFile ('some_pdf_in_server_working_dir.pdf', 0);
... some RDF data should be returned ...
]]></programlisting>
</listitem>
</itemizedlist>
<para>You should now be able to sponge all document types supported by the Aperture framework, (using
one of the standard Sponger invocation mechanisms, for instance with a URL of the form
http://localhost:8890/about/rdf/http://targethost/targetfile.pdf), subject to the MIME type pattern
filters configured for the cartridge in the Conductor UI. By default the Aperture cartridge is
registered to match MIME types (application/octet-stream)|(application/pdf)|(application/mspowerpoint).
To sponge all the MIME types Aperture is capable of handling, changed the MIME type pattern to
'application/.*'.</para>
<para>Important: The installation guidelines presented above have been verified on Mac OS X with
Aperture 1.2.0. Some adjustment may be needed for different operating systems or versions of Aperture.</para>
<para><emphasis>Examples & tutorials</emphasis></para>
<para>How to write own RDF mapper? Look at Virtuoso tutorial on this subject
http://demo.openlinksw.com/tutorial/rdf/rd_s_1/rd_s_1.vsp .
</para>
</sect5>
</sect4>
</sect3>
<sect3 id="virtuosospongercreatecustcartrxslt">
<title>Meta-Cartridges</title>
<para>So far the discussion has centered on 'primary' cartridges. However,
Virtuoso supports an alternative type of cartridge, a 'meta-cartridge'. The way a
meta-cartridge operates is essentially the same as a primary cartridge, that is it
has a cartridge hook function with the same signature and its inserts data into the
quad store through entity extraction and ontology mapping as before. Where meta-cartridges
differ from primary cartridges is in their intent and their position in the cartridge
invocation pipeline.</para>
<para>The purpose of meta-cartridges is to enrich graphs produced by other (primary)
cartridges. They serve as general post-processors to add additional information about selected
entities in an RDF graph. For instance, a particular meta-cartridge might be designed to search
for entities of type 'umbel:Country' in a given graph, and then add additional statements about
each country it finds, where the information contained in these statements is retrieved from the
web service targeted by the meta-cartridge. One such example might be a 'World Bank' meta-cartridge
which adds information relating to a country's GDP, its exports of goods and services as a percentage
of GDP etc; retrieved using the <ulink url="http://developer.worldbank.org/docs/">World Bank web service API</ulink>.
In order to benefit from the World Bank meta-cartridge, any primary cartridge which might generate instance data relating to countries should
ensure that each country instance it handles is also described as being of rdf:type 'umbel:Country'.
Here, the <ulink url="http://wiki.umbel.org/index.php/Welcome">UMBEL</ulink> (Upper Mapping and Binding Exchange Layer) ontology is used as a data-source-agnostic
classification system. It provides a core set of 20,000+ subject concepts which act as "a fixed set of
reference points in a global knowledge space". The use of UMBEL in this way serves to decouple
meta-cartridges from primary cartridges and data source specific ontologies.</para>
<para>Virtuoso includes two default meta-cartridges which use
UMBEL and <ulink url="http://www.opencalais.com/">OpenCalais</ulink> to augment source graphs.</para>
<para><emphasis>Registration</emphasis></para>
<para>Meta-cartridges must be registered in the RDF_META_CARTRIDGES table, which fulfills a role
similar to the SYS_RDF_MAPPERS table used by primary cartridges. The structure of the table, and the
meaning and use of its columns, are similar to SYS_RDF_MAPPERS. The meta-cartridge hook function
signature is identical to that for primary cartridges.</para>
<para>The RDF_META_CARTRIDGES table definition is as follows:</para>
<programlisting><![CDATA[
create table DB.DBA.RDF_META_CARTRIDGES (
MC_ID INTEGER IDENTITY, -- meta-cartridge ID. Determines the order of the
meta-cartridge's invocation in the Sponger
processing chain
MC_SEQ INTEGER IDENTITY,
MC_HOOK VARCHAR, -- fully qualified Virtuoso/PL function name
MC_TYPE VARCHAR,
MC_PATTERN VARCHAR, -- a REGEX pattern to match resource URL or
MIME type
MC_KEY VARCHAR, -- API specific key to use
MC_OPTIONS ANY, -- meta-cartridge specific options
MC_DESC LONG VARCHAR, -- meta-cartridge description (free text)
MC_ENABLED INTEGER -- a 0 or 1 integer flag to exclude or include
meta-cartridge from Sponger processing chain
);
]]></programlisting>
<para>(At the time of writing there is no Conductor UI for registering meta-cartridges, they must be
registered using SQL. A Conductor interface for this task will be added in due course.)</para>
<para><emphasis>Invocation</emphasis></para>
<para>Meta-cartridges are invoked through the post-processing hook procedure RDF_LOAD_POST_PROCESS
which is called, for every document retrieved, after RDF_LOAD_RDFXML loads sponged data into the quad
store.</para>
<para>Cartridges in the meta-cartridge registry (RDF_META_CARTRIDGES) are configured to match a given
MIME type or URI pattern. Matching meta-cartridges are invoked in order of their MC_SEQ value. Ordinarily
a meta-cartridge should return 0, in which case the next meta-cartridge in the post-processing chain will
be invoked. If it returns 1 or -1, the post-processing stops and no further meta-cartridges are invoked.</para>
<para>The order of processing by the Sponger cartridge pipeline is thus:</para>
<orderedlist>
<listitem>Try to get RDF in the form of TTL or RDF/XML. If RDF is retrieved if go to step 3</listitem>
<listitem>Try generating RDF through the Sponger primary cartridges as before</listitem>
<listitem>Post-process the RDF using meta-cartridges in order of their MC_SEQ value. If a meta-cartridge returns 1 or -1, stop the post-processing chain.</listitem>
</orderedlist>
<para>Notice that meta-cartridges may be invoked even if primary cartridges are not.</para>
<sect4 id="virtuosospongercreatecustcartrexfm">
<title>Example - A Campaign Finance Meta-Cartridge for Freebase</title>
<para><emphasis>Note</emphasis></para>
<para>The example which follows builds on a Freebase Sponger cartridge developed prior to the announcement of Freebase's
support for generating Linked Data through the endpoint http://rdf.freebase.com/ . The OpenLink cartridge
has since evolved to reflect these changes. A snapshot of the Freebase cartridge and stylesheet compatible
with this example can be found in Appendix C.</para>
<para><ulink url="http://www.freebase.com/">Freebase</ulink> is an open community database of the world's information which serves facts
and statistics rather than articles. Its designers see this difference in emphasis from article-oriented
databases as beneficial for developers wanting to use Freebase facts in other websites and applications.</para>
<para>Virtuoso includes a Freebase cartridge in the rdf_mappers VAD. The aim of the example cartridge presented here is to provide a lightweight
meta-cartridge that is used to conditionally add triples to graphs generated by the Freebase cartridge,
if Freebase is describing a U.S. senator.</para>
<para><emphasis>New York Times Campaign Finance (NYTCF) API</emphasis></para>
<para>The <ulink url="http://developer.nytimes.com/docs/campaign_finance_api?authChecked=1">New York Times Campaign Finance (NYTCF) API</ulink> allows you to retrieve contribution and
expenditure data based on United States Federal Election Commission filings. You can retrieve totals
for a particular presidential candidate, see aggregates by ZIP code or state, or get details on a
particular donor.</para>
<para>The API supports a number of query types. To keep this example from being overly long,
the meta-cartridge supports just one of these - a query for the candidate details. An example query
and the resulting output follow:</para>
<para><emphasis>Query:</emphasis></para>
<programlisting><![CDATA[
http://api.nytimes.com/svc/elections/us/v2/president/2008/finances/candidates/obama,barack.xml?api-key=xxxx
]]></programlisting>
<para>Result:</para>
<programlisting><![CDATA[
<result_set>
<status>OK</status>
<copyright>
Copyright (c) 2008 The New York Times Company. All Rights Reserved.
</copyright>
<results>
<candidate>
<candidate_name>Obama, Barack</candidate_name>
<committee_id>C00431445</committee_id>
<party>D</party>
<total_receipts>468841844</total_receipts>
<total_disbursements>391437723.5</total_disbursements>
<cash_on_hand>77404120</cash_on_hand>
<net_individual_contributions>426902994</net_individual_contributions>
<net_party_contributions>150</net_party_contributions>
<net_pac_contributions>450</net_pac_contributions>
<net_candidate_contributions>0</net_candidate_contributions>
<federal_funds>0</federal_funds>
<total_contributions_less_than_200>222694981.5</total_contributions_less_than_200>
<total_contributions_2300>76623262</total_contributions_2300>
<net_primary_contributions>46444638.81</net_primary_contributions>
<net_general_contributions>30959481.19</net_general_contributions>
<total_refunds>2058240.92</total_refunds>
<date_coverage_from>2007-01-01</date_coverage_from>
<date_coverage_to>2008-08-31</date_coverage_to>
</candidate>
</results>
</result_set>
]]></programlisting>
<para><emphasis>Sponging Freebase</emphasis></para>
<para><emphasis>Using OpenLink Data Explorer</emphasis></para>
<para>The following instructions assume you have the <ulink url="http://ode.openlinksw.com/">OpenLink Data Explorer (ODE)</ulink> browser extension installed in your browser.</para>
<para>An HTML description of Barack Obama can be obtained directly from Freebase by pasting the
following URL into your browser: http://www.freebase.com/view/en/barack_obama</para>
<para>To view RDF data sponged from this page, select 'Linked Data Sources' from the browser's
'View' menu. An OpenLink Data Explorer interface will load in a new tab.</para>
<para>Clicking on the 'Barack Obama' link under the 'Person' category displayed by ODE sponges
RDF data using the Freebase cartridge. Click the 'down arrow' adjacent to the 'Barack Obama' link to
explore the retrieved data.</para>
<para>Assuming your Virtuoso instance is running on port 8890 on localhost, the list of data caches displayed
by ODE should include: http://localhost:8890/about/html/http/www.freebase.com/view/en/barack_obama#this</para>
<para>The information displayed in the rest of the page relates to the entity instance identified by this URI. The prefix http://localhost:8890/about/html/http/ prepended to the
original URI indicates that the Sponger Proxy Service has been invoked. The Sponger creates an associated
entity instance (identified by the above URI with the #this suffix) which holds sponged information
about the original entity.</para>
<para><emphasis>Using the Command Line</emphasis></para>
<para>As an alternative to ODE, you can sponge from the command line with the command:</para>
<programlisting><![CDATA[
curl -H "Accept: text/xml" "http://localhost:8890/about/html/http/www.freebase.com/view/en/barack_obama"
]]></programlisting>
<para>To view the results, you can use Conductor's browser-based SPARQL interface (e.g.
http://localhost:8890/sparql) to query the resulting graph generated by the Sponger,
http://www.freebase.com/view/en/barack_obama.</para>
<para><emphasis>Installing the Meta-Cartridge</emphasis></para>
<para>To register the meta-cartridge, a procedure similar to the following can be used:</para>
<programlisting><![CDATA[
create procedure INSTALL_RDF_LOAD_NYTCF ()
{
-- delete any previous NYTCF cartridge installed as a primary cartridge
DELETE FROM SYS_RDF_MAPPERS WHERE RM_HOOK = 'DB.DBA.RDF_LOAD_NYTCF';
-- register in the meta-cartridge post-processing chain
INSERT SOFT DB.DBA.RDF_META_CARTRIDGES (MC_PATTERN, MC_TYPE, MC_HOOK,
MC_KEY, MC_DESC, MC_OPTIONS)
VALUES (
'http://www.freebase.com/view/.*',
'URL', 'DB.DBA.RDF_LOAD_NYTCF', '2c1d95a62e5fxxxxx', 'Freebase NYTCF',
vector ());
};
]]></programlisting>
<para>Looking at the list of cartridges in Conductor's 'RDF Cartridges' screen, you will
see that the Freebase cartridge is configured by default to sponge URIs which match the pattern
"http://www.freebase.com/view/.*" The meta-cartridge is configured to match on the same URI pattern.</para>
<para>To use the Campaign Finance API, you must register and request an API key. The script
above shows an invalid key. Replace it with your own key before executing the procedure.</para>
<para><emphasis>NYTCF Meta-Cartridge Functions</emphasis></para>
<para>The meta-cartridge function definitions are listed below. They can be executed by
pasting them into Conductor's iSQL interface.</para>
<programlisting><![CDATA[
-- New York Times: Campaign Finance Web Service
-- See http://developer.nytimes.com/docs/campaign_finance_api
-- DB.DBA.RDF_NYTCF_LOOKUP is in effect a lightweight lookup cartridge that is used
-- to conditionally add triples to graphs generated by the Wikipedia and
-- Freebase cartridges. These cartridges call on RDF_NYTCF_LOOKUP when
-- handling an entity of rdf:type yago:Congressman109955781. The NYTCF lookup
-- cartridge (aka a metacartridge) is used to return campaign finance data
-- for the candidate in question retrieved from the New York Times Campaign
-- Finance web service.
create procedure DB.DBA.RDF_NYTCF_LOOKUP(
in candidate_id any, -- id of candidate
in graph_iri varchar, -- graph into which the additional campaign finance triples should be loaded
in api_key varchar -- NYT finance API key
)
{
declare version, campaign_type, year any;
declare nyt_url, hdr, tmp any;
declare xt, xd any;
-- Common parameters - The NYT API only supports the following values at present:
version := 'v2';
campaign_type := 'president';
year := '2008';
-- Candidate summaries
-- nyt_url := sprintf('http://api.nytimes.com/svc/elections/us/%s/%s/%s/finances/totals.xml?api-key=%s',
-- version, campaign_type, year, api_key);
-- Candidate details
nyt_url := sprintf('http://api.nytimes.com/svc/elections/us/%s/%s/%s/finances/candidates/%s.xml?api-key=%s',
version, campaign_type, year, candidate_id, api_key);
tmp := http_client_ext (nyt_url, headers=>hdr, proxy=>connection_get ('sparql-get:proxy'));
if (hdr[0] not like 'HTTP/1._ 200 %')
signal ('22023', trim(hdr[0], '\r\n'), 'DB.DBA.RDF_LOAD_NYTCF_LOOKUP');
xd := xtree_doc (tmp);
-- baseUri specifies what the generated RDF description is about
-- <rdf:Description rdf:about="{baseUri}">
-- Example baseUri's:
-- http://localhost:8890/about/rdf/http://www.freebase.com/view/en/barack_obama#this
-- http://localhost:8890/about/rdf/http://www.freebase.com/view/en/hillary_rodham_clinton#this
declare path any;
declare lang, k, base_uri varchar;
if (graph_iri like 'http://rdf.freebase.com/ns/%.%')
base_uri := graph_iri;
else
{
path := split_and_decode (graph_iri, 0, '%\0/');
k := path [length(path) - 1];
lang := path [length(path) - 2];
base_uri := sprintf ('http://rdf.freebase.com/ns/%U.%U', lang, k);
}
xt := DB.DBA.RDF_MAPPER_XSLT (registry_get ('_rdf_mappers_path_') || 'xslt/nytcf2rdf.xsl', xd,
vector ('baseUri', base_uri));
xd := serialize_to_UTF8_xml (xt);
DB.DBA.RDF_LOAD_RDFXML (xd, '', graph_iri);
}
;
create procedure DB.DBA.RDF_MQL_RESOURCE_IS_SENATOR (
in fb_graph_uri varchar -- URI of graph containing Freebase resource
)
{
-- Check if the resource described by Freebase is a U.S. senator. Only then does it make sense to query for campaign finance
-- data from the NYT data space.
--
-- To test for senators, we start by looking for two statements in the Freebase cartridge output, similar to:
--
-- <rdf:Description rdf:about="http://localhost:8890/about/rdf/http://www.freebase.com/view/en/hillary_rodham_clinton#this">
-- <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
-- <rdfs:seeAlso rdf:resource="http://en.wikipedia.org/wiki/Hillary_Rodham_Clinton"/>
-- ...
-- where the graph generated by the Sponger will be <http://www.freebase.com/view/en/hillary_rodham_clinton>
--
-- To test whether a resource is a senator:
-- 1) Check whether the Freebase resource is of rdf:type foaf:Person
-- 2) Extract the person_name from the Wikipedia URI referenced by rdfs:seeAlso
-- 3) Use the extracted person_name to build a URI to DBpedia's description of the person.
-- 4) Query the DBpedia description to see if the person is of rdf:type yago:Senator110578471
declare xp, xt, tmp any;
declare qry varchar; -- SPARQL query
declare qry_uri varchar; -- query URI
declare qry_res varchar; -- query result
declare dbp_resource_name varchar; -- Equivalent resource name in DBpedia
declare fb_resource_uri varchar; -- Freebase resource URI
declare path any;
declare lang, k varchar;
declare exit handler for sqlstate '*' {
return 0;
};
if (fb_graph_uri like 'http://rdf.freebase.com/ns/%.%')
fb_resource_uri := fb_graph_uri;
else
{
path := split_and_decode (fb_graph_uri, 0, '%\0/');
if (length (path) < 2)
return 0;
k := path [length(path) - 1];
lang := path [length(path) - 2];
fb_resource_uri := sprintf ('http://rdf.freebase.com/ns/%U.%U', lang, k);
}
-- 1) Check whether the Freebase resource is a politician from united_states
{
declare stat, msg varchar;
declare mdata, rset any;
qry := sprintf ('sparql ask from <%s> where { <%s> <http://rdf.freebase.com/ns/people.person.profession> <http://rdf.freebase.com/ns/en.politician> ; <http://rdf.freebase.com/ns/people.person.nationality> <http://rdf.freebase.com/ns/en.united_states> . }', fb_graph_uri, fb_resource_uri);
exec (qry, stat, msg, vector(), 1, mdata, rset);
if (length(rset) = 0 or rset[0][0] <> 1)
return 0;
}
return 1;
}
;
create procedure DB.DBA.RDF_LOAD_NYTCF_META (in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout _ret_body any, inout aq any, inout ps any, inout _key any, inout opts any)
{
declare candidate_id, candidate_name any;
declare api_key any;
declare indx, tmp any;
declare ord int;
declare exit handler for sqlstate '*'
{
return 0;
};
if (not DB.DBA.RDF_MQL_RESOURCE_IS_SENATOR (new_origin_uri))
return 0;
-- TO DO: hardcoded for now
-- Need a mechanism to specify API key for meta-cartridges
-- Could retrieve from virtuoso.ini?
api_key := _key;
-- NYT API supports a candidate_id in one of two forms:
-- candidate_id ::= {candidate_ID} | {last_name [,first_name]}
-- first_name is optional. If included, there should be no space after the comma.
--
-- However, because this meta cartridge supplies additional triples for the
-- Wikipedia or Freebase cartridges, only the second form of candidate_id is
-- supported. i.e. We extract the candidate name, rather than a numeric
-- candidate_ID (FEC committee ID) from the Wikipedia or Freebase URL.
--
-- It's assumed that the source URI includes the candidate's first name.
-- If it is omitted, the NYT API will return information about *all* candidates
-- with that last name - something we don't want.
indx := strstr(graph_iri, 'www.freebase.com/view/en/');
if (indx is not null)
{
-- extract candidate_id from Freebase URI
tmp := sprintf_inverse(subseq(graph_iri, indx), 'www.freebase.com/view/en/%s', 0);
if (length(tmp) <> 1)
return 0;
candidate_name := tmp[0];
}
else
{
indx := strstr(graph_iri, 'wikipedia.org/wiki/');
if (indx is not null)
{
-- extract candidate_id from Wikipedia URI
tmp := sprintf_inverse(subseq(graph_iri, indx), 'wikipedia.org/%s', 0);
if (length(tmp) <> 1)
return 0;
candidate_name := tmp[0];
}
else
{
tmp := sprintf_inverse(graph_iri, 'http://%s.freebase.com/ns/%s/%s', 0);
if (length (tmp) <> 3)
tmp := sprintf_inverse(graph_iri, 'http://%s.freebase.com/ns/%s.%s', 0);
if (length (tmp) <> 3)
return 0;
candidate_name := tmp[2];
}
}
-- split candidate_name into its component parts
-- candidate_name is assumed to be firstname_[middlename_]*lastname
-- e.g. hillary_rodham_clinton (Freebase), Hillary_clinton (Wikipedia)
{
declare i, _end, len int;
declare names, tmp_name varchar;
names := vector ();
tmp_name := candidate_name;
len := length (tmp_name);
while (1)
{
_end := strchr(tmp_name, '_');
if (_end is not null)
{
names := vector_concat (names, vector(subseq(tmp_name, 0, _end)));
tmp_name := subseq(tmp_name, _end + 1);
}
else
{
names := vector_concat(names, vector(tmp_name));
goto done;
}
}
done:
if (length(names) < 2)
return 0;
-- candidate_id ::= lastname,firstname
candidate_id := sprintf('%s,%s', names[length(names)-1], names[0]);
}
DB.DBA.RDF_NYTCF_LOOKUP(candidate_id, coalesce (dest, graph_iri), api_key);
return 0;
}
;
]]></programlisting>
<para><emphasis>NYTCF Meta-Cartridge Stylesheet</emphasis></para>
<para>The XSLT stylesheet, nyctf2rdf.xsl, used by the meta-cartridge to transform the base
Campaign Finance web service output to RDF is shown below. RDF_NYCTF_LOOKUP() assumes the stylesheet
is located alongside the other stylesheets provided by the rdf_mappers VAD in the Virtuoso WebDAV
folder DAV/VAD/rdf_mappers/xslt. You should create nyctf2rdf.xsl here from the following listing.
The WebDAV Browser interface in Conductor provides the easiest means to upload the stylesheet.</para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<!ENTITY nyt "http://www.nytimes.com/">
]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vi="http://www.openlinksw.com/virtuoso/xslt/"
xmlns:rdf=""
xmlns:nyt=""
>
<xsl:output method="xml" indent="yes" />
<xsl:template match="/result_set/status">
<xsl:if test="text() = 'OK'">
<xsl:apply-templates mode="ok" select="/result_set/results/candidate"/>
</xsl:if>
</xsl:template>
<xsl:template match="candidate" mode="ok">
<rdf:Description rdf:about="{vi:proxyIRI($baseUri)}">
<nyt:candidate_name><xsl:value-of select="candidate_name"/></nyt:candidate_name>
<nyt:committee_id><xsl:value-of select="committee_id"/></nyt:committee_id>
<nyt:party><xsl:value-of select="party"/></nyt:party>
<nyt:total_receipts><xsl:value-of select="total_receipts"/></nyt:total_receipts>
<nyt:total_disbursements>
<xsl:value-of select="total_disbursements"/>
</nyt:total_disbursements>
<nyt:cash_on_hand><xsl:value-of select="cash_on_hand"/></nyt:cash_on_hand>
<nyt:net_individual_contributions>
<xsl:value-of select="net_individual_contributions"/>
</nyt:net_individual_contributions>
<nyt:net_party_contributions>
<xsl:value-of select="net_party_contributions"/>
</nyt:net_party_contributions>
<nyt:net_pac_contributions>
<xsl:value-of select="net_pac_contributions"/>
</nyt:net_pac_contributions>
<nyt:net_candidate_contributions>
<xsl:value-of select="net_candidate_contributions"/>
</nyt:net_candidate_contributions>
<nyt:federal_funds><xsl:value-of select="federal_funds"/></nyt:federal_funds>
<nyt:total_contributions_less_than_200>
<xsl:value-of select="total_contributions_less_than_200"/>
</nyt:total_contributions_less_than_200>
<nyt:total_contributions_2300>
<xsl:value-of select="total_contributions_2300"/>
</nyt:total_contributions_2300>
<nyt:net_primary_contributions>
<xsl:value-of select="net_primary_contributions"/>
</nyt:net_primary_contributions>
<nyt:net_general_contributions>
<xsl:value-of select="net_general_contributions"/>
</nyt:net_general_contributions>
<nyt:total_refunds><xsl:value-of select="total_refunds"/></nyt:total_refunds>
<nyt:date_coverage_from rdf:datatype="date">
<xsl:value-of select="date_coverage_from"/>
</nyt:date_coverage_from>
<nyt:date_coverage_to rdf:datatype="date">
<xsl:value-of select="date_coverage_to"/>
</nyt:date_coverage_to>
</rdf:Description>
</xsl:template>
<xsl:template match="text()|@*"/>
</xsl:stylesheet>
]]></programlisting>
<para>The stylesheet uses the prefix nyt: (http://www.nytimes.com) for the predicates of
the augmenting triples. This has been used purely for illustration - you may prefer to define your
own ontology for RDF data derived from New York Times APIs.</para>
<para><emphasis>Testing the Meta-Cartridge</emphasis></para>
<para>After creating the required Virtuoso/PL functions and installing the stylesheet, you
should be able to test the meta-cartridge by sponging a Freebase page as described earlier using
ODE or the command line. For instance:</para>
<itemizedlist mark="bullet">
<listitem>http://www.freebase.com/view/en/barack_obama , or </listitem>
<listitem>http://www.freebase.com/view/en/hillary_rodham_clinton</listitem>
</itemizedlist>
<para>You should see campaign finance data added to the graph created by the Sponger in the form of triples with predicates starting http://www.nytimes.com/xxx, e.g. http://www.nytimes.com/net_primary_contribution.</para>
<para><emphasis>How The Meta-Cartridge Works</emphasis></para>
<para>The comments in the meta-cartridge code detail how the cartridge works. In brief:</para>
<para>Given the URI of the graph being created by the Freebase cartridge,
RDF_MQL_RESOURCE_IS_SENATOR checks if the resource described by Freebase is a U.S. senator.
Only then does it make sense to query for campaign finance data from the NYTCF data space.</para>
<para>To test for senators, the procedure starts by looking for two statements in the Freebase cartridge output similar to:</para>
<programlisting><![CDATA[
<rdf:Description rdf:about="http://localhost:8890/about/rdf/http://www.freebase.com/view/en/barack_obama#this">
<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
<rdfs:seeAlso rdf:resource="http://en.wikipedia.org/wiki/Barack_Obama"/>
...
]]></programlisting>
<para>where the graph generated by the Sponger will be</para>
<programlisting><![CDATA[
<http://www.freebase.com/view/en/barack_obama>
]]></programlisting>
<para>To test whether a resource is a senator, RDF_MQL_RESOURCE_IS_SENATOR</para>
<itemizedlist mark="bullet">
<listitem>Checks whether the Freebase resource is of rdf:type foaf:Person</listitem>
<listitem>Extracts the person's name from the Wikipedia URI referenced by rdfs:seeAlso</listitem>
<listitem>Uses the extracted name to build a URI to DBpedia's description of the person. </listitem>
<listitem>Queries the DBpedia description to see if the person is of rdf:type yago:Senator110578471 (
<ulink url="http://www.mpi-inf.mpg.de/~suchanek/downloads/yago/">YAGO</ulink> is a semantic knowledge base which provides a core set of concepts which in turn are used by DBpedia.)</listitem>
</itemizedlist>
<para>Only if this is the case is the RDF_NYTCF_LOOKUP routine called to query for and return campaign finance data for the candidate. The form of the query and the resulting XML output from the Campaign Finance service were presented earlier.</para>
</sect4>
</sect3>
<sect3 id="virtuosospongerelatedfunc">
<title>Virtuoso functions usage examples</title>
<sect4 id="virtuosospongerelatedfuncstring">
<title>String Functions</title>
<para><emphasis><link linkend="fn_sprintf_inverse">sprintf_inverse</link></emphasis></para>
<programlisting><![CDATA[
tmp := sprintf_inverse (new_origin_uri, 'http://farm%s.static.flickr.com/%s/%s_%s.%s', 0);
img_id := tmp[2];
]]></programlisting>
<para><emphasis><link linkend="fn_split_and_decode">split_and_decode</link></emphasis></para>
<programlisting><![CDATA[
request_hdr := headers[0];
response_hdr := headers[1];
host := http_request_header (request, 'Host');
tmp := split_and_decode (request_hdr[0], 0, '\0\0 ');
http_method := tmp[0];
url := tmp[1];
protocol_version := substring (tmp[2], 6, 8);
tmp := rtrim (response_hdr[0], '\r\n');
tmp := split_and_decode (response_hdr[0], 0, '\0\0 ');
]]></programlisting>
</sect4>
<sect4 id="virtuosospongerelatedfuncrurl">
<title>Retrieving URLs</title>
<para><emphasis><link linkend="fn_http_get">http_get</link></emphasis></para>
<programlisting><![CDATA[
url := sprintf('http://api.flickr.com/services/rest/?i"??
method=flickr.photos.getInfo&photo_id=%s&api_key=%s', img_id, api_key);
tmp := http_get (url, hdr);
if (hdr[0] not like 'HTTP/1._ 200 %')
signal ('22023', trim(hdr[0], '\r\n'), 'RDFXX');
xd := xtree_doc (tmp);
]]></programlisting>
<para><emphasis>DB.DBA.RDF_HTTP_URL_GET</emphasis></para>
<para>A wrapper around http_get. Retrieves a URL using the specified HTTP method
(defaults to GET). The function can handle proxies, redirects (up to fifteen) and HTTPS.</para>
<programlisting><![CDATA[
uri := sprintf ('http://musicbrainz.org/ws/1/%s/%s?type=xml&inc=%U',
kind, id, inc);
cnt := RDF_HTTP_URL_GET (uri, '', hdr, 'GET', 'Accept: */*');
xt := xtree_doc (cnt);
xd := DB.DBA.RDF_MAPPER_XSLT (registry_get ('_rdf_mappers_path_') || 'xslt/mbz2rdf.xsl', xt, vector ('baseUri', new_origin_uri));
]]></programlisting>
<para><emphasis><link linkend="fn_http_request_header">http_request_header</link></emphasis></para>
<programlisting><![CDATA[
content := RDF_HTTP_URL_GET (rdf_url, new_origin_uri, hdr, 'GET',
'Accept: application/rdf+xml, text/rdf+n3, */*');
ret_content_type := http_request_header (hdr, 'Content-Type', null, null);
]]></programlisting>
</sect4>
<sect4 id="virtuosospongerelatedfunchnxml">
<title>Handling Non-XML Response Content</title>
<para><emphasis>json_parse</emphasis>: Parses JSON content into a tree.</para>
<programlisting><![CDATA[
url := sprintf ('http://www.freebase.com/api/service/mqlread?queries=%U', qr);
content := http_get (url, hdr);
tree := json_parse (content);
tree := get_keyword ('ROOT', tree);
tree := get_keyword ('result', tree);
]]></programlisting>
</sect4>
<sect4 id="virtuosospongerelatedfuncwrarb">
<title>Writing Arbitrarily Long Text</title>
<para><emphasis><link linkend="fn_http">http</link></emphasis></para>
<programlisting><![CDATA[
-- Writing N3 to a string output stream using function http(), parsing the N3 into a graph, then loading the graph into the quad store.
ses := string_output ();
http ('@prefix opl: <http://www.openlinksw.com/schema/attribution#> .\n', ses);
http ('@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n', ses);
...
DB.DBA.TTLP (ses, base, graph);
DB.DBA.RDF_LOAD_RDFXML (strg, base, graph);
]]></programlisting>
<para><emphasis><link linkend="fn_string_output">string_output</link></emphasis></para>
<programlisting><![CDATA[
ses := string_output ();
cnt := http_get (sprintf ('http://download.finance.yahoo.com/d/quotes.csv?s=%U&f=nsbavophg&e=.csv',
symbol));
arr := rdfm_yq_parse_csv (cnt);
http ('<quote stock="NASDAQ">', ses);
foreach (any q in arr) do
{
http_value (q[0], 'company', ses);
http_value (q[1], 'symbol', ses);
...
}
http ('</quote>', ses);
content := string_output_string (ses);
xt := xtree_doc (content);
]]></programlisting>
<para><emphasis><link linkend="fn_string_output_string">string_output_string</link></emphasis></para>
</sect4>
<sect4 id="virtuosospongerelatedfuncxmlxslt">
<title>XML & XSLT</title>
<para><emphasis><link linkend="fn_xtree_doc">xtree_doc</link></emphasis></para>
<programlisting><![CDATA[
content := RDF_HTTP_URL_GET (uri, '', hdr, 'GET', 'Accept: */*');
xt := xtree_doc (content);
]]></programlisting>
<para><emphasis><link linkend="fn_xpath_eval">xpath_eval</link></emphasis></para>
<programlisting><![CDATA[
profile := cast (xpath_eval ('/html/head/@profile', xt) as varchar);
]]></programlisting>
<para><emphasis><link linkend="fn_xslt">DB.DBA.RDF_MAPPER_XSLT</link></emphasis></para>
<programlisting><![CDATA[
tmp := http_get (url);
xd := xtree_doc (tmp);
xt := DB.DBA.RDF_MAPPER_XSLT (
registry_get ('_rdf_mappers_path_') || 'xslt/atom2rdf.xsl',
xd, vector ('baseUri', coalesce (dest, graph_iri)));
]]></programlisting>
</sect4>
<sect4 id="virtuosospongerelatedfunccharserconv">
<title>Character Set Conversion</title>
<para><emphasis><link linkend="fn_serialize_to_UTF8_xml">serialize_to_UTF8_xml</link></emphasis></para>
<programlisting><![CDATA[
xt := DB.DBA.RDF_MAPPER_XSLT (
registry_get ('_rdf_mappers_path_') || 'xslt/crunchbase2rdf.xsl',
xt, vector ('baseUri', coalesce (dest, graph_iri), 'base', base,
'suffix', suffix));
xd := serialize_to_UTF8_xml (xt);
DB.DBA.RM_RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
]]></programlisting>
</sect4>
<sect4 id="virtuosospongerelatedfuncloaddata">
<title>Loading Data Into the Quad Store</title>
<para><emphasis><link linkend="fn_rdf_load_rdfxml">DB.DBA.RDF_LOAD_RDFXML</link></emphasis></para>
<programlisting><![CDATA[
content := RDF_HTTP_URL_GET (uri, '', hdr, 'GET', 'Accept: */*');
xt := xtree_doc (content);
xd := DB.DBA.RDF_MAPPER_XSLT (
registry_get ('_rdf_mappers_path_') || 'xslt/mbz2rdf.xsl',
xt, vector ('baseUri', new_origin_uri));
xd := serialize_to_UTF8_xml (xd);
DB.DBA.RM_RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
]]></programlisting>
<para><emphasis><link linkend="fn_ttlp">DB.DBA.TTLP</link></emphasis></para>
<programlisting><![CDATA[
sess := string_output ();
...
http (sprintf ('<http://dbpedia.org/resource/%s>
<http://xbrlontology.com/ontology/finance/stock_market#hasCompetitor>
<http://dbpedia.org/resource/%s> .\n',
symbol, x), sess);
http (sprintf ('<http://dbpedia.org/resource/%s>
<http://www.w3.org/2000/01/rdf-schema#isDefinedBy>
<http://finance.yahoo.com/q?s=%s> .\n',
x, x), sess);
content := string_output_string (sess);
DB.DBA.TTLP (content, new_origin_uri, coalesce (dest, graph_iri));
]]></programlisting>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfinsertmethodsapifunct">Loading RDF using API functions</link></listitem>
</itemizedlist>
</tip>
</sect4>
<sect4 id="virtuosospongerelatedfuncdebugpoutput">
<title>Debug Output</title>
<para><emphasis><link linkend="fn_dbg_obj_print">dbg_obj_print</link></emphasis></para>
<programlisting><![CDATA[
dbg_obj_print ('try all grddl mappings here');
]]></programlisting>
</sect4>
</sect3>
<sect3 id="virtuosospongeref">
<title>References</title>
<itemizedlist mark="bullet">
<listitem>RDF Primer: http://www.w3.org/TR/2004/REC-rdf-primer-20040210/</listitem>
<listitem>RDF/XML Syntax Specification: http://www.w3.org/TR/rdf-syntax-grammar/</listitem>
<listitem>GRDDL Primer: http://www.w3.org/TR/grddl-primer/</listitem>
</itemizedlist>
<sect4 id="virtuosospongerefping">
<title>PingTheSemanticWeb RDF Notification Service</title>
<para><ulink url="http://www.pingthesemanticweb.com/">PingtheSemanticWeb</ulink> (PTSW) is a repository for RDF documents. The PTSW web service
archives the location of recently created or updated RDF documents on the Web. It is intended
for use by crawlers or other types of software agents which need to know when and where the
latest updated RDF documents can be found. They can request a list of recently updated documents
as a starting location to crawl the Semantic Web.</para>
<para>You may find this service useful for publicizing your own RDF content. Content authors can
notify PTSW that an RDF document has been created or updated by pinging the service with the URL of
the document. The Sponger supports this facility through the async_queue and ping_service parameters
of the cartridge hook function, where the ping_service parameter contains the ping service URL as
configured in the SPARQL section of the virtuoso.ini file:</para>
<programlisting><![CDATA[
[SPARQL]
...
PingService = http://rpc.pingthesemanticweb.com/
...
]]></programlisting>
<para>The configured ping service can be called using an asynchronous request and
the RDF_SW_PING procedure as illustrated below. </para>
<programlisting><![CDATA[
create procedure DB.DBA.RDF_LOAD_HTML_RESPONSE (
in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout ret_body any, inout async_queue any, inout ping_service any,
inout _key any, inout opts any )
{
...
if ( ... and async_queue is not null)
aq_request (async_queue, 'DB.DBA.RDF_SW_PING',
vector (ping_service, new_origin_uri));
]]></programlisting>
<para>For more details refer to section <link linkend="ASYNCEXECMULTITHREAD">Asynchronous Execution and Multithreading in Virtuoso/PL</link></para>
</sect4>
<sect4 id="virtuosospongeremname">
<title>Main Namespaces used by OpenLink Cartridges</title>
<para>A list of the main namespaces / ontologies used by OpenLink-provided Sponger cartridges
is given below. Some of these ontologies may prove useful when creating your own cartridges.</para>
<itemizedlist mark="bullet">
<listitem>- http://www.openlinksw.com/virtuoso/xslt/</listitem>
<listitem>- http://www.openlinksw.com/schemas/XHTML# </listitem>
<listitem>rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns# </listitem>
<listitem>rdfs: http://www.w3.org/2000/01/rdf-schema# </listitem>
<listitem>dc: http://purl.org/dc/elements/1.1/</listitem>
<listitem>dcterms: http://purl.org/dc/terms/</listitem>
<listitem>foaf: http://xmlns.com/foaf/0.1/</listitem>
<listitem>sioc: http://rdfs.org/sioc/ns# </listitem>
<listitem>sioct: http://rdfs.org/sioc/types# </listitem>
<listitem>skos: http://www.w3.org/2004/02/skos/core# </listitem>
<listitem>bibo: http://purl.org/ontology/bibo/</listitem>
</itemizedlist>
</sect4>
<sect4 id="virtuosospongerfreeb">
<title>Freebase Cartridge & Stylesheet</title>
<para>Snapshots of the Freebase cartridge and stylesheet compatible with the meta-cartridge
example presented earlier in this document can be found below.</para>
<para><emphasis>DB.DBA.RDF_LOAD_MQL:</emphasis></para>
<programlisting><![CDATA[
--no_c_escapes-
create procedure DB.DBA.RDF_LOAD_MQL (in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout _ret_body any, inout aq any, inout ps any, inout _key any, inout opts any)
{
declare qr, path, hdr any;
declare tree, xt, xd, types any;
declare k, cnt, url, sa varchar;
hdr := null;
sa := '';
declare exit handler for sqlstate '*'
{
--dbg_printf ('%s', __SQL_MESSAGE);
return 0;
};
path := split_and_decode (new_origin_uri, 0, '%\0/');
if (length (path) < 1)
return 0;
k := path [length(path) - 1];
if (path [length(path) - 2] = 'guid')
k := sprintf ('"id":"/guid/%s"', k);
else
{
if (k like '#%')
k := sprintf ('"id":"%s"', k);
else
{
sa := DB.DBA.RDF_MQL_GET_WIKI_URI (k);
k := sprintf ('"key":"%s"', k);
}
}
qr := sprintf ('{"ROOT":{"query":[{%s, "type":[]}]}}', k);
url := sprintf ('http://www.freebase.com/api/service/mqlread?queries=%U', qr);
cnt := http_get (url, hdr);
tree := json_parse (cnt);
xt := get_keyword ('ROOT', tree);
if (not isarray (xt))
return 0;
xt := get_keyword ('result', xt);
types := vector ();
foreach (any tp in xt) do
{
declare tmp any;
tmp := get_keyword ('type', tp);
types := vector_concat (types, tmp);
}
--types := get_keyword ('type', xt);
DELETE FROM DB.DBA.RDF_QUAD WHERE g = iri_to_id(new_origin_uri);
foreach (any tp in types) do
{
qr := sprintf ('{"ROOT":{"query":{%s, "type":"%s", "*":[]}}}', k, tp);
url := sprintf ('http://www.freebase.com/api/service/mqlread?queries=%U', qr);
cnt := http_get (url, hdr);
--dbg_printf ('%s', cnt);
tree := json_parse (cnt);
xt := get_keyword ('ROOT', tree);
xt := DB.DBA.MQL_TREE_TO_XML (tree);
--dbg_obj_print (xt);
xt := DB.DBA.RDF_MAPPER_XSLT (registry_get ('_rdf_mappers_path_') || 'xslt/mql2rdf.xsl', xt,
vector ('baseUri', coalesce (dest, graph_iri), 'wpUri', sa));
sa := '';
xd := serialize_to_UTF8_xml (xt);
-- dbg_printf ('%s', xd);
DB.DBA.RM_RDF_LOAD_RDFXML (xd, new_origin_uri, coalesce (dest, graph_iri));
}
return 1;
}
]]></programlisting>
<para><emphasis>mql2rdf.xsl:</emphasis></para>
<programlisting><![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- $Id: rdfandsparql.xml,v 1.95.2.36 2010/07/08 15:18:23 source Exp $
-
- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
- project.
-
- Copyright (C) 1998-2008 OpenLink Software
-
- This project is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; only version 2 of the License, dated June 1991.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-->
<!DOCTYPE xsl:stylesheet [
<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<!ENTITY bibo "http://purl.org/ontology/bibo/">
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#">
<!ENTITY foaf "http://xmlns.com/foaf/0.1/">
<!ENTITY sioc "http://rdfs.org/sioc/ns#">
]>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vi="http://www.openlinksw.com/virtuoso/xslt/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:sioc=""
xmlns:bibo=""
xmlns:foaf=""
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:dcterms= "http://purl.org/dc/terms/"
xmlns:mql="http://www.freebase.com/">
<xsl:output method="xml" indent="yes" />
<xsl:param name="baseUri" />
<xsl:param name="wpUri" />
<xsl:variable name="ns">http://www.freebase.com/</xsl:variable>
<xsl:template match="/">
<rdf:RDF>
<xsl:if test="/results/ROOT/result/*">
<rdf:Description rdf:about="{$baseUri}">
<rdf:type rdf:resource="Document"/>
<rdf:type rdf:resource="Document"/>
<rdf:type rdf:resource="Container"/>
<sioc:container_of rdf:resource="{vi:proxyIRI($baseUri)}"/>
<foaf:primaryTopic rdf:resource="{vi:proxyIRI($baseUri)}"/>
<dcterms:subject rdf:resource="{vi:proxyIRI($baseUri)}"/>
</rdf:Description>
<rdf:Description rdf:about="{vi:proxyIRI($baseUri)}">
<rdf:type rdf:resource="Item"/>
<sioc:has_container rdf:resource="{$baseUri}"/>
<xsl:apply-templates select="/results/ROOT/result/*"/>
<xsl:if test="$wpUri != ''">
<rdfs:seeAlso rdf:resource="{$wpUri}"/>
</xsl:if>
</rdf:Description>
</xsl:if>
</rdf:RDF>
</xsl:template>
<xsl:template match="*[starts-with(.,'http://') or starts-with(.,'urn:')]">
<xsl:element namespace="{$ns}" name="{name()}">
<xsl:attribute name="rdf:resource">
<xsl:value-of select="vi:proxyIRI (.)"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="*[starts-with(.,'/')]">
<xsl:if test="local-name () = 'type' and . like '%/person'">
<rdf:type rdf:resource="Person"/>
</xsl:if>
<xsl:if test="local-name () = 'type'">
<sioc:topic>
<skos:Concept rdf:about="{vi:proxyIRI (concat ($ns, 'view', .))}"/>
</sioc:topic>
</xsl:if>
<xsl:element namespace="{$ns}" name="{name()}">
<xsl:attribute name="rdf:resource">
<xsl:value-of select="vi:proxyIRI(concat ($ns, 'view', .))"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template match="*[* and ../../*]">
<xsl:element namespace="{$ns}" name="{name()}">
<xsl:attribute name="rdf:parseType">Resource</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:if test="* or . != ''">
<xsl:choose>
<xsl:when test="name()='image'">
<foaf:depiction rdf:resource="{vi:mql-image-by-name (.)}"/>
</xsl:when>
<xsl:otherwise>
<xsl:element namespace="{$ns}" name="{name()}">
<xsl:if test="name() like 'date_%'">
<xsl:attribute name="rdf:datatype">dateTime</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
]]></programlisting>
</sect4>
</sect3>
<sect3 id="rdfspongerprogrammerguidepython"><title>Using Python to perform Virtuoso Sponging</title>
<para>This section contains the generic steps to use Python language to extend the Virtuoso Sponger.</para>
<orderedlist>
<listitem>Build the latest Python hosting module. It will introduce a new function <code>python_exec ()</code>
<para>The parameters of python_exec are :</para>
<itemizedlist mark="bullet">
<listitem>string containing a python code, it should define one or more functions, see remarks bellow</listitem>
<listitem>string containing name of function to be called</listitem>
<listitem>list of parameters for the function </listitem>
</itemizedlist>
<para>For Example:</para>
<programlisting><![CDATA[
python_exec (file_to_string ('spoonge.py'), 'rdf4uri', 'http://url..', 'http://base...');
]]></programlisting>
<para>The above means call the rdf4uri ('http://url..', 'http://base...') function from spoonge.py file.
It is importnat to know that python_exec is restricted to DBA only group and that the python source
should not have __main__ or this to be restricted in python code to not be called .
Any print etc. for stdout/stderr will go on server console if server is on foreground.
Can be used for debug for example but not for real work. </para>
<para>The function is supposed to return just single string, don't try to return multiple results,
this will not work in this revision.
</para>
</listitem>
<listitem>Setup the Virtuoso server INI to include python module:
<programlisting><![CDATA[
...
[Plugins]
LoadPath = ../lib
Load1 = Hosting, hosting_python.so
...
]]></programlisting>
</listitem>
<listitem>Download and install the rdflib package from http://www.rdflib.net/
Note before to build, disable Zope interface in rdflib as this not work with C-API correctly.
Or make sure Python has no Zope interfaces installed.
To disable the zope in rdflib, just comment out following in <rdflibhome>/rdflib/__init__.py:
<programlisting><![CDATA[
36 #from rdflib.interfaces import IIdentifier, classImplements
37 #classImplements(URIRef, IIdentifier)
38 #classImplements(BNode, IIdentifier)
39 #classImplements(Literal, IIdentifier)
]]></programlisting>
<para>Then do:</para>
<programlisting><![CDATA[
perl setup.py build
perl setup.py --user install
]]></programlisting>
</listitem>
<listitem>Get an example of python code for sponger like: http://www.ebusiness-unibw.org/wiki/Python4Spongers
and make sure you disable the last lines which not suitable for calling inside Sponger:
<programlisting><![CDATA[
...
#if __name__ == '__main__':
# rdf_xml = rdf4uri(uri='http://www.amazon.com/Apple-touch-Generation-NEWEST-MODEL/dp/B002M3SOBU/')
# print rdf_xml
]]></programlisting>
<para>Store the python code in sponge.py in server working directory.
Make sure this directory is allowed to read in DirsAllowed INI setting.</para>
</listitem>
<listitem>Create a procedure and register with Sponger:
<programlisting><![CDATA[
-- THIS IS FOR DEMO PURPOSE ONLY
-- for demo purposes we delete all other cartridges registrations to see effect from only this cartridge
delete from DB.DBA.SYS_RDF_MAPPERS;
delete from DB.DBA.RDF_META_CARTRIDGES;
-- register cartridge
insert soft DB.DBA.SYS_RDF_MAPPERS (RM_PATTERN, RM_TYPE, RM_HOOK, RM_KEY, RM_DESCRIPTION)
values ('(http://.*amazon.[^/]+/[^/]+/dp/[^/]+(/.*)?)', 'URL', 'DB.DBA.RDF_LOAD_PYTHON_AMAZON_ARTICLE', null, 'Amazon articles');
-- the cartridge stored procedure itself
create procedure DB.DBA.RDF_LOAD_PYTHON_AMAZON_ARTICLE (in graph_iri varchar, in new_origin_uri varchar, in dest varchar,
inout _ret_body any, inout aq any, inout ps any, inout _key any, inout opts any)
{
declare result any;
-- we check first python hosting is capable to run code
if (__proc_exists ('python_exec', 2) is null)
return 0;
-- handle any error
declare exit handler for sqlstate '*'
{
-- log the error
DB.DBA.RM_RDF_SPONGE_ERROR (current_proc_name (), graph_iri, dest, __SQL_MESSAGE);
return 0;
};
-- call the python code
result := python_exec (file_to_string ('sponge.py'), 'rdf4uri', new_origin_uri);
-- in case of python error we will get integer zero, so we check
if (not isstring (result))
return 0;
-- for demo purpose we delete all from this graph
delete from DB.DBA.RDF_QUAD where G = DB.DBA.RDF_MAKE_IID_OF_QNAME (graph_iri);
-- load the results
DB.DBA.RDF_LOAD_RDFXML (result, new_origin_uri, coalesce (dest, graph_iri), 0);
return 1;
}
;
]]></programlisting>
</listitem>
<listitem>Test the Sponger code like this:
<programlisting><![CDATA[
sparql define get:soft "soft" select * from <http://www.amazon.com/Apple-touch-Generation-NEWEST-MODEL/dp/B002M3SOBU/> { ?s ?p ?o };
]]></programlisting>
</listitem>
</orderedlist>
</sect3>
</sect2>
</sect1>
<sect1 id="rdfiridereferencing"><title>Linked Data</title>
<para>There are many cases when RDF data should be retrieved from remote sources only when really needed.
E.g., a scheduling application may read personal calendars from personal sites of its users.
Calendar data expire quickly, so there's no reason to frequently re-load them in hope that they are queried before expired.
</para>
<para>Virtuoso extends SPARQL so it is possible to download RDF resource from a given IRI, parse them and store the resulting triples in a graph, all three operations will be performed during the SPARQL query execution.
The IRI of graph to store triples is usually equal to the IRI where the resource is download from, so the feature is named "IRI dereferencing"
There are two different use cases for this feature.
In simple case, a SPARQL query contains <emphasis>from</emphasis> clauses that enumerate graphs to process, but there are no triples in <emphasis>DB.DBA.RDF_QUAD</emphasis> that correspond to some of these graphs.
The query execution starts with dereferencing of these graphs and the rest runs as usual.
In more sophisticated case, the query is executed many times in a loop.
Every execution produces a partial result.
SPARQL processor checks for IRIs in the result such that resources with that IRIs may contain relevant data but not yet loaded into the <emphasis>DB.DBA.RDF_QUAD</emphasis>.
After some iteration, the partial result is identical to the result of the previous iteration, because there's no more data to retrieve.
As the last step, SPARQL processor builds the final result set.
</para>
<sect2 id="rdfinputgrab"><title>IRI Dereferencing For FROM Clauses, "define get:..." Pragmas</title>
<para>Virtuoso extends SPARQL syntax of <emphasis>from</emphasis> and <emphasis>from named</emphasis> clauses.
It allows additional list of options at end of clause: <emphasis>option ( param1 value1, param2 value2, ... )</emphasis>
where parameter names are QNames that start with <emphasis>get:</emphasis> prefix and values are "precode" expressions, i.e. expressions that does not contain variables other than external parameters.
Names of allowed parameters are listed below.
</para>
<itemizedlist>
<listitem><emphasis>get:soft</emphasis> is the retrieval mode, supported values are "soft" and "replacing".
If the value is "soft" then the SPARQL processor will not even try to retrieve triples if the destination graph is non-empty.
Other <emphasis>get:...</emphasis> parameters are useless without this one.</listitem>
<listitem><emphasis>get:uri</emphasis> is the IRI to retrieve if it is not equal to the IRI of the <emphasis>from</emphasis> clause.
These can be used if data should be retrieved from a mirror, not from original resource location or in any other case when the destination graph IRI differs from the location of the resource.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define get:uri "http://myopenlink.net/dataspace/person/kidehen"
SELECT ?id
FROM NAMED <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
WHERE { graph ?g { ?id a ?o } }
LIMIT 10;
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1231
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1231
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1243
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1243
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
10 Rows. -- 10 msec.
]]></programlisting>
<listitem><emphasis>get:method</emphasis> is the HTTP method that should be used to retrieve the resource, supported methods are "GET" for plain HTTP and "MGET" for URIQA web service endpoint.
By default, "MGET" is used for IRIs that end with "/" and "GET" for everything else.</listitem>
<listitem><emphasis>get:refresh</emphasis> is the maximum allowed age of the cached resource, no matter what is specified by the server where the resource resides.
The value is an positive integer (number of seconds). Virtuoso reads HTTP headers and uses "Date", "ETag", "Expires", "Last-Modified", "Cache-Control" and "Pragma: no-cache" fields to calculate when the resource should be reloaded, this value can become smaller due to <emphasis>get:refresh</emphasis> but can not be incremented.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define get:refresh "3600"
SELECT ?id
FROM NAMED <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
WHERE { graph ?g { ?id a ?o } }
LIMIT 10;
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1231
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1231
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1243
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1243
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
10 Rows. -- 10 msec.
]]></programlisting>
<listitem><emphasis>get:proxy</emphasis> address of the proxy server, as "host:port" string, if direct download is impossible; the default is to not use proxy.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define get:proxy "www.openlinksw.com:80"
define get:method "GET"
define get:soft "soft"
SELECT ?id
FROM NAMED <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
WHERE { graph ?g { ?id a ?o } }
LIMIT 10;
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1231
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1231
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1243
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1243
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1261
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com#this
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D
10 Rows. -- 10 msec.
SQL> limit 10;
]]></programlisting>
<!--
<listitem><emphasis>get:login</emphasis></listitem>
<listitem><emphasis>get:password</emphasis></listitem>
<listitem><emphasis>get:query</emphasis></listitem> -->
<para>If a value of some <emphasis>get:...</emphasis> parameter repeats for every <emphasis>from</emphasis> clause then it can be written as a global
pragma like <emphasis>define get:soft "soft"</emphasis>.
The following two queries will work identically:
</para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT ?id
FROM NAMED <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
OPTION (get:soft "soft", get:method "GET")
FROM NAMED <http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/sioc.ttl>
OPTION (get:soft "soft", get:method "GET")
WHERE { graph ?g { ?id a ?o } }
LIMIT 10;
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/person/oerling#this
http://www.openlinksw.com/mt-tb
http://www.openlinksw.com/RPC2
http://www.openlinksw.com/dataspace/oerling#this
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/958
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/958
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/949
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/949
10 Rows. -- 862 msec.
]]></programlisting>
<programlisting><![CDATA[
SQL>SPARQL
define get:method "GET"
define get:soft "soft"
SELECT ?id
FROM NAMED <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
FROM NAMED <http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/sioc.ttl>
WHERE { graph ?g { ?id a ?o } }
LIMIT 10;
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/dataspace/person/oerling#this
http://www.openlinksw.com/mt-tb
http://www.openlinksw.com/RPC2
http://www.openlinksw.com/dataspace/oerling#this
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/958
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/958
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/949
http://www.openlinksw.com/dataspace/oerling/weblog/Orri%20Erling%27s%20Blog/949
10 Rows. -- 10 msec.
]]></programlisting>
<para>
It can make text shorter and it is especially useful when the query text comes from client but the parameter should have a fixed value due to security reasons:
the values set by <emphasis>define get:...</emphasis> can not be redefined inside the query and the application may prevent the text with desired pragmas before the execution.
</para>
<para>
Note that the user should have <emphasis>SPARQL_UPDATE</emphasis> role in order to execute such a query.
By default SPARQL web service endpoint is owned by <emphasis>SPARQL</emphasis> user that have <emphasis>SPARQL_SELECT</emphasis> but not
<emphasis>SPARQL_UPDATE</emphasis>.
It is possible in principle to grant <emphasis>SPARQL_UPDATE</emphasis> to <emphasis>SPARQL</emphasis> but this breaches the whole security of the RDF storage.
</para>
<listitem><emphasis>FROM CLAUSE with options</emphasis>: options in OPTION() list should be delimited with commas.
grab options are not allowed as they are global for the query. Only specific 'get:xxx' options are useful here.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?friend
FROM NAMED <http://myopenlink.net/dataspace/person/kidehen>
OPTION (get:soft "soft", get:method "GET")
WHERE
{
<http://myopenlink.net/dataspace/person/kidehen#this> foaf:knows
?friend .
};
friend
VARCHAR
_______________________________________________________________________________
http://www.dajobe.org/foaf.rdf#i
http://www.w3.org/People/Berners-Lee/card#i
http://www.w3.org/People/Connolly/#me
http://my.opera.com/chaals/xml/foaf#me
http://www.w3.org/People/Berners-Lee/card#amy
http://www.w3.org/People/EM/contact#me
http://myopenlink.net/dataspace/person/ghard#this
http://myopenlink.net/dataspace/person/omfaluyi#this
http://myopenlink.net/dataspace/person/alanr#this
http://myopenlink.net/dataspace/person/bblfish#this
http://myopenlink.net/dataspace/person/danja#this
http://myopenlink.net/dataspace/person/tthibodeau#this
...
36 Rows. -- 1693 msec.
]]></programlisting>
</itemizedlist>
</sect2>
<sect2 id="rdfinputgrab"><title>IRI Dereferencing For Variables, "define input:grab-..." Pragmas</title>
<para>
Consider a set of personal data such that one resource can list many persons and point to resources where that persons are described in more details.
E.g. resource about <emphasis>user1</emphasis> describes the user and also contain statements that <emphasis>user2</emphasis> and <emphasis>user3</emphasis> are persons and more data can be found in <emphasis>user2.ttl</emphasis> and <emphasis>user3.ttl</emphasis>,
<emphasis>user3.ttl</emphasis> can contain statements that <emphasis>user4</emphasis> is also person and more data can be found in <emphasis>user4.ttl</emphasis> and so on.
The query should find as many users as it is possible and return their names and e-mails.
</para>
<para>
If all data about all users were loaded into the database, the query could be quite simple:
</para>
<programlisting><![CDATA[
SQL>SPARQL
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?id ?firstname ?nick
where
{
graph ?g
{
?id rdf:type foaf:Person.
?id foaf:firstName ?firstname.
?id foaf:knows ?fn .
?fn foaf:nick ?nick.
}
}
limit 10;
id firstname nick
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://myopenlink.net/dataspace/person/pmitchell#this LaRenda sdmonroe
http://myopenlink.net/dataspace/person/pmitchell#this LaRenda kidehen{at}openlinksw.com
http://myopenlink.net/dataspace/person/pmitchell#this LaRenda alexmidd
http://myopenlink.net/dataspace/person/abm#this Alan kidehen{at}openlinksw.com
http://myopenlink.net/dataspace/person/igods#this Cameron kidehen{at}openlinksw.com
http://myopenlink.net/dataspace/person/goern#this Christoph captsolo
http://myopenlink.net/dataspace/person/dangrig#this Dan rickbruner
http://myopenlink.net/dataspace/person/dangrig#this Dan sdmonroe
http://myopenlink.net/dataspace/person/dangrig#this Dan lszczepa
http://myopenlink.net/dataspace/person/dangrig#this Dan kidehen
10 Rows. -- 80 msec.
]]></programlisting>
<para>
It is possible to enable IRI dereferencing in such a way that all appropriate resources are loaded during the query execution even if names of some of them are not known a priori.
</para>
<programlisting><![CDATA[
SQL>SPARQL
define input:grab-var "?more"
define input:grab-depth 10
define input:grab-limit 100
define input:grab-base "http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300"
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
SELECT ?id ?firstname ?nick
WHERE {
graph ?g {
?id rdf:type foaf:Person.
?id foaf:firstName ?firstname.
?id foaf:knows ?fn .
?fn foaf:nick ?nick.
OPTIONAL { ?id rdfs:SeeAlso ?more }
}
}
LIMIT 10;
id firstname nick
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://myopenlink.net/dataspace/person/ghard#this Yrj+?n+? kidehen
http://inamidst.com/sbp/foaf#Sean Sean d8uv
http://myopenlink.net/dataspace/person/dangrig#this Dan rickbruner
http://myopenlink.net/dataspace/person/dangrig#this Dan sdmonroe
http://myopenlink.net/dataspace/person/dangrig#this Dan lszczepa
http://myopenlink.net/dataspace/person/dangrig#this Dan kidehen
http://captsolo.net/semweb/foaf-captsolo.rdf#Uldis_Bojars Uldis mortenf
http://captsolo.net/semweb/foaf-captsolo.rdf#Uldis_Bojars Uldis danja
http://captsolo.net/semweb/foaf-captsolo.rdf#Uldis_Bojars Uldis zool
http://myopenlink.net/dataspace/person/rickbruner#this Rick dangrig
10 Rows. -- 530 msec.
]]></programlisting>
<para>
The IRI dereferencing is controlled by the following pragmas:
</para>
<itemizedlist>
<listitem><emphasis>input:grab-var</emphasis> specifies a name of variable whose values should be used as IRIs of resources that should be downloaded.
It is not an error if the variable is sometimes unbound or gets values that can not be converted to IRIs (e.g., integers) -- bad values are silently ignored.
It is also not an error if the IRI can not be retrieved, this makes IRI retrieval somewhat similar to "best effort union" in SQL.
This pragma can be used more than once to specify many variable names.
It is not an error if values of different variables result in same IRI or a variable gets same value many times -- no one IRI is retrieved more than once.</listitem>
<listitem><emphasis>input:grab-iri</emphasis> specifies an IRI that should be retrieved before executing the rest of the query, if it is not in the <emphasis>DB.DBA.RDF_QUAD</emphasis> already.
This pragma can be used more than once to specify many IRIs.
The typical use of this pragma is querying a set of related resources when only one "root" resource IRI is known but even that resource is not loaded.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define input:storage ""
define input:grab-iri <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
define input:grab-var "id"
define input:grab-depth 10
define input:grab-limit 100
define input:grab-base "http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300"
SELECT ?id
WHERE { graph ?g { ?id a ?o } }
LIMIT 10;
id
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/virtrdf-data-formats#default-iid
http://www.openlinksw.com/virtrdf-data-formats#default-iid-nullable
http://www.openlinksw.com/virtrdf-data-formats#default-iid-nonblank
http://www.openlinksw.com/virtrdf-data-formats#default-iid-nonblank-nullable
http://www.openlinksw.com/virtrdf-data-formats#default
http://www.openlinksw.com/virtrdf-data-formats#default-nullable
http://www.openlinksw.com/virtrdf-data-formats#sql-varchar
http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-nullable
http://www.openlinksw.com/virtrdf-data-formats#sql-longvarchar
http://www.openlinksw.com/virtrdf-data-formats#sql-longvarchar-nullable
10 Rows. -- 530 msec.
]]></programlisting>
<listitem><emphasis>input:grab-all</emphasis> is the simplest possible way to enable the feature but the resulting performance can be very bad.
It turns all variables and IRI constants in all graph, subject and object fields of all triple patterns of the query into values for
<emphasis>input:grab-var</emphasis> and <emphasis>input:grab-iri</emphasis>,
so the SPARQL processor will dereference everything what might be related to the text of the query.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define input:grab-all "yes"
define input:grab-depth 10
define input:grab-limit 100
define input:grab-base "http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300"
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?id ?firstname ?nick
where
{
graph ?g
{
?id rdf:type foaf:Person.
?id foaf:firstName ?firstname.
?id foaf:knows ?fn .
?fn foaf:nick ?nick.
}
}
limit 10;
id firstname nick
VARCHAR VARCHAR VARCHAR
____________________________________________________________________
http://myopenlink.net/dataspace/person/pmitchell#this LaRenda sdmonroe
http://myopenlink.net/dataspace/person/pmitchell#this LaRenda kidehen{at}openlinksw.com
http://myopenlink.net/dataspace/person/pmitchell#this LaRenda alexmidd
http://myopenlink.net/dataspace/person/abm#this Alan kidehen{at}openlinksw.com
http://myopenlink.net/dataspace/person/igods#this Cameron kidehen{at}openlinksw.com
http://myopenlink.net/dataspace/person/goern#this Christoph captsolo
http://myopenlink.net/dataspace/person/dangrig#this Dan rickbruner
http://myopenlink.net/dataspace/person/dangrig#this Dan sdmonroe
http://myopenlink.net/dataspace/person/dangrig#this Dan lszczepa
http://myopenlink.net/dataspace/person/dangrig#this Dan kidehen
10 Rows. -- 660 msec.
]]></programlisting>
<listitem><emphasis>input:grab-seealso</emphasis> (and synonym <emphasis>input:grab-follow-predicate</emphasis>) specifies an IRI of an predicate similar to foaf:seeAlso.
Predicates of that sort suggest location of resources that contain more data about predicate subject.
The IRI dereferencing routine may use these predicates to find additional IRIs for loading resources.
This is especially useful when the text of the query comes from remote client and may lack triple patterns like
<emphasis><![CDATA[optional { ?id <SeeAlso> ?more }]]></emphasis> from the previous example.
The use of <emphasis>input:grab-seealso</emphasis> makes the SPARQL query nondeterministic, because the order and the number of retrieved documents will
depend on execution plan and they may change from run to run.
This pragma can be used more than once to specify many IRIs, but this feature is costly.
Every additional predicate may result in significant number of lookups in the RDF storage, affecting total execution time.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define input:grab-iri <http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/sioc.ttl>
define input:grab-var "id"
define input:grab-depth 10
define input:grab-limit 100
define input:grab-base "http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300"
define input:grab-seealso <foaf:maker>
prefix foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?id
where
{
graph ?g
{
?id a foaf:Person .
}
}
limit 10;
id
VARCHAR
_______________________________________________________________________________
mailto:somebody@example.domain
http://localhost:8895/dataspace/person/dav#this
http://localhost:8895/dataspace/person/dba#this
mailto:2@F.D
http://localhost:8895/dataspace/person/test1#this
http://www.openlinksw.com/blog/~kidehen/gems/rss.xml#Kingsley%20Uyi%20Idehen
http://art.weblogsinc.com/rss.xml#
http://digitalmusic.weblogsinc.com/rss.xml#
http://partners.userland.com/nytrss/books.xml#
http://partners.userland.com/nytrss/arts.xml#
10 Rows. -- 105 msec.
]]></programlisting>
<listitem><emphasis>input:grab-limit</emphasis> should be an integer that is a maximum allowed number of resource retrievals.
The default value is pretty big (few millions of documents) so it is strongly recommended to set smaller value.
Set it even if you're absolutely sure that the set of resources is small, because program errors are always possible.
All resource downloads are counted, both successful and failed, both forced by <emphasis>input:grab-iri</emphasis> and forced by <emphasis>input:grab-var</emphasis>.
Nevertheless, all constant IRIs specified by <emphasis>input:grab-iri</emphasis> (or <emphasis>input:grab-all</emphasis>) are downloaded before the first check of the <emphasis>input:grab-limit</emphasis> counter,
so this limit will never prevent from downloading "root" resources.
</listitem>
<listitem><emphasis>input:grab-depth</emphasis> should be an integer that is a maximum allowed number of query iterations.
Every iteration may find new IRIs to retrieve, because resources loaded on previous iteration may add these IRIs to <emphasis>DB.DBA.RDF_QUAD</emphasis> and make result set longer.
The default value is 1, so the SPARQL processor will retrieve only resources explicitly named in "root" resources or in quad that are in the database before the query execution.
</listitem>
<listitem><emphasis>input:grab-base</emphasis> specifies a base IRI used to convert relative IRIs into absolute. The default is an empty string.</listitem>
<programlisting><![CDATA[
SQL>SPARQL
define input:grab-depth 10
define input:grab-limit 100
define input:grab-var "more"
define input:grab-base "http://www.openlinksw.com/dataspace/kidehen@openlinksw.com/weblog/kidehen@openlinksw.com%27s%20BLOG%20%5B127%5D/1300"
prefix foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?id
where
{
graph ?g
{
?id a foaf:Person .
optional { ?id foaf:maker ?more }
}
}
limit 10;
id
VARCHAR
_______________________________________________________________________________
mailto:somebody@example.domain
http://localhost:8895/dataspace/person/dav#this
http://localhost:8895/dataspace/person/dba#this
mailto:2@F.D
http://localhost:8895/dataspace/person/test1#this
http://www.openlinksw.com/blog/~kidehen/gems/rss.xml#Kingsley%20Uyi%20Idehen
http://art.weblogsinc.com/rss.xml#
http://digitalmusic.weblogsinc.com/rss.xml#
http://partners.userland.com/nytrss/books.xml#
http://partners.userland.com/nytrss/arts.xml#
10 Rows. -- 115 msec.
]]></programlisting>
<listitem><emphasis>input:grab-resolver</emphasis> is a name of procedure that resolve IRIs and determines the HTTP method of retrieval.
The default is name of <emphasis>DB.DBA.RDF_GRAB_RESOLVER_DEFAULT()</emphasis> procedure that is described below.
If other procedure is specified, the signature should match to the default one.</listitem>
<listitem><emphasis>input:grab-destination</emphasis> is to override the default behaviour of the IRI dereferencing and store all retrieved triples in a single graph.
This is convenient when there's no logical difference where any given triple comes from, and changes in remote resources will only add triples but not make cached triples obsolete.
A SPARQL query is usually faster when all graph IRIs are fixed and there are no graph group patterns with an unbound graph variable, so storing everything in one single graph is worth considering.
</listitem>
<listitem><emphasis>input:grab-loader</emphasis> is a name of procedure that retrieve the resource via HTTP, parse it and store it.
The default is name of <emphasis>DB.DBA.RDF_SPONGE_UP()</emphasis> procedure; this procedure also used by IRI dereferencing for FROM clauses.
You will probably never need to write your own procedure of this sort but some Virtuoso plugins will provide ready-to-use functions that will retrieve non-RDF resources and extract their metadata as triples or
will implement protocols other than HTTP.
</listitem>
</itemizedlist>
<para>Default resolver procedure is <emphasis>DB.DBA.RDF_GRAB_RESOLVER_DEFAULT()</emphasis>. Note that the function produce two absolute URIs,
<emphasis>abs_uri</emphasis> and <emphasis>dest_uri</emphasis>. Default procedure returns two equal strings, but other may return different values,
e.g., return primary and permanent location of the resource as <emphasis>dest_uri</emphasis> and the fastest known mirror location as
<emphasis>abs_uri</emphasis> thus saving HTTP retrieval time. It can even signal an error to block the downloading of some unwanted resource.</para>
<programlisting><![CDATA[
DB.DBA.RDF_GRAB_RESOLVER_DEFAULT (
in base varchar, -- base IRI as specified by input:grab-base pragma
in rel_uri varchar, -- IRI of the resource as it is specified by input:grab-iri or a value of a variable
out abs_uri varchar, -- the absolute IRI that should be downloaded
out dest_uri varchar, -- the graph IRI where triples should be stored after download
out get_method varchar ) -- the HTTP method to use, should be "GET" or "MGET".
]]></programlisting>
</sect2>
<sect2 id="urlrewriting"><title>URL rewriting</title>
<para>URL rewriting is the act of modifying a source URL prior to the final processing of that URL by a
Web Server.</para>
<para>The ability to rewrite URLs may be desirable for many reasons that include:</para>
<itemizedlist>
<listitem>Changing Web information resource URLs on the a Web Server without breaking existing bookmarks
held in User Agents (e.g., Web browsers)</listitem>
<listitem>URL compaction where shorter URLs may be constructed on a conditional basis for specific User
Agents (e.g. Email clients)</listitem>
<listitem>Construction of search engine friendly URLs that enable richer indexing since most search
engines cannot process parameterized URLs effectively.</listitem>
</itemizedlist>
<sect3 id="usingurlrewritesolelinkdpl">
<title>Using URL Rewriting to Solve Linked Data Deployment Challenges</title>
<para>URI naming schemes don't resolve the challenges associated with referencing data. To reiterate,
this is demonstrated by the fact that the URIs http://demo.openlinksw.com/Northwind/Customer/ALFKI
and http://demo.openlinksw.com/Northwind/Customer/ALFKI#this both appear as
http://demo.openlinksw.com/Northwind/Customer/ALFKI to the Web Server, since data following the
fragment identifier "#" never makes it that far.</para>
<para>The only way to address data referencing is by pre-processing source URIs
(e.g. via regular expression or sprintf substitutions) as part of a URL rewriting
processing pipeline. The pipeline process has to take the form of a set of rules
that cater for elements such as HTTP Accept headers, HTTP response code, HTTP response
headers, and rule processing order.</para>
<para>An example of such a pipeline is depicted in the table below.</para>
<table><title>Pre-processing source URIs</title>
<tgroup cols="5">
<thead><row>
<entry>URI Source(Regular Expression Pattern)</entry>
<entry>HTTP Accept Headers(Regular Expression)</entry>
<entry>HTTPResponse Code</entry>
<entry>HTTP Response Headers</entry>
<entry>Rule Processing Order</entry>
</row></thead>
<tbody>
<row>
<entry>/Northwind/Customer/([^#]*)</entry>
<entry>None (meaning default)</entry>
<entry>200 or 303 redirect to a resource with default representation.</entry>
<entry>None</entry>
<entry>Normal (order irrelevant)</entry>
</row>
<row>
<entry>/Northwind/Customer/([^#]*)</entry>
<entry>(text/rdf.n3)</entry>
<entry>(application/rdf.xml)</entry>
<entry>303 redirect to location of a descriptive and associated resource (e.g.
RESTful Web Service that returns desired representation)</entry>
<entry>None</entry>
</row>
<row>
<entry>/Northwind/Customer/([^#]*)</entry>
<entry>(text/html)</entry>
<entry>(application/xhtml.xml)</entry>
<entry>406 (Not Acceptable)or303 redirect to location of resource in requested representation</entry>
<entry>Vary: negotiate, acceptAlternates: {"ALFKI" 0.9 {type application/rdf+xml}}</entry>
</row>
</tbody>
</tgroup>
</table>
<para>The source URI patterns refer to virtual or physical directories for ex. at http://demo.openlinksw.com/.
Rules can be placed at the head or tail of the pipeline, or applied in the order they are declared,
by specifying a Rule Processing Order of First, Last, or Normal, respectively. The decision as to
which representation to return for URI http://demo.openlinksw.com/Northwind/Customer/ALFKI is based
on the MIME type(s) specified in any Accept header accompanying the request.</para>
<para>In the case of the last rule, the Alternates response header applies only to response code 406.
406 would be returned if there were no (X)HTML representation available for the requested resource.
In the example shown, an alternative representation is available in RDF/XML.</para>
<para>When applied to matching HTTP requests, the last two rules might generate responses similar to those below:</para>
<programlisting><![CDATA[
$ curl -I -H "Accept: application/rdf+xml" http://demo.openlinksw.com/Northwind/Customer/ALFKI
HTTP/1.1 303 See Other
Server: Virtuoso/05.00.3016 (Solaris) x86_64-sun-solaris2.10-64 PHP5
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Date: Mon, 16 Jul 2007 22:40:03 GMT
Accept-Ranges: bytes
Location: /sparql?query=CONSTRUCT+{+%3Chttp%3A//demo.openlinksw.com/Northwind/Customer/ALFKI%23this%3E+%3Fp+%3Fo+}+FROM+%3Chttp%3A//demo.openlinksw.com/Northwind%3E+WHERE+{+%3Chttp%3A//demo.openlinksw.com/Northwind/Customer/ALFKI%23this%3E+%3Fp+%3Fo+}&format=application/rdf%2Bxml
Content-Length: 0
]]></programlisting>
<para>In the cURL exchange depicted above, the target Virtuoso server redirects to a SPARQL endpoint
that retrieves an RDF/XML representation of the requested entity.</para>
<programlisting><![CDATA[
$ curl -I -H "Accept: text/html" http://demo.openlinksw.com/Northwind/Customer/ALFKI
HTTP/1.1 406 Not Acceptable
Server: Virtuoso/05.00.3016 (Solaris) x86_64-sun-solaris2.10-64 PHP5
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Date: Mon, 16 Jul 2007 22:40:23 GMT
Accept-Ranges: bytes
Vary: negotiate,accept
Alternates: {"ALFKI" 0.9 {type application/rdf+xml}}
Content-Length: 0
]]></programlisting>
<para>In this second cURL exchange, the target Virtuoso server indicates that there is no resource
to deliver in the requested representation. It provides hints in the form of an alternate resource
representation and URI that may be appropriate, i.e., an RDF/XML representation of the requested entity.
</para>
</sect3>
<sect3 id="virtuosorulebasedurlrewriter">
<title>The Virtuoso Rules-Based URL Rewriter</title>
<para>Virtuoso provides a URL rewriter that can be enabled for URLs matching specified patterns.
Coupled with customizable HTTP response headers and response codes, Data-Web server administrators
can configure highly flexible rules for driving content negotiation and URL rewriting. The key
elements of the URL rewriter are:</para>
<itemizedlist>
<listitem>Rewriting rule</listitem>
<listitem>Each rule describes how to parse a single source URL, and how to compose the URL of
the page ultimately returned in the "Location:" response headers</listitem>
<listitem>Every rewriting rule is uniquely identified internally (using IRIs).</listitem>
<listitem>Two types of rule are supported, based on the syntax used to describe the source
URL pattern matching: sprintf-based and regex-based.</listitem>
<listitem>Rewrite rules list</listitem>
<listitem>A named ordered list of rewrite rules or rule lists where rules of the list are
processed from top to bottom or in line with processing pipeline precedence instructions</listitem>
<listitem>Configuration API</listitem>
<listitem>The rewriter configuration API defines functions for creating, dropping, and
enumerating rules and rule lists.</listitem>
<listitem>Virtual hosts and virtual paths</listitem>
<listitem>URL rewriting is enabled by associating a rewrite rules list with a virtual directory</listitem>
</itemizedlist>
</sect3>
<sect3 id="urlrewritevirtdomains">
<title>Virtual Domains (Hosts) & Directories</title>
<para>A Virtuoso virtual directory maps a logical path to a physical directory that is file
system or WebDAV based. This mechanism allows physical locations to be hidden or simply reorganised.
Virtual directory definitions are held in the system table DB.DBA.HTTP_PATH. Virtual directories
can be administered in three basic ways:</para>
<itemizedlist>
<listitem>Using the Visual Administration Interface via a Web browser;</listitem>
<listitem>Using the functions vhost_define() and vhost_remove(); and</listitem>
<listitem>Using SQL statements to directly update the HTTP_PATH system table.</listitem>
</itemizedlist>
</sect3>
<sect3 id="urlrewriteniceurlsvslongurls">
<title>"Nice" URLs vs. "Long" URLs</title>
<para>Although we are approaching the URL Rewriter from the perspective of deploying linked data,
the Rewriter was developed with additional objectives in mind. These in turn have influenced
the naming of some of the formal argument names in the Configuration API function prototypes.
In the following sections, long URLs are those containing a query string with named parameters;
nice (aka. source) URLs have data encoded in some other format. The primary goal of the Rewriter
is to accept a nice URL from an application and convert this into a long URL, which then
identifies the page that should actually be retrieved.
</para>
</sect3>
<sect3 id="urlrewriterulesprocessmechanic">
<title>Rule Processing Mechanics</title>
<para>When an HTTP request is accepted by the Virtuoso HTTP server, the received nice URL is
passed to an internal path translation function. This function takes the nice URL and, if
the current virtual directory has a url_rewrite option set to an existing ruleset name, tries
to match the corresponding rulesets and rules; that is, it performs a recursive traversal
of any rulelist associated with it. For every rule in the rulelist, the same logic is
applied (only the logic for regex-based rules is described; that for sprintf-based rules
is very similar):
</para>
<itemizedlist>
<listitem>The input for the rule is the resource URL as received from the HTTP header, i.e.,
the portion of the URL from the first '/' after the host:port fields to the end of the URL.</listitem>
<listitem>The input is normalized.</listitem>
<listitem>The input is matched against the rule's regex. If the match fails, the rule is not
applied and the next rule is tried. If the match succeeds, the result is a vector of values.</listitem>
<listitem>If the URL contains a query string, the names and values of the parameters are decoded by
split_and_decode().</listitem>
<listitem>The names and values of any parameters in the request body are also decoded.</listitem>
<listitem>The destination URL is composed</listitem>
<listitem>The value of each parameter in the destination URL is taken from (in order of priority)</listitem>
<listitem>The value of a parameter in the match result;</listitem>
<listitem>The value of a named parameter in the query string of the input nice URL;</listitem>
<listitem>If the original request was submitted by the POST method, the value of a named parameter
in the body of the POST request; or</listitem>
<listitem>if a parameter value cannot be derived from one of these sources, the rule is not applied
and the next rule is tried.</listitem>
</itemizedlist>
<para>The path translation function described above is internal to the Web server, so its signature
is not appropriate for Virtuoso/PL calls and thus is not published. Virtuoso/PL developers can
harness the same functionality using the DB.DBA.URLREWRITE_APPLY API call.
</para>
</sect3>
<sect3 id="urlrewriteruleconductor">
<title>Enabling URL Rewriting via the Virtuoso Conductor UI</title>
<para>Virtuoso is a full-blown HTTP server in its own right. The HTTP server functionality co-exists
with the product core (i.e., DBMS Engine, Web Services Platform, WebDAV filesystem, and other
components of the Universal Server). As a result, it has the ability to multi-home Web domains
within a single instance across a variety of domain name and port combinations. In addition,
it also enables the creation of multiple virtual directories per domain.
</para>
<para>In addition to the basic functionality, Virtuoso facilitates the association of URL
Rewriting rules with the virtual directories associated with a hosted Web domain.
</para>
<para>In all cases, Virtuoso enables you to configure virtual domains, virtual directories
and URL rewrite rules for one or more virtual directories, via the (X)HTML-based Conductor
Admin User Interface or a collection of Virtuoso Stored Procedure Language (PL)-based APIs.
</para>
<para>The steps for configuring URL Rewrite rules via the Virtuoso Conductor are as follows:</para>
<itemizedlist>
<listitem>Assuming you are using the local demonstration database, load http://localhost:8890/conductor
into your browser, and then proceed through the Conductor as follows:</listitem>
<listitem>Click the "Web Application Server", and "Virtual Domains & Directories" tabs</listitem>
<listitem>Pick the domain that contains the virtual directories to which the rules are to be applied
(in this case the default was taken)</listitem>
<listitem>Click on the "URL-rewrite" link to create, delete, or edit a rule as shown below:</listitem>
<listitem>Create a Rule for HTML Representation Requests (via SPARQL SELECT Query)</listitem>
<listitem>Create a Rule for RDF Representation Requests (via SPARQL CONSTRUCT Query)</listitem>
<listitem>Then save and exit the Conductor, and test your rules with curl or any other User Agent.</listitem>
</itemizedlist>
<figure id="urlrewriteimg1" float="1">
<title>URL-rewrite UI using Conductor</title>
<graphic fileref="ui/urlrw1.png"/>
</figure>
</sect3>
<sect3 id="urlrewriterulevirtusopl">
<title>Enabling URL Rewriting via Virtuoso PL</title>
<para>The vhost_define()API is used to define virtual hosts and virtual paths hosted by the
Virtuoso HTTP server. URL rewriting is enabled through this function's opts parameter.
opts is of type ANY, e.g., a vector of field-value pairs. Numerous fields are recognized
for controlling different options. The field value url_rewrite controls URL rewriting.
The corresponding field value is the IRI of a rule list to apply.
</para>
<sect4 id="urlrewriterulevirtusoplcontrolapi"><title>Configuration API</title>
<para>Virtuoso includes the following functions for managing URL rewriting rules and rule
lists. The names are self-explanatory.</para>
<programlisting><![CDATA[
-- Deletes a rewriting rule
DB.DBA.URLREWRITE_DROP_RULE
-- Creates a rewriting rule which uses sprintf-based pattern matching
DB.DBA.URLREWRITE_CREATE_SPRINTF_RULE
-- Creates a rewriting rule which uses regular expression (regex) based pattern matching
DB.DBA.URLREWRITE_CREATE_REGEX_RULE
-- Deletes a rewriting rule list
DB.DBA.URLREWRITE_DROP_RULELIST
-- Creates a rewriting rule list
DB.DBA.URLREWRITE_CREATE_RULELIST
-- Lists all the rules whose IRI match the specified 'SQL like' pattern
DB.DBA.URLREWRITE_ENUMERATE_RULES
-- Lists all the rule lists whose IRIs match the specified 'SQL like' pattern
DB.DBA.URLREWRITE_ENUMERATE_RULELISTS
]]></programlisting>
</sect4>
<sect4 id="urlrewriterulecreaterewriterule"><title>Creating Rewriting Rules</title>
<para>Rewriting rules take two forms: sprintf-based or regex-based. When used for nice
URL to long URL conversion, the only difference between them is the syntax of format
strings. The reverse long to nice conversion works only for sprintf-based rules,
whereas regex-based rules are unidirectional.
</para>
<para>For the purposes of describing how to make dereferenceable URIs for linked data,
we will stick with the nice to long conversion using regex-based rules.
</para>
<para>Regex rules are created using the <emphasis>URLREWRITE_CREATE_REGEX_RULE()</emphasis> function.</para>
</sect4>
</sect3>
<sect3 id="urlrewriteruleexamplenorthwind">
<title>Example - URL Rewriting For the Northwind RDF View</title>
<para>The Northwind schema is comprised of commonly understood SQL Tables that include: Customers,
Orders, Employees, Products, Product Categories, Shippers, Countries, Provinces etc.
</para>
<para>An RDF View of SQL data is an RDF named graph (RDF data set) comprised of RDF Linked Data
(triples) stored in a Virtuoso Quad Store (the native RDF Data Management realm of Virtuoso).
</para>
<para>In this example we are going interact with Linked Data deployed into the Data-Web from
a live instance of Virtuoso, which uses the URL Rewrite rules from the prior section.
</para>
<para>The components used in the example are as follows:</para>
<itemizedlist>
<listitem>Virtuoso SPARQL Endpoint: http://demo.openlinksw.com/sparql</listitem>
<listitem>Named RDF Graph: http://demo.openlinksw.com/Northwind</listitem>
<listitem>Entity ID - http://demo.openlinksw.com/Northwind/Customer/ALFKI#this</listitem>
<listitem>Information Resource: http://demo.openlinksw.com/Northwind/Customer/ALFKI</listitem>
<listitem>Interactive SPARQL Query Builder (iSPARQL) - http://demo.openlinksw.com/DAV/JS/isparql/index.html</listitem>
</itemizedlist>
<sect4 id="urlrewriterulenorthwindverificationcurl"><title>Northwind URL Rewriting Verification Using curl</title>
<para>The curl utility provides a useful tool for verifying HTTP server responses and rewriting
rules. The curl exchanges below show the URL rewriting rules defined for the Northwind RDF
view being applied.
</para>
<para><emphasis>Example 1:</emphasis></para>
<programlisting><![CDATA[
$ curl -I -H "Accept: text/html" http://demo.openlinksw.com/Northwind/Customer/ALFKI
HTTP/1.1 303 See Other
Server: Virtuoso/05.00.3016 (Solaris) x86_64-sun-solaris2.10-64 PHP5
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Date: Tue, 14 Aug 2007 13:30:02 GMT
Accept-Ranges: bytes
Location: http://demo.openlinksw.com/about/html/http/demo.openlinksw.com/Northwind/Customer/ALFKI
Content-Length: 0
]]></programlisting>
<para><emphasis>Example 2:</emphasis></para>
<programlisting><![CDATA[
$ curl -I -H "Accept: application/rdf+xml" http://demo.openlinksw.com/Northwind/Customer/ALFKI
HTTP/1.1 303 See Other
Server: Virtuoso/05.00.3016 (Solaris) x86_64-sun-solaris2.10-64 PHP5
Connection: close
Content-Type: text/html; charset=ISO-8859-1
Date: Tue, 14 Aug 2007 13:30:22 GMT
Accept-Ranges: bytes
Location: /sparql?query=CONSTRUCT+{+%3Chttp%3A//demo.openlinksw.com/Northwind/Customer/ALFKI%23this%3E+%3Fp+%3Fo+}+FROM+%3Chttp%3A//demo.openlinksw.com/Northwind%3E+WHERE+{+%3Chttp%3A//demo.openlinksw.com/Northwind/Customer/ALFKI%23this%3E+%3Fp+%3Fo+}&format=application/rdf%2Bxml
Content-Length: 0
]]></programlisting>
<para><emphasis>Example 3:</emphasis></para>
<programlisting><![CDATA[
$ curl -I -H "Accept: text/html" http://demo.openlinksw.com/Northwind/Customer/ALFKI#this
HTTP/1.1 404 Not Found
Server: Virtuoso/05.00.3016 (Solaris) x86_64-sun-solaris2.10-64 PHP5
Connection: Keep-Alive
Content-Type: text/html; charset=ISO-8859-1
Date: Tue, 14 Aug 2007 13:31:01 GMT
Accept-Ranges: bytes
Content-Length: 0
]]></programlisting>
<para>The output above shows how RDF entities from the Data-Web, in this case customer ALFKI,
are exposed in the Document Web. The power of SPARQL coupled with URL rewriting enables us to
produce results in line with the desired representation. A SPARQL SELECT or CONSTRUCT query is
used depending on whether the requested representation is text/html or application/rdf+xml,
respectively.</para>
<para>The 404 response in Example 3 indicates that no HTML representation is available for entity
ALFKI#this. In most cases, a URI of this form (containing a '#' fragment identifier) will
not reach the server. This example supposes that it does: i.e., the RDF client and network
routing allows the suffixed request. The presence of the #this suffix implicitly states
that this is a request for a data resource in the Data-Web realm, not a document resource
from the Document Web.2</para>
<para>Rather than return 404, we could instead choose to construct our rewriting rules to
perform a 303 redirect, so that the response for ALFKI#this in Example 3 becomes the same
as that for ALFKI in Example 1.</para>
</sect4>
</sect3>
<sect3 id="urlrewritetransperantcontent">
<title>Transparent Content Negotiation</title>
<para>So as not to overload our preceding description of Linked Data deployment with excessive
detail, the description of content negotiation presented thus far was kept deliberately brief.
This section discusses content negotiation in more detail.
</para>
<sect4 id="urlrewritetransperantcontenthttp"><title>HTTP/1.1 Content Negotiation</title>
<para>Recall that a resource (conceptual entity) identified by a URI may be associated
with more than one representation (e.g. multiple languages, data formats, sizes, resolutions).
If multiple representations are available, the resource is referred to as negotiable and
each of its representations is termed a variant. For instance, a Web document resource, named
'ALFKI' may have three variants: alfki.xml, alfki.html and alfki.txt all representing the same data.
Content negotiation provides a mechanism for selecting the best variant.</para>
<para>As outlined in the earlier brief discussion of content negotiation, when a user agent
requests a resource, it can include with the request Accept headers (Accept, Accept-Language,
Accept-Charset, Accept-Encoding etc.) which express the user preferences and user agent
capabilities. The server then chooses and returns the best variant based on the Accept headers.
Because the selection of the best resource representation is made by the server, this
scheme is classed as server-driven negotiation.</para>
</sect4>
<sect4 id="urlrewritetransperantcontenttransperant"><title>Transparent Content Negotiation</title>
<para>An alternative content negotiation mechanism is Transparent Content Negotiation (TCN),
a protocol defined by RFC2295 . TCN offers a number of benefits over standard HTTP/1.1 negotiation,
for suitably enabled user agents.</para>
<para>RFC2295 introduces a number of new HTTP headers including the Negotiate request header,
and the TCN and Alternates response headers. (Krishnamurthy et al. note that although the
HTTP/1.1 specification reserved the Alternates header for use in agent driven negotiation,
it was not fully specified. Consequently under a pure HTTP/1.1 implementation as defined by
RFC2616, server-driven content negotiation is the only option. RFC2295 addresses this issue.)</para>
</sect4>
<sect4 id="urlrewritetransperantcontentdefic"><title>Deficiencies of HTTP/1.1 Server-Driven Negotiation</title>
<para>Weaknesses of server-driven negotiation highlighted by RFCs 2295 and 2616 include:</para>
<itemizedlist>
<listitem>Inefficiency - Sending details of a user agent's capabilities and preferences
with every request is very inefficient, not least because very few Web resources have
multiple variants, and expensive in terms of the number of Accept headers required to
fully describe all but the most simple browser's capabilities.</listitem>
<listitem>Server doesn't always know 'best' - Having the server decide on the 'best' variant
may not always result in the most suitable resource representation being returned to
the client. The user agent might often be better placed to decide what is best for its needs.</listitem>
</itemizedlist>
</sect4>
<sect4 id="urlrewritetransperantcontentvariantagent"><title>Variant Selection By User Agent</title>
<para>Rather than rely on server-driven negotiation and variant selection by the server,
a user agent can take full control over deciding the best variant by explicitly requesting
transparent content negotiation through the Negotiate request header. The negotiation is
'transparent' because it makes all the variants on the server visible to the agent.</para>
<para>Under this scheme, the server sends the user agent a list, represented in an
Alternates header, containing the available variants and their properties. The user
agent can then choose the best variant itself. Consequently, the agent no longer
needs to send large Accept headers describing in detail its capabilities
and preferences. (However, unless caching is used, user-agent driven negotiation does
suffer from the disadvantage of needing a second request to obtain the best representation.
By sending its best guess as the first response, server driven negotiation avoids this
second request if the initial best guess is acceptable.)</para>
</sect4>
<sect4 id="urlrewritetransperantcontentvariantserver"><title>Variant Selection By Server</title>
<para>As well as variant selection by the user agent, TCN allows the server to choose on
behalf of the user agent if the user agent explicitly allows it through the Negotiate
request header. This option allows the user agent to send smaller Accept headers
containing enough information to allow the server to choose the best variant and
return it directly. The server's choice is controlled by a 'remote variant selection
algorithm' as defined in RFC2296.</para>
</sect4>
<sect4 id="urlrewritetransperantcontentvariantuser"><title>Variant Selection By End-User</title>
<para>A further option is to allow the end-user to select a variant, in case the choice made
by negotiation process is not optimal. For instance, the user agent could display an
HTML-based 'pick list' of variants constructed from the variant list returned by the server.
Alternatively the server could generate this pick list itself and include it in the response
to a user agent's request for a variant list. (Virtuoso currently responds this way.)</para>
</sect4>
</sect3>
<sect3 id="urlrewritetransperantcontentserver">
<title>Transparent Content Negotiation in Virtuoso HTTP Server</title>
<para>The following section describes the Virtuoso HTTP server's TCN implementation
which is based on RFC2295, but without "Feature" negotiation. OpenLink's RDF rich clients,
iSparql and the OpenLink RDF Browser, both support TCN. User agents which do not support
transparent content negotiation continue to be handled using HTTP/1.1 style content
negotiation (whereby server-side selection is the only option - the server selects
the best variant and returns a list of variants in an Alternates response header).</para>
<sect4 id="urlrewritetransperantcontentserverdesc"><title>Describing Resource Variants</title>
<para>In order to negotiate a resource, the server needs to be given information about each
of the variants. Variant descriptions are held in SQL table HTTP_VARIANT_MAP.
The descriptions themselves can be created, updated or deleted using Virtuoso/PL or
through the Conductor UI. The table definition is as follows:</para>
<programlisting><![CDATA[
create table DB.DBA.HTTP_VARIANT_MAP (
VM_ID integer identity, -- unique ID
VM_RULELIST varchar, -- HTTP rule list name
VM_URI varchar, -- name of requested resource e.g. 'page'
VM_VARIANT_URI varchar, -- name of variant e.g. 'page.xml', 'page.de.html' etc.
VM_QS float, -- Source quality, a number in the range 0.001-1.000, with 3 digit precision
VM_TYPE varchar, -- Content type of the variant e.g. text/xml
VM_LANG varchar, -- Content language e.g. 'en', 'de' etc.
VM_ENC varchar, -- Content encoding e.g. 'utf-8', 'ISO-8892' etc.
VM_DESCRIPTION long varchar, -- a human readable description about the variant e.g. 'Profile in RDF format'
VM_ALGO int default 0, -- reserved for future use
primary key (VM_RULELIST, VM_URI, VM_VARIANT_URI)
)
create unique index HTTP_VARIANT_MAP_ID on DB.DBA.HTTP_VARIANT_MAP (VM_ID)
]]></programlisting>
</sect4>
<sect4 id="urlrewritetransperantcontentserveconfgpl"><title>Configuration using Virtuoso/PL</title>
<para>Two functions are provided for adding or updating, or removing variant descriptions using Virtuoso/PL:</para>
<programlisting><![CDATA[
-- Adding or Updating a Resource Variant:
DB.DBA.HTTP_VARIANT_ADD (
in rulelist_uri varchar, -- HTTP rule list name
in uri varchar, -- Requested resource name e.g. 'page'
in variant_uri varchar, -- Variant name e.g. 'page.xml', 'page.de.html' etc.
in mime varchar, -- Content type of the variant e.g. text/xml
in qs float := 1.0, -- Source quality, a floating point number with 3 digit precision in 0.001-1.000 range
in description varchar := null, -- a human readable description of the variant e.g. 'Profile in RDF format'
in lang varchar := null, -- Content language e.g. 'en', 'bg'. 'de' etc.
in enc varchar := null -- Content encoding e.g. 'utf-8', 'ISO-8892' etc.
)
--Removing a Resource Variant
DB.DBA.HTTP_VARIANT_REMOVE (
in rulelist_uri varchar, -- HTTP rule list name
in uri varchar, -- Name of requested resource e.g. 'page'
in variant_uri varchar := '%' -- Variant name filter
)
]]></programlisting>
</sect4>
<sect4 id="urlrewritetransperantcontentserveconfgconductor"><title>Configuration using Conductor UI</title>
<para>The Conductor 'Content negotiation' panel for describing resource variants and configuring
content negotiation is depicted below. It can be reached by selecting the 'Virtual Domains & Directories'
tab under the 'Web Application Server' menu item, then selecting the 'URL rewrite' option for a logical path
listed amongst those for the relevant HTTP host, e.g. '{Default Web Site}'</para>
<para>The input fields reflect the supported 'dimensions' of negotiation which include content type,
language and encoding. Quality values corresponding to the options for 'Source Quality' are as follows:</para>
<table><title>Source Quality</title>
<tgroup cols="2">
<thead><row>
<entry>Source Quality</entry>
<entry>Quality Value</entry>
</row></thead>
<tbody>
<row>
<entry>perfect representation</entry>
<entry>1.000</entry>
</row>
<row>
<entry>threshold of noticeable loss of quality</entry>
<entry>0.900</entry>
</row>
<row>
<entry>noticeable, but acceptable quality reduction</entry>
<entry>0.800</entry>
</row>
<row>
<entry>barely acceptable quality</entry>
<entry>0.500</entry>
</row>
<row>
<entry>severely degraded quality</entry>
<entry>0.300</entry>
</row>
<row>
<entry>completely degraded quality</entry>
<entry>0.000</entry>
</row>
</tbody>
</tgroup>
</table>
</sect4>
<sect4 id="urlrewritetransperantcontentserveconfgvarselalgr"><title>Variant Selection Algorithm</title>
<para>When a user agent instructs the server to select the best variant, Virtuoso does so
using the selection algorithm below:</para>
<para>If a virtual directory has URL rewriting enabled (has the 'url_rewrite' option set),
the web server:</para>
<itemizedlist>
<listitem>Looks in DB.DBA.HTTP_VARIANT_MAP for a VM_RULELIST matching the one specified in
the 'url_rewrite' option</listitem>
<listitem>If present, it loops over all variants for which VM_URI is equal to the resource requested</listitem>
<listitem>For every variant it calculates the source quality based on the value of VM_QS and the
source quality given by the user agent</listitem>
<listitem>If the best variant is found, it adds TCN HTTP headers to the response and passes the
VM_VARIANT_URI to the URL rewriter</listitem>
<listitem>If the user agent has asked for a variant list, it composes such a list and returns an
'Alternates' HTTP header with response code 300</listitem>
<listitem>If no URL rewriter rules exist for the target URL, the web server returns the content of
the dereferenced VM_VARIANT_URI.</listitem>
</itemizedlist>
<para>The server may return the best-choice resource representation or a list of available
resource variants. When a user agent requests transparent negotiation, the web server returns
the TCN header "choice". When a user agent asks for a variant list, the server returns the
TCN header "list".</para>
</sect4>
<sect4 id="urlrewritetransperantcontentserveconfgexamples"><title>Examples</title>
<para>In this example we assume the following files have been uploaded to the Virtuoso WebDAV
server, with each containing the same information but in different formats:</para>
<itemizedlist>
<listitem>/DAV/TCN/page.xml - a XML variant</listitem>
<listitem>/DAV/TCN/page.html - a HTML variant</listitem>
<listitem>/DAV/TCN/page.txt - a text variant</listitem>
</itemizedlist>
<para>We add TCN rules and define a virtual directory:</para>
<programlisting><![CDATA[
DB.DBA.HTTP_VARIANT_ADD ('http_rule_list_1', 'page', 'page.html','text/html', 0.900000, 'HTML variant');
DB.DBA.HTTP_VARIANT_ADD ('http_rule_list_1', 'page', 'page.txt', 'text/plain', 0.500000, 'Text document');
DB.DBA.HTTP_VARIANT_ADD ('http_rule_list_1', 'page', 'page.xml', 'text/xml', 1.000000, 'XML variant');
DB.DBA.VHOST_DEFINE (lpath=>'/DAV/TCN/',
ppath=>'/DAV/TCN/',
is_dav=>1,
vsp_user=>'dba',
opts=>vector ('url_rewrite', 'http_rule_list_1'));
]]></programlisting>
<para>Having done this we can now test the setup with a suitable HTTP client, in this
case the curl command line utility. In the following examples, the curl client supplies
Negotiate request headers containing content negotiation directives which include:</para>
<itemizedlist>
<listitem>"trans" - The user agent supports transparent content negotiation for the current request.</listitem>
<listitem>"vlist" - The user agent requests that any transparently negotiated response
for the current request includes an Alternates header with the variant list bound to
the negotiable resource. Implies "trans".</listitem>
<listitem>"*" - The user agent allows servers and proxies to run any remote variant selection algorithm.</listitem>
</itemizedlist>
<para>The server returns a TCN response header signalling that the resource is transparently negotiated and either
a choice or a list response as appropriate.</para>
<para>In the first curl exchange, the user agent indicates to the server that, of the formats
it recognizes, HTML is preferred and it instructs the server to perform transparent content
negotiation. In the response, the Vary header field expresses the parameters the server used
to select a representation, i.e. only the Negotiate and Accept header fields are considered.</para>
<programlisting><![CDATA[
$ curl -i -H "Accept: text/xml;q=0.3,text/html;q=1.0,text/plain;q=0.5,*/*;
q=0.3" -H "Negotiate: *" http://localhost:8890/DAV/TCN/page
HTTP/1.1 200 OK Server: Virtuoso/05.00.3021 (Linux) i686-pc-linux-gnu
VDB Connection: Keep-Alive Date: Wed, 31 Oct 2007 15:43:18
GMT Accept-Ranges: bytes TCN: choice Vary: negotiate,accept
Content-Location: page.html Content-Type: text/html
ETag: "14056a25c066a6e0a6e65889754a0602"
Content-Length: 49
<html> <body> some html </body> </html>
]]></programlisting>
<para>Next, the source quality values are adjusted so that the user agent indicates that XML is its preferred format.
</para>
<programlisting><![CDATA[
$ curl -i -H "Accept: text/xml,text/html;q=0.7,text/plain;q=0.5,*/*;q=0.3" -H "Negotiate:
*" http://localhost:8890/DAV/TCN/page HTTP/1.1 200 OK Server: Virtuoso/05.00.3021
(Linux) i686-pc-linux-gnu VDB Connection: Keep-Alive Date: Wed, 31 Oct 2007
15:44:07 GMT Accept-Ranges: bytes TCN: choice Vary: negotiate,accept
Content-Location: page.xml Content-Type: text/xml ETag:
"8b09f4b8e358fcb7fd1f0f8fa918973a" Content-Length: 39
<?xml version="1.0" ?> <a>some xml</a>
]]></programlisting>
<para>In the final example, the user agent wants to decide itself which is the most
suitable representation, so it asks for a list of variants. The server provides the
list, in the form of an Alternates response header, and, in addition, sends an
HTML representation of the list so that the end user can decide on the preferred
variant himself if the user agent is unable to.</para>
<programlisting><![CDATA[
$ curl -i -H "Accept: text/xml,text/html;q=0.7,text/plain;q=0.5,*/*;q=0.3" -H "Negotiate:
vlist" http://localhost:8890/DAV/TCN/page HTTP/1.1 300 Multiple Choices Server:
Virtuoso/05.00.3021 (Linux) i686-pc-linux-gnu VDB Connection: close Content-Type:
text/html; charset=ISO-8859-1 Date: Wed, 31 Oct 2007 15:44:35 GMT Accept-Ranges:
bytes TCN: list Vary: negotiate,accept Alternates: {"page.html" 0.900000 {type text/html}},
{"page.txt" 0.500000 {type text/plain}}, {"page.xml" 1.000000 {type text/xml}} Content-Length: 368
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>300 Multiple Choices</title>
</head>
<body>
<h1>Multiple Choices</h1>
Available variants:
<ul>
<li>
<a href="page.html">HTML variant</a>, type text/html</li>
<li><a href="page.txt">Text document</a>, type text/plain</li>
<li><a href="page.xml">XML variant</a>, type text/xml</li>
</ul>
</body>
</html>
]]></programlisting>
</sect4>
</sect3>
</sect2>
<sect2 id="rdfiridereferencingexamples"><title>Examples of other Protocol Resolvers</title>
<para>Example of <emphasis>LSIDs</emphasis>: A scientific name from UBio</para>
<programlisting><![CDATA[
SQL>SPARQL
define get:soft "soft"
SELECT *
FROM <urn:lsid:ubio.org:namebank:11815>
WHERE { ?s ?p ?o }
LIMIT 5;
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
urn:lsid:ubio.org:namebank:11815 http://purl.org/dc/elements/1.1/title Pternistis leucoscepus
urn:lsid:ubio.org:namebank:11815 http://purl.org/dc/elements/1.1/subject Pternistis leucoscepus (Gray, GR) 1867
urn:lsid:ubio.org:namebank:11815 http://purl.org/dc/elements/1.1/identifier urn:lsid:ubio.org:namebank:11815
urn:lsid:ubio.org:namebank:11815 http://purl.org/dc/elements/1.1/creator http://www.ubio.org
urn:lsid:ubio.org:namebank:11815 http://purl.org/dc/elements/1.1/type Scientific Name
5 Rows. -- 741 msec.
]]></programlisting>
<para>Example of <emphasis>LSIDs</emphasis>: A segment of the human genome from GDB</para>
<programlisting><![CDATA[
SQL>SPARQL
define get:soft "soft"
SELECT *
FROM <urn:lsid:gdb.org:GenomicSegment:GDB132938>
WHERE { ?s ?p ?o }
LIMIT 5;
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
urn:lsid:gdb.org:GenomicSegment:GDB132938 urn:lsid:gdb.org:DBObject-predicates:accessionID GDB:132938
urn:lsid:gdb.org:GenomicSegment:GDB132938 http://www.ibm.com/LSID/2004/RDF/#lsidLink urn:lsid:gdb.org:DBObject:GDB132938
urn:lsid:gdb.org:GenomicSegment:GDB132938 urn:lsid:gdb.org:DBObject-predicates:objectClass DBObject
urn:lsid:gdb.org:GenomicSegment:GDB132938 urn:lsid:gdb.org:DBObject-predicates:displayName D20S95
urn:lsid:gdb.org:GenomicSegment:GDB132938 urn:lsid:gdb.org:GenomicSegment-predicates:variantsQ nodeID://1000027961
5 Rows. -- 822 msec.
]]></programlisting>
<para>Example of <emphasis>OAI</emphasis>: an institutional / departmental repository.</para>
<programlisting><![CDATA[
SQL>SPARQL
define get:soft "soft"
SELECT *
FROM <oai:etheses.bham.ac.uk:23>
WHERE { ?s ?p ?o }
LIMIT 5;
s p o
VARCHAR VARCHAR VARCHAR
_____________________________________________________________________________
oai:etheses.bham.ac.uk:23 http://purl.org/dc/elements/1.1/title A study of the role of ATM mutations in the pathogenesis of B-cell chronic lymphocytic leukaemia
oai:etheses.bham.ac.uk:23 http://purl.org/dc/elements/1.1/date 2007-07
oai:etheses.bham.ac.uk:23 http://purl.org/dc/elements/1.1/subject RC0254 Neoplasms. Tumors. Oncology (including Cancer)
oai:etheses.bham.ac.uk:23 http://purl.org/dc/elements/1.1/identifier Austen, Belinda (2007) A study of the role of ATM mutations in the pathogenesis of B-cell chronic lymphocytic leukaemia. Ph.D. thesis, University of Birmingham.
oai:etheses.bham.ac.uk:23 http://purl.org/dc/elements/1.1/identifier http://etheses.bham.ac.uk/23/1/Austen07PhD.pdf
5 Rows. -- 461 msec.
]]></programlisting>
<para>Example of <emphasis>DOI</emphasis></para>
<para>In order to execute correctly queries with doi resolver you need to have:</para>
<itemizedlist>
<listitem>the handle.dll file accessible from your system. For ex. you can put it in the Virtuoso bin folder where the rest of the server components are.</listitem>
<listitem>in your Virtuoso database ini file in section Plugins added the hslookup.dll file, which location should be in the plugins folder under your Virtuoso server installation. For ex:
<programlisting><![CDATA[
[Plugins]
LoadPath = ./plugin
...
Load6 = plain,hslookup
]]></programlisting>
</listitem>
</itemizedlist>
<programlisting><![CDATA[
SQL>SPARQL
define get:soft "soft"
SELECT *
FROM <doi:10.1045/march99-bunker>
WHERE { ?s ?p ?o } ;
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://www.dlib.org/dlib/march99/bunker/03bunker.html http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://www.openlinksw.com/schemas/XHTML#
http://www.dlib.org/dlib/march99/bunker/03bunker.html http://www.openlinksw.com/schemas/XHTML#title Collaboration as a Key to Digital Library Development: High Performance Image Management at the University of Washington
2 Rows. -- 12388 msec.
]]></programlisting>
<para>Other examples</para>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX doap: <http://usefulinc.com/ns/doap#>
SELECT DISTINCT ?name ?mbox ?projectName
WHERE {
<http://dig.csail.mit.edu/2005/ajar/ajaw/data#Tabulator>
doap:developer ?dev .
?dev foaf:name ?name .
OPTIONAL { ?dev foaf:mbox ?mbox }
OPTIONAL { ?dev doap:project ?proj .
?proj foaf:name ?projectName }
};
name mbox projectName
VARCHAR VARCHAR VARCHAR
____________________ ___________________________________________
Adam Lerer NULL NULL
Dan Connolly NULL NULL
David Li NULL NULL
David Sheets NULL NULL
James Hollenbach NULL NULL
Joe Presbrey NULL NULL
Kenny Lu NULL NULL
Lydia Chilton NULL NULL
Ruth Dhanaraj NULL NULL
Sonia Nijhawan NULL NULL
Tim Berners-Lee NULL NULL
Timothy Berners-Lee NULL NULL
Yuhsin Joyce Chen NULL NULL
13 Rows. -- 491 msec.
]]></programlisting>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?friendsname ?friendshomepage ?foafsname ?foafshomepage
WHERE
{
<http://myopenlink.net/dataspace/person/kidehen#this> foaf:knows ?friend .
?friend foaf:mbox_sha1sum ?mbox .
?friendsURI foaf:mbox_sha1sum ?mbox .
?friendsURI foaf:name ?friendsname .
?friendsURI foaf:homepage ?friendshomepage .
OPTIONAL { ?friendsURI foaf:knows ?foaf .
?foaf foaf:name ?foafsname .
?foaf foaf:homepage ?foafshomepage .
}
}
LIMIT 10;
friendsname friendshomepage foafsname foafshomepage
ANY ANY ANY ANY
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Dan Connolly http://www.w3.org/People/Connolly/
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Henry J. Story http://bblfish.net/
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Henry Story http://bblfish.net/
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Henry J. Story http://bblfish.net/people/henry/card
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Henry Story http://bblfish.net/people/henry/card
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Ruth Dhanaraj http://web.mit.edu/ruthdhan/www
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Dan Brickley http://danbri.org/
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Dan Brickley http://danbri.org/
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Daniel Krech http://eikeon.com/
Tim Berners Lee http://www.w3.org/People/Berners-Lee/ Daniel Krech http://eikeon.com/
]]></programlisting>
</sect2>
<sect2 id="rdfiridereferencingfacet"><title>Faceted Views over Large-Scale Linked Data</title>
<para>Faceted views over structured and semi structured data have been popular in user interfaces for
some years. Deploying such views of arbitrary linked data at arbitrary scale has been hampered by lack
of suitable back end technology. Many ontologies are also quite large, with hundreds of thousands of
classes.
</para>
<para>Also, the linked data community has been concerned with the processing cost and potential for
denial of service presented by public SPARQL end points.
</para>
<para>This section discusses how we use Virtuoso Cluster Edition for providing interactive browsing over
billions of triples, combining full text search, structured querying and result ranking. We discuss query
planning, run-time inferencing and partial query evaluation. This functionality is exposed through SPARQL,
a specialized web service and a web user interface.</para>
<para>The transition of the web from a distributed document repository into a universal, ubiquitous
database requires a new dimension of scalability for supporting rich user interaction. If the web is the
database, then it also needs a query and report writing tool to match. A faceted user interaction paradigm
has been found useful for aiding discovery and query of variously structured data. Numerous implementations
exist but they are chiefly client side and are limited in the data volumes they can handle.
</para>
<para>At the present time, linked data is well beyond prototypes and proofs of concept. This means that
what was done in limited specialty domains before must now be done at real world scale, in terms of both
data volume and ontology size. On the schema, or T box side, there exist many comprehensive general purpose
ontologies such as Yago[1], OpenCyc[2], Umbel[3] and the DBpedia[4] ontology and many domain specific
ones, such as [5]. For these to enter into the user experience, the platform must be able to support
the user's choice of terminology or terminologies as needed, preferably without blow up of data and
concomitant slowdown.
</para>
<para>Likewise, in the LOD world, many link sets have been created for bridging between data sets.
Whether such linkage is relevant will depend on the use case. Therefore we provide fine grained control
over which owl:sameAs assertions will be followed, if any.
</para>
<para>Against this background, we discuss how we tackle incremental interactive query composition on
arbitrary data with <link linkend="clusteroperation">Virtuoso Cluster</link>.
</para>
<para>Using SPARQL or a web/web service interface, the user can form combinations of text search and
structured criteria, including joins to an arbitrary depth. If queries are precise and select a limited
number of results, the results are complete. If queries would select tens of millions of results, partial
results are shown.
</para>
<para>The system being described is being actively developed as of this writing, early March of 2009
and is online at http://lod.openlinksw.com/. The data set is a combination of DBpedia, MusicBrainz,
Freebase, UniProt, NeuroCommons, Bio2RDF, and web crawls from PingTheSemanticWeb.com.
</para>
<para>The hardware consists of two 8-core servers with 16G RAM and 4 disks each. The system runs on
Virtuoso 6 Cluster Edition. All application code is written in SQL procedures with limited client side
Ajax, the Virtuoso platform itself is in C.
</para>
<para>The facets service allows the user to start with a text search or a fixed URI and to refine the
search by specifying classes, property values etc., on the selected subjects or any subjects referenced
therefrom.
</para>
<para>This process generates queries involving combinations of text and structured criteria, often
dealing with property and class hierarchies and often involving aggregation over millions of subjects,
specially at the initial stages of query composition. To make this work with in interactive time, two
things are needed:
</para>
<orderedlist>
<listitem>a query optimizer that can almost infallibly produce the right join order based on cardinalities of
the specific constants in the query</listitem>
<listitem>a query execution engine that can return partial results after a timeout.</listitem>
</orderedlist>
<para>It is often the case, specially at the beginning of query formulation, that the user only needs
to know if there are relatively many or few results that are of a given type or involve a given property.
Thus partially evaluating a query is often useful for producing this information. This must however be
possible with an arbitrary query, simply citing precomputed statistics is not enough.
</para>
<para>It has for a long time been a given that any search-like application ranks results by relevance.
Whenever the facets service shows a list of results, not an aggregation of result types or properties,
it is sorted on a composite of text match score and link density.
</para>
<para>The section is divided into the following parts:
</para>
<itemizedlist mark="bullet">
<listitem>SPARQL query optimization and execution adapted for run time inference over large subclass
structures.</listitem>
<listitem>Resolving identity with inverse functional properties</listitem>
<listitem>Ranking entities based on graph link density</listitem>
<listitem>SPARQL partial query evaluation for displaying partial results in fixed time</listitem>
<listitem>a facets web service providing an XML interface for submitting queries, so that the
user interface is not required to parse SPARQL</listitem>
<listitem>a sample web interface for interacting with this</listitem>
<listitem>sample queries and their evaluation times against combinations of large LOD data sets</listitem>
</itemizedlist>
<sect3 id="rdfiridereferencingfacetprlh"><title>Processing Large Hierarchies in SPARQL</title>
<para>Virtuoso has for a long time had built-in superclass and superproperty inference. This is enabled by
specifying the <emphasis>DEFINE input:inference "context"</emphasis> option, where context is previously
declared to be all subclass, subproperty, equivalence, inverse functional property and same as relations
defined in a given graph. The ontology file is loaded into its own graph and this is then used to construct
the context. Multiple ontologies and their equivalences can be loaded into a single graph which then makes
another context which holds the union of the ontology information from the merged source ontologies.
</para>
<para>
Let us consider a sample query combining a full text search and a restriction on the class of the desired
matches:
</para>
<programlisting><![CDATA[
DEFINE input:inference "yago"
PREFIX cy: <http://dbpedia.org/class/yago/>
SELECT DISTINCT ?s1 AS ?c1
( bif:search_excerpt
( bif:vector ( 'Shakespeare' ), ?o1 )
) AS ?c2
WHERE
{
?s1 ?s1textp ?o1 .
FILTER
( bif:contains (?o1, '"Shakespeare"') ) .
?s1 a cy:Performer110415638
}
LIMIT 20
]]></programlisting>
<para>This selects all Yago performers that have a property that contains "Shakespeare" as a whole word.
</para>
<para>The <emphasis>DEFINE input:inference "yago"</emphasis> clause means that subclass, subproperty and
inverse functions property statements contained in the inference context called yago are considered when
evaluating the query. The built-in function <emphasis>bif:search_excerpt</emphasis> makes a search engine style summary of
the found text, highlighting occurrences of Shakespeare.
</para>
<para>The <emphasis>bif:contains</emphasis> function in the filter specifies the full text search
condition on ?o1.
</para>
<para>This query is a typical example of queries that are executed all the time when a user refines a
search. We will now look at how we can make an efficient execution plan for the query. First, we must
know the cardinalities of the search conditions:
</para>
<para>To see the count of subclasses of Yago performer, we can do:
</para>
<programlisting><![CDATA[
SPARQL
PREFIX cy: <http://dbpedia.org/class/yago/>
SELECT COUNT (*)
FROM <http://dbpedia.org/yago.owl>
WHERE
{
?s rdfs:subClassOf cy:Performer110415638
OPTION (TRANSITIVE, T_DISTINCT)
}
]]></programlisting>
<para>There are 4601 distinct subclasses, including indirect ones. Next we look at how many Shakespeare
mentions there are:
</para>
<programlisting><![CDATA[
SPARQL
SELECT COUNT (*)
WHERE
{
?s ?p ?o .
FILTER
( bif:contains (?o, 'Shakespeare') )
}
]]></programlisting>
<para>There are 10267 subjects with Shakespeare mentioned in some literal.
</para>
<programlisting><![CDATA[
SPARQL
DEFINE input:inference "yago"
PREFIX cy: <http://dbpedia.org/class/yago/>
SELECT COUNT (*)
WHERE
{
?s1 a cy:Performer110415638
}
]]></programlisting>
<para>There are 184885 individuals that belong to some subclass of performer.
</para>
<para>This is the data that the SPARQL compiler must know in order to have a valid query plan. Since
these values will wildly vary depending on the specific constants in the query, the actual database
must be consulted as needed while preparing the execution plan. This is regular query processing
technology but is now specially adapted for deep subclass and subproperty structures.
</para>
<para>Conditions in the queries are not evaluated twice, once for the cardinality estimate and once
for the actual run. Instead, the cardinality estimate is a rapid sampling of the index trees that reads
at most one leaf page.
</para>
<para>Consider a B tree index, which we descend from top to the leftmost leaf containing a match of
the condition. At each level, we count how many children would match and always select the leftmost one.
When we reach a leaf, we see how many entries are on the page. From these observations, we extrapolate
the total count of matches.
</para>
<para>With this method, the guess for the count of performers is 114213, which is acceptably close to the
real number. Given these numbers, we see that it makes sense to first find the full text matches and
then retrieve the actual classes of each and see if this class is a subclass of performer. This last
check is done against a memory resident copy of the Yago hierarchy, the same copy that was used for
enumerating the subclasses of performer.
</para>
<para>However, the query
</para>
<programlisting><![CDATA[
SPARQL
DEFINE input:inference "yago"
PREFIX cy: <http://dbpedia.org/class/yago/>
SELECT DISTINCT ?s1 AS ?c1,
( bif:search_excerpt
( bif:vector ('Shakespeare'), ?o1 )
) AS ?c2
WHERE
{
?s1 ?s1textp ?o1 .
FILTER
( bif:contains (?o1, '"Shakespeare"') ) .
?s1 a cy:ShakespeareanActors
}
]]></programlisting>
<para>will start with Shakespearean actors since this is a leaf class with only 74 instances and then
check if the properties contain Shakespeare and return their search summaries.
</para>
<para>In principle, this is common cost based optimization but is here adapted to deep hierarchies
combined with text patterns. An unmodified SQL optimizer would have no possibility of arriving at
these results.
</para>
<para>The implementation reads the graphs designated as holding ontologies when first needed and
subsequently keeps a memory based copy of the hierarchy on all servers. This is used for quick iteration
over sub/superclasses or properties as well as for checking if a given class or property is a
subclass/property of another. Triples with OWL predicates <emphasis>equivalentClass</emphasis>,
<emphasis>equivalentProperty</emphasis> and <emphasis>sameAs</emphasis> are also cached in the same data
structure if they occur in the ontology graphs.
</para>
<para>Also cardinality estimates for members of classes near the root of the class hierarchy take
some time since a sample of each subclass is needed. These are cached for some minutes in the
inference context, so that repeated queries will not redo the sampling.
</para>
</sect3>
<sect3 id="rdfiridereferencingfacetinvfpr"><title>Inverse Functional Properties and Same As</title>
<para>Specially when navigating social data, as in FOAF and SIOC spaces, there are many blank nodes that
are identified by properties only. For this, we offer an option for automatically joining to subjects
which share an IFP value with the subject being processed. For example, the query for the friends of
friends of Kjetil Kjernsmo returns empty:
</para>
<programlisting><![CDATA[
SPARQL
SELECT COUNT (?f2)
WHERE
{
?s a foaf:Person ;
?p ?o ;
foaf:knows ?f1 .
?o bif:contains "'Kjetil Kjernsmo'" .
?f1 foaf:knows ?f2
}
]]></programlisting>
<para>But with the option
</para>
<programlisting><![CDATA[
SPARQL
DEFINE input:inference "b3sifp"
SELECT COUNT (?f2)
WHERE
{
?s a foaf:Person ;
?p ?o ;
foaf:knows ?f1 .
?o bif:contains "'Kjetil Kjernsmo'" .
?f1 foaf:knows ?f2
}
]]></programlisting>
<para>we get 4022. We note that there are many duplicates since the data is blank nodes only,
with people easily represented 10 times. The context <emphasis>b3sifp</emphasis> simple declares that
<emphasis>foaf:name</emphasis> and <emphasis>foaf:mbox</emphasis> sha1sum should be treated as inverse
functional properties (IFP). The name is not an IFP in the actual sense but treating it as such for
the purposes of this one query makes sense, otherwise nothing would be found.
</para>
<para>This option is controlled by the choice of the inference context, which is selectable in the
interface discussed below.
</para>
<para>The IFP inference can be thought of as a transparent addition of a subquery into the join sequence.
The subquery joins each subject to its synonyms given by sharing IFPs. This subquery has the special
property that it has the initial binding automatically in its result set. It could be expressed as:
</para>
<programlisting><![CDATA[
SPARQL
SELECT ?f
WHERE
{
?k foaf:name "Kjetil Kjernsmo" .
{
SELECT ?org ?syn
WHERE
{
?org ?p ?key .
?syn ?p ?key .
FILTER
( bif:rdf_is_sub
( "b3sifp", ?p, <b3s:any_ifp>, 3 )
&&
?syn != ?org
)
}
}
OPTION
(
TRANSITIVE ,
T_IN (?org),
T_OUT (?syn),
T_MIN (0),
T_MAX (1)
)
FILTER
( ?org = ?k ) .
?syn foaf:knows ?f .
}
]]></programlisting>
<para>It is true that each subject shares IFP values with itself but the transitive construct with 0
minimum and 1 maximum depth allows passing the initial binding of <emphasis>?org</emphasis> directly to
<emphasis>?syn</emphasis>, thus getting first results more rapidly. The <emphasis>rdf_is_sub</emphasis>
function is an internal that simply tests whether <emphasis>?p</emphasis> is a subproperty of
<emphasis>b3s:any_ifp</emphasis>.
</para>
<para>Internally, the implementation has a special query operator for this and the internal form is more
compact than would result from the above but the above could be used to the same effect.
</para>
<para>Our general position is that identity criteria are highly application specific and thus we offer
the full spectrum of choice between run time and precomputing. Further, weaker identity statements than
sameness are difficult to use in queries, thus we prefer identity with semantics of
<emphasis>owl:sameAs</emphasis> but make this an option that can be turned on and off query by query.
</para>
</sect3>
<sect3 id="rdfiridereferencingfaceter"><title>Entity Ranking</title>
<para>It is a common end user expectation to see text search results sorted by their relevance. The term
entity rank refers to a quantity describing the relevance of a URI in an RDF graph.
</para>
<para>This is a sample query using entity rank:
</para>
<programlisting><![CDATA[
SPARQL
PREFIX yago: <http://dbpedia.org/class/yago/>
PREFIX prop: <http://dbpedia.org/property/>
SELECT DISTINCT ?s2 AS ?c1
WHERE
{
?s1 ?s1textp ?o1 .
?o1 bif:contains 'Shakespeare' .
?s1 a yago:Writer110794014 .
?s2 prop:writer ?s1
}
ORDER BY DESC ( <LONG::IRI_RANK> (?s2) )
LIMIT 20
OFFSET 0
]]></programlisting>
<para>This selects works where a writer with Shakespeare in some property is the writer.
</para>
<para>Here the query returns subjects, thus no text search summaries, so only the entity rank of the
returned subject is used. We order text results by a composite of text hit score and entity rank of the
RDF subject where the text occurs. The entity rank of the subject is defined by the count of references
to it, weighed by the rank of the referrers and the outbound link count of referrers. Such techniques
are used in text based information retrieval.
</para>
<para><emphasis>Example with Entity Ranking and Score</emphasis></para>
<programlisting><![CDATA[
## Searching over labels, with text match
## scores and additional ranks for each
## iri / resource:
SELECT ?s ?page ?label
?textScore AS ?Text_Score_Rank
( <LONG::IRI_RANK> (?s) ) AS ?Entity_Rank
WHERE
{
?s foaf:page ?page ;
rdfs:label ?label .
FILTER( lang( ?label ) = "en" ) .
?label bif:contains 'adobe and flash'
OPTION (score ?textScore ) .
}
]]></programlisting>
<para>One interesting application of entity rank and inference on IFPs and <emphasis>owl:sameAs</emphasis> is in locating
URIs for reuse. We can easily list synonym URIs in order of popularity as well as locate URIs based
on associated text. This can serve in application such as the Entity Name Server
</para>
<para>Entity ranking is one of the few operations where we take a precomputing approach. Since a rank is
calculated based on a possibly long chain of references, there is little choice but to precompute. The
precomputation itself is straightforward enough: First all outbound references are counted for all
subjects. Next all ranks of subjects are incremented by 1 over the referrer's outbound link count.
On successive iterations, the increment is based on the rank increment the referrer received in
the previous round.
</para>
<para>The operation is easily partitioned, since each partition increments the ranks of subjects it
holds. The referrers are spread throughout the cluster, though. When rank is calculated, each partition
accesses every other partition. This is done with relatively long messages, referee ranks are accessed
in batches of several thousand at a time, thus absorbing network latency.
</para>
<para>On the test system, this operation performs a single pass over the corpus of 2.2 billion triples
and 356 million distinct subjects in about 30 minutes. The operation has 100% utilization of all 16
cores. Adding hardware would speed it up, as would implementing it in C instead of the SQL procedures
it is written in at present.
</para>
<para>The main query in rank calculation is:
</para>
<programlisting><![CDATA[
SPARQL
SELECT O ,
P ,
iri_rank (S)
FROM rdf_quad TABLE
OPTION (NO CLUSTER)
WHERE isiri_id(O)
ORDER BY O
]]></programlisting>
<para>This is the SQL cursor iterated over by each partition. The no cluster option means that only rows
in this process's partition are retrieved. The RDF_QUAD table holds the RDF quads in the store, i.e.,
triple plus graph. The S, P, O columns are the subject, predicate, and object respectively. The graph
column is not used here. The textttiri rank is a partitioned SQL function. This works by using the S
argument to determine which cluster node should run the function. The specifics of the partitioning
are declared elsewhere. The calls are then batched for each intended recipient and sent when the
batches are full. The SQL compiler automatically generates the relevant control structures. This
is like an implicit map operation in the map-reduce terminology.
</para>
<para>An SQL procedure loops over this cursor, adds up the rank and when seeing a new O, the added
rank is persisted into a table. Since links in RDF are typed, we can use the semantics of the link
to determine how much rank is transferred by a reference. With extraction of named entities from
text content, we can further place a given entity into a referential context and use this as a
weighting factor. This is to be explored in future work. The experience thus far shows that we
greatly benefit from Virtuoso being a general purpose DBMS, as we can create application specific
data structures and control flows where these are efficient. For example, it would make little
sense to store entity ranks as triples due to space consumption and locality considerations. With
these tools, the whole ranking functionality took under a week to develop.
</para>
<para><emphasis>Note:</emphasis> In order to use the IRI_RANK feature you need to have the
Facet (fct) vad package installed as the procedure is part of this vad.
</para>
</sect3>
<sect3 id="rdfiridereferencingfacetqel"><title>Query Evaluation Time Limits</title>
<para>When scaling the Linked Data model, we have to take it as a given that the workload will be
unexpected and that the query writers will often be unskilled in databases. Insofar possible, we
wish to promote the forming of a culture of creative reuse of data. To this effect, even poorly
formulated questions deserve an answer that is better than just timeout.
</para>
<para>If a query produces a steady stream of results, interrupting it after a certain quota is simple.
However, most interesting queries do not work in this way. They contain aggregation, sorting, maybe
transitivity.
</para>
<para>When evaluating a query with a time limit in a cluster setup, all nodes monitor the time left
for the query. When dealing with a potentially partial query to begin with, there is little point in
transactionality. Therefore the facet service uses read committed isolation. A read committed query
will never block since it will see the before-image of any transactionally updated row. There will
be no waiting for locks and timeouts can be managed locally by all servers in the cluster.
</para>
<para>Thus, when having a partitioned count, for example, we expect all the partitions to time out
around the same time and send a ready message with the timeout information to the cluster node
coordinating the query. The condition raised by hitting a partial evaluation time limit differs
from a run time error in that it leaves the query state intact on all participating nodes. This
allows the timeout handling to come fetch any accumulated aggregates.
</para>
<para>Let us consider the query for the top 10 classes of things with "Shakespeare" in some literal.
This is typical of the workload generated by the faceted browsing web service:
</para>
<programlisting><![CDATA[
SPARQL
DEFINE input:inference "yago"
SELECT ?c
COUNT (*)
WHERE
{
?s a ?c ;
?p ?o .
?o bif:contains "Shakespeare"
}
GROUP BY ?c
ORDER BY DESC 2
LIMIT 10
]]></programlisting>
<para>On the first execution with an entirely cold cache, this times out after 2 seconds and returns:
</para>
<programlisting><![CDATA[
?c COUNT (*)
yago:class/yago/Entity100001740 566
yago:class/yago/PhysicalEntity100001930 452
yago:class/yago/Object100002684 452
yago:class/yago/Whole100003553 449
yago:class/yago/Organism100004475 375
yago:class/yago/LivingThing100004258 375
yago:class/yago/CausalAgent100007347 373
yago:class/yago/Person100007846 373
yago:class/yago/Abstraction100002137 150
yago:class/yago/Communicator109610660 125
]]></programlisting>
<para>
The next repeat gets about double the counts, starting with 1291 entities.
</para>
<para>With a warm cache, the query finishes in about 300 ms (4 core Xeon, Virtuoso 6 Cluster) and returns:
</para>
<programlisting><![CDATA[
?c COUNT (*)
yago:class/yago/Entity100001740 13329
yago:class/yago/PhysicalEntity100001930 10423
yago:class/yago/Object100002684 10408
yago:class/yago/Whole100003553 10210
yago:class/yago/LivingThing100004258 8868
yago:class/yago/Organism100004475 8868
yago:class/yago/CausalAgent100007347 8853
yago:class/yago/Person100007846 8853
yago:class/yago/Abstraction100002137 3284
yago:class/yago/Entertainer109616922 2356
]]></programlisting>
<para>It is a well known fact that running from memory is thousands of times faster than from disk.
</para>
<para>The query plan begins with the text search. The subjects with "Shakespeare" in some property get
dispatched to the partition that holds their class. Since all partitions know the class hierarchy,
the superclass inference runs in parallel, as does the aggregation of the group by. When all
partitions have finished, the process coordinating the query fetches the partial aggregates,
adds them up and sorts them by count.
</para>
<para>If a timeout occurs, it will most likely occur where the classes of the text matches are being
retrieved. When this happens, this part of the query is reset, but the aggregate states are left
in place. The process coordinating the query then goes on as if the aggregates had completed. If
there are many levels of nested aggregates, each timeout terminates the innermost aggregation that
is still accumulating results, thus a query is guaranteed to return in no more than n timeouts,
where n is the number of nested aggregations or subqueries.
</para>
</sect3>
<sect3 id="rdfiridereferencingfacetws"><title>Facets Web Service and Linked Data</title>
<para>The Virtuoso Facets web service is a general purpose RDF query facility for facet based browsing.
It takes an XML description of the view desired and generates the reply as an XML tree containing the
requested data. The user agent or a local web page can use XSLT for rendering this for the end user.
The selection of facets and values is represented as an XML tree. The rationale for this is the fact
that such a representation is easier to process in an application than the SPARQL source text or a
parse tree of SPARQL and more compactly captures the specific subset of SPARQL needed for faceted
browsing. All such queries internally generate SPARQL and the SPARQL generated is returned with
the results. One can therefore use this is a starting point for hand crafted queries.
</para>
<para>The query has the top level element. The child elements of this represents conditions pertaining
to a single subject. A join is expressed with the property or propertyof element. This has in turn
children which state conditions on a property of the first subject. Property and propertyof elements
can be nested to an arbitrary depth and many can occur inside one containing element. In this way,
tree-shaped structures of joins can be expressed.
</para>
<para>Expressing more complex relationships, such as intermediate grouping, subqueries, arithmetic or
such requires writing the query in SPARQL. The XML format is for easy automatic composition of queries
needed for showing facets, not a replacement for SPARQL.
</para>
<para>Consider composing a map of locations involved with Napoleon. Below we list user actions and
the resulting XML query descriptions.
</para>
<itemizedlist mark="bullet">
<listitem>Enter in the search form "Napoleon":
<programlisting><![CDATA[
<query inference="" same-as="" view3="" s-term="e" c-term="type">
<text>napoleon</text>
<view type="text" limit="20" offset="" />
</query>
]]></programlisting>
</listitem>
<listitem>Select the "types" view:
<programlisting><![CDATA[
<query inference="" same-as="" view3="" s-term="e" c-term="type">
<text>napoleon</text>
<view type="classes" limit="20" offset="0" location-prop="0" />
</query>
]]></programlisting>
</listitem>
<listitem>Choose "MilitaryConflict" type:
<programlisting><![CDATA[
<query inference="" same-as="" view3="" s-term="e" c-term="type">
<text>napoleon</text>
<view type="classes" limit="20" offset="0" location-prop="0" />
<class iri="yago:ontology/MilitaryConflict" />
</query>
]]></programlisting>
</listitem>
<listitem>Choose "NapoleonicWars":
<programlisting><![CDATA[
<query inference="" same-as="" view3="" s-term="e" c-term="type">
<text>napoleon</text>
<view type="classes" limit="20" offset="0" location-prop="0" />
<class iri="yago:ontology/MilitaryConflict" />
<class iri="yago:class/yago/NapoleonicWars" />
</query>
]]></programlisting>
</listitem>
<listitem>Select "any location" in the select list beside the "map" link; then hit "map" link:
<programlisting><![CDATA[
<query inference="" same-as="" view3="" s-term="e" c-term="type">
<text>napoleon</text>
<class iri="yago:ontology/MilitaryConflict" />
<class iri="yago:class/yago/NapoleonicWars" />
<view type="geo" limit="20" offset="0" location-prop="any" />
</query>
]]></programlisting>
</listitem>
</itemizedlist>
<para>This last XML fragment corresponds to the below text of SPARQL query:
</para>
<programlisting><![CDATA[
SPARQL
SELECT ?location AS ?c1
?lat1 AS ?c2
?lng1 AS ?c3
WHERE
{
?s1 ?s1textp ?o1 .
FILTER
( bif:contains (?o1, '"Napoleon"') ) .
?s1 a <yago:ontology/MilitaryConflict> .
?s1 a <yago:class/yago/NapoleonicWars> .
?s1 ?anyloc ?location .
?location geo:lat ?lat1 ;
geo:long ?lng1
}
LIMIT 200
OFFSET 0
]]></programlisting>
<para>
The query takes all subjects with some literal property with "Napoleon" in it, then filters for
military conflicts and Napoleonic wars, then takes all objects related to these where the related
object has a location. The map has the objects and their locations.
</para>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="virtuosospongerfacent">Virtuoso Facets Web Service</link></listitem>
<listitem><link linkend="virtuosospongerfacentuirestapi">Virtuoso APIs for Facet REST services</link></listitem>
</itemizedlist>
</tip>
</sect3>
<sect3 id="rdfiridereferencingfacetvd"><title>voiD Discoverability</title>
<para>A long awaited addition to the LOD cloud is the Vocabulary of Interlinked Data (voiD).
Virtuoso automatically generates voiD descriptions of data sets it hosts. Virtuoso incorporates an
SQL function <emphasis>rdf_void_gen</emphasis> which returns a Turtle representation of a given
graph's voiD statistics.
</para>
</sect3>
<sect3 id="rdfiridereferencingfacet"><title>Test System and Data</title>
<para>The test system consists of two 2x4 core Xeon 5345, 2.33 GHz servers with 16G RAM and 4 disks
each. The machines are connected by two 1Gbit Ethernet connections. The software is Virtuoso 6
Cluster. The Virtuoso server is split into 16 partitions, 8 for each machine. Each partition is
managed by a separate server process.
</para>
<para>The test database has the following data sets:
</para>
<itemizedlist mark="bullet">
<listitem>DBpedia 3.2</listitem>
<listitem>MusicBrainz</listitem>
<listitem>Bio2RDF</listitem>
<listitem>NeuroCommons</listitem>
<listitem>UniProt</listitem>
<listitem>Freebase (95M triples)</listitem>
<listitem>PingTheSemanticWeb (1.6M miscellaneous files from http://www.pingthesemanticweb.com/).</listitem>
</itemizedlist>
<para>Ontologies:
</para>
<itemizedlist mark="bullet">
<listitem>Yago</listitem>
<listitem>OpenCyc</listitem>
<listitem>Umbel</listitem>
<listitem>DBpedia</listitem>
</itemizedlist>
<para>The database is 2.2 billion triples with 356 million distinct URIs.
</para>
</sect3>
</sect2>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="virtuosospongerfacetinstall">Virtuoso Facet Browser Installation and configuration</link></listitem>
</itemizedlist>
</tip>
</sect1>
<sect1 id="rdfsparqlrule"><title>Inference Rules & Reasoning</title>
<sect2 id="rdfsparqlruleintro"><title>Introduction</title>
<para>Virtuoso SPARQL can use an inference context for inferring triples that are not physically stored.
This functionality applies to physically stored quads and not to virtual triples generated from relational data with RDF views.
Such an inference context can be built from one or more graphs containing RDF Schema triples. The supported
RDF Schema or OWL constraints are imported from these graphs and are grouped together into rule bases.
A rule base is a persistent entity that can be referenced by a SPARQL query or end point. Queries running
with a given rule base work as if the triples asserted by this rule base were included in the graph or graphs accessed by the query.
</para>
<para>As of version 5.0, Virtuoso recognizes <emphasis>rdfs:subClassOf</emphasis> and <emphasis>rdfs:subPropertyOf</emphasis>.
owl:sameAs is considered for arbitrary subjects and objects if specially enabled by a pragma in the query.
As of 5.00.3031, owl:sameAs, owl:equivalentClass and owl:equivalentProperty are also considered when determining subclass or subproperty relations. If two classes are equivalent, they share all instances, subclasses and superclasses directly or indirectly stated in the data for either class.
Other RDF Schema or OWL information is not taken into account.
</para>
</sect2>
<sect2 id="rdfsparqlrulemake"><title>Making Rule Sets</title>
<para>Since RDF Schema and OWL schemas are RDF graphs, these can be loaded into the triple store. Thus, in order to use
such a schema as query context, one first loads the corresponding document into the triple store using <emphasis>ttlp</emphasis> or
<emphasis>rdf_load_rdfxml</emphasis> or related functions. After the schema document is loaded, one can add the assertions therein
into an inference context with the <emphasis>rdfs_rule_set</emphasis> function. This function specifies a logical name for the rule
set plus a graph URI. It is possible to combine multiple schema graphs into a single rule set. A single schema
graph may also independently participate in multiple rule sets.
</para>
<programlisting>
rdfs_rule_set (in name varchar, in uri varchar, in remove int := 0)
</programlisting>
<para>This function adds the applicable facts of the graph into a rule set. The graph URI must correspond
to the graph IRI of a graph stored in the triple store of the Virtuoso instance. If the remove argument
is true, the specified graph is removed from the rule set instead.
</para>
</sect2>
<sect2 id="rdfsparqlrulechange"><title>Changing Rule Sets</title>
<para>Changing a rule set affects queries made after the change. Some queries may have been previously
compiled and will not be changed as a result of modifying the rule set. When a rule set is changed, i.e.
when <emphasis>rdfs_rule_set</emphasis> is called with the first argument set to a pre-existing rule set's name, all the graphs
associated with this name are read and the relevant facts are added to a new empty rule set. Thus, if
triples are deleted from or added to the graphs comprising the rule set, calling <emphasis>rdfs_rule_set</emphasis> will refresh
the rule set to correspond to the state of the stored graphs.
</para>
</sect2>
<sect2 id="rdfsparqlrulesubclassandsubprop"><title>Subclasses and Subproperties</title>
<para>Virtuoso SPARQL supports RDF Schema subclasses and subproperties.
</para>
<para>The predicates <emphasis>rdfs:subClassOf</emphasis> and <emphasis>rdfs:subPropertyOf</emphasis> are
recognized when they appear in graphs included in a rule set. When such a rule set is specified as a context
for a SPARQL query, the following extra triples are generated as needed.
</para>
<para>For every <emphasis>?s rdf:type ?class</emphasis>, a triple <emphasis>?s rdf:type ?superclass</emphasis> is considered to exist,
such that <emphasis>?superclass</emphasis> is a direct or indirect superclass of <emphasis>?class</emphasis>. Direct superclasses are
declared with the <emphasis>rdfs:subClassOf</emphasis> predicate in the rule set graph. Transitivity of superclasses
is automatically taken into account, meaning that if a is a superclass of b and b a superclass of c,
then a is a superclass of c also. Cyclic superclass relations are not allowed. If such occur in the rule set data,
the behavior is undefined but will not involve unterminating recursion.
</para>
<para>For every <emphasis>?s ?subpredicate ?o</emphasis>, a triple <emphasis>?s ?superpredicate ?o</emphasis>
is considered to exist if the rule context declares <emphasis>?superpredicate</emphasis> to be a superpredicate
of <emphasis>?predicate</emphasis>. This is done by having the triple <emphasis>?subpredicate rdfs:subPropertyOf ?superpredicate</emphasis>
as part of the graphs making up the rule context. Transitivity is observed, thus if a is a subpredicate of b and b
a subpredicate of c, then a is also a subpredicate of c.
</para>
</sect2>
<sect2 id="rdfsameas"><title>OWL sameAs Support</title>
<para>
Virtuoso has limited support for the OWL sameAs predicate.
</para>
<para>
If sameAs traversal is enabled and a triple pattern with a given
subject or object is being matched, all the synonyms of the S and O
will be tried and results generated for all the tried bindings of S
and O. The set of synonyms is generated at run time by following all
owl:sameAs triples where the IRI in question is either the subject or
the object. These are followed recursively from object to subject and
subject to object until the complete transitive closure is generated.
All sameAs triples from all the graphs applicable to instantiating
the triple pattern at hand are considered.
</para>
<para>
Thus for example:
</para>
<para>The inital SPARQL query:</para>
<programlisting><![CDATA[
SQL>SPARQL
prefix foaf: <http://xmlns.com/foaf/0.1/>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix sioc: <http://rdfs.org/sioc/ns#>
SELECT *
from <http://myopenlink.net/dataspace>
where
{
?person a foaf:Person FILTER REGEX(?person ,"http://myopenlink.net/dataspace/person/kidehen#this").
?person foaf:name ?name .
?person owl:sameAs ?sameas .
}
limit 10;
person name sameas
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com#this
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://my.openlinksw.com/dataspace/person/kidehen@openlinksw.com#this
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://kidehen.idehen.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://qdos.com/user/e922b748a2eb667bf37b188018002dec
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://knowee.net/kidehen/ids/id3684976382
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://dbpedia.org/resource/Kingsley_Idehen
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://dbtune.org/last-fm/kidehen
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://revyu.com/people/kidehen
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://identi.ca/user/14092
http://myopenlink.net/dataspace/person/kidehen#this Kingsley Idehen http://myopenlink.net/proxy?url=http%3A%2F%2Fwww.facebook.com%2Fpeople%2FKingsley_Idehen%2F605980750&force=rdf&login=kidehen
10 Rows. -- 181 msec.
]]></programlisting>
<para>So if we have:</para>
<programlisting><![CDATA[
<http://myopenlink.net/dataspace/person/kidehen#this> <http://www.w3.org/2002/07/owl#sameAs> <http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com#this> .
<http://myopenlink.net/dataspace/person/kidehen#this> <http://xmlns.com/foaf/0.1/name> Kingsley Idehen
]]></programlisting>
<para>
and we instantiate <emphasis>?s <http://xmlns.com/foaf/0.1/name> "Kingsley Idehen"</emphasis>
we get <emphasis>?s</emphasis> bound to <emphasis><http://myopenlink.net/dataspace/person/kidehen#this></emphasis>.
</para>
<para>
If we instantiate <emphasis><http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com#this>
<http://xmlns.com/foaf/0.1/name> ?l</emphasis>
we get <emphasis>?l</emphasis> bound to <emphasis>"Kingsley Idehen"</emphasis> because the subject was given and it was expanded to its synonyms.
</para>
<para>
If binding a variable in a pattern where the variable was free, we do not expand the value to the complete set of its synonyms.
</para>
<para>
Same-as expansion is enabled in a query by <emphasis>define input:same-as "yes"</emphasis> in the beginning of the SPARQL query.
This has a significant run time cost but is in some cases useful when joining data between sets which are mapped to each other with same-as.
</para>
<para>
We note that the number of same-as expansions will depend on the join order used for the SPARQL query.
The compiler does not know the number of synonyms and cannot set the join order accordingly.
Regardless of the join order we will however get at least one IRI of the each synonym set as answer.
Also when interactively navigating a graph with a browser, the same-as expansion will take all synonyms into account.
</para>
<para>
For getting the complete entailment of same-as, a forward
chaining approach should be used, effectively asserting all the
implied triples.
</para>
<sect3 id="rdfsameasexmp"><title>OWL sameAs Example</title>
<programlisting><![CDATA[
SQL>SPARQL
DEFINE input:same-as "yes"
SELECT *
WHERE
{
?s <http://xmlns.com/foaf/0.1/name> "Kingsley Idehen" .
}
LIMIT 10;
s
VARCHAR
___________________________________________________
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
http://demo.openlinksw.com/dataspace/kingsley#person
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
http://myopenlink.net/dataspace/person/kidehen#this
No. of rows in result: 10
]]></programlisting>
</sect3>
</sect2>
<sect2 id="rdfsparqlruleintro"><title>Implementation</title>
<para>Triples entailed by subclass or subproperty statements in an inference context are not physically stored.
Such triples are added to the result set by the query run time as needed. Also queries involving subclass or subproperty
rules are not rewritten into unions of all the possible triple patterns that might imply the pattern that is requested.
Instead, the SQL compiler adds special nodes that iterate over subclasses or subproperties at run time. The cost model
also takes subclasses and subproperties into account when determining the approximate cardinality of triple patterns.
</para>
<para>In essence, Virtuoso's support for subclasses and subproperties is backward chaining, i.e. it does not materialize
all implied triples but rather looks for the basic facts implying these triples at query evaluation time.
</para>
</sect2>
<sect2 id="rdfsparqlruleintro"><title>Enabling Inferencing</title>
<para>In a SPARQL query, the define input:inference clause is used to instruct the compiler to use the rules in the named rule set. For example:
</para>
<programlisting>
SQL> rdfs_rule_set ('sample', 'rule_graph');
SQL> SPARQL
define input:inference "sample"
SELECT *
FROM <g>
WHERE {?s ?p ?o};
</programlisting>
<para>will include all the implied triples in the result set, using the rules in the sample rule set.
</para>
<para>Inference can be enabled triple pattern by triple pattern. This is done with the option
(inference 'rule_set') clause after the triple pattern concerned. Specifying option (inference none)
will disable inference for the pattern concerned while the default inference context applies to the
rest of the patterns. Note that the keyword is input:inference in the query header and simply inference
in the option clause. See the examples section below for examples.
</para>
<para>In SQL, if RDF_QUAD occurs in a select from clause, inference can be added with the table option <emphasis>WITH</emphasis>, as follows:
</para>
<programlisting>
SPARQL
SELECT *
FROM rdf_quad table OPTION (with 'sample')
WHERE g = iri_to_id ('xx', 0);
</programlisting>
<para>This is about the same as:
</para>
<programlisting>
SPARQL
define input:inference "sample"
SELECT *
FROM <xx>
WHERE {?s ?p ?o}
</programlisting>
</sect2>
<sect2 id="rdfsparqlruleexamples"><title>Examples</title>
<sect3 id="rdfsparqlruleexamples1"><title>Example for loading data space instance data Triples
into a Named Graph for schema/ontology data</title>
<para>The following example shows how to load data space instance data Triples
into a Named Graph: <http://localhost:8890/test>, for schema/ontology data called:
<http://localhost:8890/schema/test> that expresses assertions about subclasses and
subproperties.</para>
<programlisting><![CDATA[
ttlp ('
<http://localhost:8890/dataspace> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#Space>.
<http://localhost:8890/dataspace/test2/weblog/test2tWeblog> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/types#Weblog> .
<http://localhost:8890/dataspace/discussion/oWiki-test1Wiki> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/types#MessageBoard>.
<http://localhost:8890/dataspace> <http://rdfs.org/sioc/ns#link> <http://localhost:8890/ods> .
<http://localhost:8890/dataspace/test2/weblog/test2tWeblog> <http://rdfs.org/sioc/ns#link> <http://localhost:8890/dataspace/test2/weblog/test2tWeblog>.
<http://localhost:8890/dataspace/discussion/oWiki-test1Wiki> <http://rdfs.org/sioc/ns#link> <http://localhost:8890/dataspace/discussion/oWiki-test1Wiki> .
', '', 'http://localhost:8890/test');
]]></programlisting>
<programlisting><![CDATA[
ttlp (' @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://rdfs.org/sioc/ns#Space> rdfs:subClassOf <http://www.w3.org/2000/01/rdf-schema#Resource> .
<http://rdfs.org/sioc/ns#Container> rdfs:subClassOf <http://rdfs.org/sioc/ns#Space> .
<http://rdfs.org/sioc/ns#Forum> rdfs:subClassOf <http://rdfs.org/sioc/ns#Container> .
<http://rdfs.org/sioc/types#Weblog> rdfs:subClassOf <http://rdfs.org/sioc/ns#Forum> .
<http://rdfs.org/sioc/types#MessageBoard> rdfs:subClassOf <http://rdfs.org/sioc/ns#Forum> .
<http://rdfs.org/sioc/ns#link> rdfs:subPropertyOf <http://rdfs.org/sioc/ns> .
', '', 'http://localhost:8890/schema/test');
]]></programlisting>
<programlisting>
rdfs_rule_set ('http://localhost:8890/schema/property_rules1', 'http://localhost:8890/schema/test');
</programlisting>
<para>This defines the rule context http://localhost:8890/schema/property_rules1 that is initialized
from the contents of graph http://localhost:8890/schema/test.
</para>
<programlisting><![CDATA[
SQL>SPARQL
define input:inference "http://localhost:8890/schema/property_rules1"
SELECT ?s
FROM <http://localhost:8890/test>
WHERE {?s <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://rdfs.org/sioc/ns#Space> };
s
VARCHAR
_______________________________________________________________________________
http://localhost:8890/dataspace/test2/weblog/test2tWeblog
http://localhost:8890/dataspace/discussion/oWiki-test1Wiki
http://localhost:8890/dataspace
3 Rows. -- 0 msec.
]]></programlisting>
<para>This returns the instances of http://rdfs.org/sioc/ns#Space. Since http://rdfs.org/sioc/types#Weblog
and http://rdfs.org/sioc/types#MessageBoard are subclasses of http://rdfs.org/sioc/ns#Space,
instances of http://rdfs.org/sioc/ns#Space, http://rdfs.org/sioc/types#Weblog and
http://rdfs.org/sioc/types#MessageBoard are all returned. This results in the subjects
http://localhost:8890/dataspace, http://localhost:8890/dataspace/test2/weblog/test2tWeblog and
http://localhost:8890/dataspace/discussion/oWiki-test1Wiki.
</para>
<programlisting><![CDATA[
SQL>SELECT id_to_iri (s)
FROM rdf_quad table option (with 'http://localhost:8890/schema/property_rules1')
WHERE g = iri_to_id ('http://localhost:8890/test',0)
AND p = iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 0)
AND o = iri_to_id ('http://rdfs.org/sioc/ns#Space', 0);
callret
VARCHAR
_______________________________________________________________________________
http://localhost:8890/dataspace/test2/weblog/test2tWeblog
http://localhost:8890/dataspace/discussion/oWiki-test1Wiki
http://localhost:8890/dataspace
3 Rows. -- 10 msec.
]]></programlisting>
<para>This is the corresponding SQL query, internally generated by the SPARQL query.</para>
<para>Below we first look for all instances of http://rdfs.org/sioc/ns#Space with some
property set to http://localhost:8890/dataspace/test2/weblog/test2tWeblog.
We get the subject http://localhost:8890/dataspace/test2/weblog/test2tWeblog and the
properties http://rdfs.org/sioc/ns#link and http://rdfs.org/sioc/ns.
The join involves both subclass and subproperty inference. Then we turn off the inference
for the second pattern and only get the property http://rdfs.org/sioc/ns#link. Then we do
the same but now specify that inference should apply only to the first triple pattern.
</para>
<programlisting><![CDATA[
SQL>SPARQL
define input:inference "http://localhost:8890/schema/property_rules1"
SELECT *
FROM <http://localhost:8890/test>
WHERE
{
?s ?p <http://rdfs.org/sioc/ns#Space> .
?s ?p1 <http://localhost:8890/dataspace/test2/weblog/test2tWeblog> .
};
s p p1
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://localhost:8890/dataspace/test2/weblog/test2tWeblog http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://rdfs.org/sioc/ns#link
http://localhost:8890/dataspace/test2/weblog/test2tWeblog http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://rdfs.org/sioc/ns
2 Rows. -- 0 msec.
SQL>SPARQL
SELECT *
FROM <http://localhost:8890/test>
WHERE
{
?s ?p <http://rdfs.org/sioc/ns#Space> OPTION (inference 'http://localhost:8890/schema/property_rules1') .
?s ?p1 <http://localhost:8890/dataspace/test2/weblog/test2tWeblog> .
};
s p p1
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://localhost:8890/dataspace/test2/weblog/test2tWeblog http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://rdfs.org/sioc/ns#link
1 Rows. -- 10 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleexamples2"><title>DBpedia example</title>
<programlisting><![CDATA[
ttlp ('
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
<http://dbpedia.org/property/birthcity> rdfs:subPropertyOf <http://dbpedia.org/property/birthPlace> .
<http://dbpedia.org/property/birthcountry> rdfs:subPropertyOf <http://dbpedia.org/property/birthPlace> .
<http://dbpedia.org/property/cityofbirth> rdfs:subPropertyOf <http://dbpedia.org/property/birthPlace> .
<http://dbpedia.org/property/countryofbirth> rdfs:subPropertyOf <http://dbpedia.org/property/birthPlace> .
<http://dbpedia.org/property/countyofbirth> rdfs:subPropertyOf <http://dbpedia.org/property/birthPlace> .
<http://dbpedia.org/property/cityofdeath> rdfs:subPropertyOf <http://dbpedia.org/property/deathPlace> .
<http://dbpedia.org/property/countryofdeath> rdfs:subPropertyOf <http://dbpedia.org/property/deathPlace> . ', '',
'http://dbpedia.org/inference/rules#') ;
rdfs_rule_set ('http://dbpedia.org/schema/property_rules1', 'http://dbpedia.org/inference/rules#');
]]></programlisting>
<programlisting><![CDATA[
SQL>SPARQL
define input:inference "http://dbpedia.org/schema/property_rules1"
prefix p: <http://dbpedia.org/property/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE {?s p:birthcity ?o }
LIMIT 50
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Britt_Janyk
http://dbpedia.org/resource/Chiara_Costazza
http://dbpedia.org/resource/Christoph_Gruber
http://dbpedia.org/resource/Daron_Rahlves
http://dbpedia.org/resource/Finlay_Mickel
http://dbpedia.org/resource/Genevi%C3%A8ve_Simard
http://dbpedia.org/resource/Johann_Grugger
http://dbpedia.org/resource/Kalle_Palander
http://dbpedia.org/resource/Marc_Gini
http://dbpedia.org/resource/Mario_Scheiber
http://dbpedia.org/resource/Prince_Hubertus_of_Hohenlohe-Langenburg
http://dbpedia.org/resource/Resi_Stiegler
http://dbpedia.org/resource/Steven_Nyman
http://dbpedia.org/resource/Hannes_Reichelt
http://dbpedia.org/resource/Jeremy_Transue
15 Rows. -- 167 msec.
SQL>SPARQL
define input:inference "http://dbpedia.org/schema/property_rules1"
prefix p: <http://dbpedia.org/property/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE {?s p:countryofbirth ?o }
LIMIT 50
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/A._J._Wood
http://dbpedia.org/resource/A._J._Godbolt
http://dbpedia.org/resource/Ac%C3%A1cio_Casimiro
http://dbpedia.org/resource/Adam_Fry
http://dbpedia.org/resource/Adam_Gilchrist
http://dbpedia.org/resource/Adam_Griffin
http://dbpedia.org/resource/Adam_Gross
...
50 Rows. -- 324 msec.
SQL>SPARQL
define input:inference "http://dbpedia.org/schema/property_rules1"
prefix p: <http://dbpedia.org/property/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE {?s p:countyofbirth ?o }
LIMIT 50
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Eddie_Colman
1 Rows. -- 163 msec.
SQL>SPARQL
define input:inference "http://dbpedia.org/schema/property_rules1"
prefix p: <http://dbpedia.org/property/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE {?s p:birthPlace ?o }
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Eddie_Colman
http://dbpedia.org/resource/Jeremy_Transue
http://dbpedia.org/resource/Finlay_Mickel
http://dbpedia.org/resource/Prince_Hubertus_of_Hohenlohe-Langenburg
http://dbpedia.org/resource/Hannes_Reichelt
http://dbpedia.org/resource/Johann_Grugger
http://dbpedia.org/resource/Chiara_Costazza
...
155287 Rows. -- 342179 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleexamples3"><title>Example for loading script of the Yago Class hierarchy as inference rules</title>
<programlisting><![CDATA[
--- Load Class Hierarchy into a Named Graph
SELECT ttlp_mt (file_to_string_output ('yago-class-hierarchy_en.nt'),
'', 'http://dbpedia.org/resource/classes/yago#');
-- Create an Inference Rule that references the Yago Class Hierarchy
Named Graph
SQL>rdfs_rule_set ('http://dbpedia.org/resource/inference/rules/yago#',
'http://dbpedia.org/resource/classes/yago#');
-- Query for the "The Lord of the Rings" which is a "Fantasy Novel" as explicitly
-- claimed in the DBpedia data set (instance data)
SQL>SPARQL
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dbpedia: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE
{
?s a <http://dbpedia.org/class/yago/FantasyNovels> .
?s dbpedia:name "The Lord of the Rings"@en .
};
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/The_Lord_of_the_Rings
1 Rows. -- 241 msec.
-- Query aimed at Novel via query scoped to the "Fiction" class of
-- which it is a subclass in the Yago Hierarchy
SQL>SPARQL
define input:inference "http://dbpedia.org/resource/inference/rules/yago#"
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dbpedia: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE {
?s a <http://dbpedia.org/class/yago/Fiction106367107> .
?s dbpedia:name "The Lord of the Rings"@en .
};
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/The_Lord_of_the_Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings
4 Rows. -- 4767 msec.
-- # Variant of query with Virtuoso's Full Text Index extension: bif:contains
SQL>SPARQL
define input:inference "http://dbpedia.org/resource/inference/rules/yago#"
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dbpedia: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?s ?n
FROM <http://dbpedia.org>
WHERE {
?s a <http://dbpedia.org/class/yago/Fiction106367107> .
?s dbpedia:name ?n .
?n bif:contains 'Lord and Rings'
};
s n
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/The_Lord_of_the_Rings The Lord of the Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings The Lord of the Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings The Lord of the Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings The Lord of the Rings
4 Rows. -- 5538 msec.
-- Retrieve all individuals instances of the FantasyNovels Class
SQL>SPARQL
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dbpedia: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?s ?n
FROM <http://dbpedia.org>
WHERE
{
?s a <http://dbpedia.org/class/yago/FantasyNovels> .
?s dbpedia:name ?n .
}
limit 10;
s n
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/ATLA_-_A_Story_of_the_Lost_Island Atla
http://dbpedia.org/resource/A_Crown_of_Swords A Crown of Swords
http://dbpedia.org/resource/A_Game_of_Thrones A Game of Thrones
http://dbpedia.org/resource/A_Secret_Atlas A Secret Atlas
http://dbpedia.org/resource/A_Storm_of_Swords A Storm of Swords
http://dbpedia.org/resource/A_Voyage_to_Arcturus A Voyage to Arcturus
http://dbpedia.org/resource/A_Wizard_Alone A Wizard Alone
http://dbpedia.org/resource/Above_the_Veil Above the Veil
http://dbpedia.org/resource/Black_Easter Black Easter
http://dbpedia.org/resource/Lord_of_Chaos Lord of Chaos
10 Rows. -- 781 msec.
-- Retrieve all individuals instances of Fiction Class which should
-- include all Novels.
SQL>SPARQL
define input:inference "http://dbpedia.org/resource/inference/rules/yago#"
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dbpedia: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?s ?n
FROM <http://dbpedia.org>
WHERE {
?s a <http://dbpedia.org/class/yago/Fiction106367107> .
?s dbpedia:name ?n .
};
s n
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Last_Son_of_Krypton Last Son of Krypton
http://dbpedia.org/resource/Tuvaluan_language Tuvaluan
http://dbpedia.org/resource/Card_Walker E. Cardon Walker
http://dbpedia.org/resource/Les_Clark Les Clark
http://dbpedia.org/resource/Marc_Davis Marc Davis
http://dbpedia.org/resource/Eric_Larson Eric Larson
http://dbpedia.org/resource/Marty_Sklar Marty Sklar
http://dbpedia.org/resource/Peter_Ellenshaw Peter Ellenshaw
http://dbpedia.org/resource/Adriana_Caselotti Adriana Caselotti
http://dbpedia.org/resource/Jimmie_Dodd Jimmie Dodd
...
15296 Rows.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleexamples4"><title>Pure SPARQL Example</title>
<programlisting><![CDATA[
-- Query aimed at Fantasy Novel via query scoped to the "Fiction" class of
-- which it is a subclass in the Yago Hierarchy
SQL>SPARQL
define input:inference "http://dbpedia.org/resource/inference/rules/yago#"
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX dbpedia: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?s
FROM <http://dbpedia.org>
WHERE {
?s a <http://dbpedia.org/class/yago/Fiction106367107> .
?s dbpedia:name "The Lord of the Rings"@en .
};
s
VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/The_Lord_of_the_Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings
http://dbpedia.org/resource/The_Lord_of_the_Rings
4 Rows. -- 150 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleexamples5"><title>Example for equivalence between classes</title>
<para>This example is based on <ulink url="http://umbel.org/documentation.html">UMBEL</ulink> and
DBpedia integration:</para>
<programlisting><![CDATA[
-- Load UMBEL & DBpedia Instance Level Cross-Links (owl:sameAs) Triples
SELECT ttlp_mt (file_to_string_output ('umbel_dbpedia_linkage_v071.n3'), '', 'http://dbpedia.org');
-- Load UMBEL and DBpedia Type (rdf:type) association Triples
SELECT ttlp_mt (file_to_string_output ('umbel_dbpedia_types_v071.n3'), '', 'http://dbpedia.org');
--- Load UMBEL Subject Concept Class Hierarchy into a Named Graph
SELECT ttlp_mt (file_to_string_output ('umbel_class_hierarchy_v071.n3'), '', 'http://dbpedia.org/resource/classes/umbel#');
--- load UMBEL Subject Concepts Instance Data
SELECT ttlp_mt (file_to_string_output ('umbel_subject_concepts.n3'), '', 'http://dbpedia.org/resource/classes/umbel#');
--- Load UMBEL Abstract Concepts Instance Data
SELECT ttlp_mt (file_to_string_output ('umbel_abstract_concepts.n3'), '', 'http://dbpedia.org/resource/classes/umbel#');
-- Load UMBEL External Ontology Mapping into a Named Graph
SELECT ttlp_mt (file_to_string_output ('umbel_external_ontologies_linkage.n3'), '', 'http://dbpedia.org/resource/classes/umbel#');
-- Create UMBEL Inference Rules
rdfs_rule_set ('http://dbpedia.org/resource/inference/rules/umbel#', 'http://dbpedia.org/resource/classes/umbel#');
]]></programlisting>
<para>Now let's execute the following queries:</para>
<programlisting><![CDATA[
SQL>SPARQL define input:inference "http://dbpedia.org/resource/inference/rules/umbel#"
prefix umbel: <http://umbel.org/umbel/sc/>
PREFIX dbpedia: <http://dbpedia.org/property/>
prefix opencyc: <http://sw.opencyc.org/2008/06/10/concept/en/>
SELECT ?s
where
{
?s a opencyc:Motorcycle.
?s dbpedia:name ?n.
?n bif:contains "BMW".
};
s
____________________________________________
http://dbpedia.org/resource/BMW_K1200GT
http://dbpedia.org/resource/BMW_F650CS
http://dbpedia.org/resource/BMW_C1
http://dbpedia.org/resource/BMW_R75
4 Rows. -- 26 msec.
]]></programlisting>
<programlisting><![CDATA[
SQL>SPARQL define input:inference "http://dbpedia.org/resource/inference/rules/umbel#"
prefix umbel: <http://umbel.org/umbel/sc/>
PREFIX dbpedia: <http://dbpedia.org/property/>
prefix opencyc: <http://sw.opencyc.org/2008/06/10/concept/en/>
SELECT ?s
where
{
?s a umbel:Motorcycle.
?s dbpedia:name ?n.
?n bif:contains "BMW".
};
s
____________________________________________
http://dbpedia.org/resource/BMW_K1200GT
http://dbpedia.org/resource/BMW_F650CS
http://dbpedia.org/resource/BMW_C1
http://dbpedia.org/resource/BMW_R75
4 Rows. -- 26 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleexamples6"><title>Example for finding celebrities which are not fans of their own fans</title>
<programlisting><![CDATA[
SQL>SPARQL
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX sioc: <http://rdfs.org/sioc/ns#>
INSERT INTO GRAPH <urn:rules.skos> { foaf:knows rdfs:subPropertyOf sioc:follows . };
callret-0
VARCHAR
Insert into <urn:rules.skos>, 1 triples -- done
No. of rows in result: 1
SQL>rdfs_rule_set ('foaf-trans', 'urn:rules.skos');
Done.
SPARQL>SPARQL
DEFINE input:inference "foaf-trans"
PREFIX sioc: <http://rdfs.org/sioc/ns#>
SELECT ?celeb COUNT (*)
WHERE
{
?claimant sioc:follows ?celeb .
FILTER
(
!bif:exists
(
( SELECT (1)
WHERE
{
?celeb sioc:follows ?claimant
}
)
)
)
}
GROUP BY ?celeb
ORDER BY DESC 2
LIMIT 10
celeb callret-1
ANY ANY
__________________________________________________________________________________________
http://localhost.localdomain/about/id/entity/http/twitter.com/kidehen 100
http://localhost.localdomain/about/id/entity/http/twitter.com/shawnafennell 77
http://localhost.localdomain/about/id/entity/http/twitter.com/thines01 71
http://localhost.localdomain/about/id/entity/http/twitter.com/mhausenblas 50
http://localhost.localdomain/about/id/entity/http/twitter.com/DirDigEng 2
http://localhost.localdomain/about/id/entity/http/twitter.com/SarahPalinUSA 1
http://localhost.localdomain/about/id/entity/http/twitter.com/zbrox 1
http://localhost.localdomain/about/id/entity/http/twitter.com/LamarLee 1
http://localhost.localdomain/about/id/entity/http/twitter.com/HackerChick 1
http://localhost.localdomain/about/id/entity/http/twitter.com/programmingfeed 1
No. of rows in result: 10
]]></programlisting>
</sect3>
</sect2>
<!-- Uncommented for Virtuoso 6 Release-->
<sect2 id="rdfsparqlruleinversefunc"><title>Identity With Inverse Functional Properties </title>
<para>A graph used used with rdfs_rule_set may declare certain properties to
be inversely functional. If one or more inverse functional properties (IFP's)
are declared in the inference context used with the query, enabled
with define input:inference = "context_name", then the following
semantics apply:</para>
<orderedlist>
<listitem>If a literal is compared with an IRI, then the literal is substituted by all the subject IRI's where this literal occurs as a value of an IFP.</listitem>
<listitem>If two IRI's are compared for equality, they will be considered the same if there is an IFP P such that the same P has the same value on both subjects.</listitem>
<listitem>If an IRI is processed for distinctness in either distinct or group by, the IRI is first translated to be the IRI with the lowest ID among all IRI's that share an IFP value with this IRI.</listitem>
</orderedlist>
<para>Thus, if two IRI's are compared for distinctness, they will count as one if there is an IFP P with the same value with both IRI's. Literal data types are not translated into IRI's even if these literals occurred as IFP values of some subject.</para>
<para>It is possible to declare that specific values, even if they occur as values of an IFP in more than onme subject do not constitute identity between the subjects.
For example, if two subjects were inferred to be the same because they had the same foaf:mbox_sha1sum, the SHA1 hash of mailto:// would be excluded. Two individuals have an email address that has a common default value are not the same.
</para>
<para>In an ontology graph, a property IRI is declared to be inversely
functional by making it an instance of the
owl:InverseFunctionalProperty class. A value of an IFP can be
declared null, i.e. sharing the value does not imply identity by by
giving the IFP IRI a
<http://www.openlinksw.com/schemas/virtrdf#nullIFPValue> property with
the value to be ignored as the object.
</para>
<emphasis>Example</emphasis>
<programlisting><![CDATA[
SQL>ttlp ('
<john1> a <person> .
<john2> a <person> .
<mary> a <person> .
<mike> a <person> .
<john1> <name> "John" .
<john2> <name> "John" .
<john1> <address> "101 A street" .
<john2> <address> "102 B street" .
<john2> <knows> <mike> .
<john1> <http://www.w3.org/2002/07/owl#sameAs> <john2> .
<mary> <knows> "John" .
<mike> <knows> <john1> .
<mike> <knows> <john2> .
<john1> <name> "Tarzan" .
<mike> <nam> "Tarzan" .
', '', 'ifps');
SQL>ttlp ('
<name> a <http://www.w3.org/2002/07/owl#InverseFunctionalProperty> .
<name> <http://www.openlinksw.com/schemas/virtrdf#nullIFPValue> "Tarzan" .
', '', 'ifp_list');
SQL>rdfs_rule_set ('ifps', 'ifp_list');
SQL>SPARQL define input:inference "ifps" SELECT * FROM <ifps> WHERE {<john1> ?p ?o};
p o
VARCHAR VARCHAR
_______________________________________________________________________________
address 101 A street
name John
http://www.w3.org/2002/07/owl#sameAs john2
http://www.w3.org/1999/02/22-rdf-syntax-ns#type person
name Tarzan
name John
knows mike
http://www.w3.org/1999/02/22-rdf-syntax-ns#type person
address 102 B street
]]></programlisting>
<para>We see that we get the properties of <john2> also.</para>
<programlisting><![CDATA[
SQL>SPARQL define input:inference "ifps" SELECT distinct ?p FROM <ifps> WHERE { ?p a <person>};
john2
mike
mary
]]></programlisting>
<para>We see that we get only one John. But John is not the same as Mike
because they share the name Tarzan which is not considered as implying
identity. Which John we get is a matter of which gets the lowest
internal ID. This is variable and arbitrary at load time but once
loaded this is permanent as long as the set of subjects with the name
John does not change.</para>
</sect2>
<sect2 id="rdfsparqlruletransoption"><title>Inference Rules and SPARQL with Transitivity Option</title>
<itemizedlist mark="bullet">
<listitem>See <link linkend="rdfsparqlimplementatiotransexamples7">example</link> with an
inference rule to cater data being skos:broader based, which is no long transitive.</listitem>
<listitem>See <link linkend="rdfsparqlimplementatiotransexamples8">example</link> with an
inference rule to find entities that are subcategories of Protestant Churches, no deeper
than 3 levels within the concept scheme hierarchy, filtered by a specific subcategory.</listitem>
</itemizedlist>
</sect2>
<sect2 id="rdfsparqlruleowlrelation"><title>Inference Rules, OWL Support and Relationship Ontology</title>
<para>This section provides queries usage for inference rules, owl support and Relationship Vocabulary.</para>
<sect3 id="rdfsparqlruleowlrelationexample1"><title>Example 1</title>
<para>Example based on Relationship Vocab:</para>
<programlisting><![CDATA[
## Verify Ontology Data is in Quad Store
## Ontology: <http://vocab.org/relationship/> (Relationship Ontology)
## Use pragma to put latest in Quad store.
DEFINE get:soft "replace"
SELECT *
FROM <http://vocab.org/relationship/>
WHERE {?s ?p ?o}
## Clean up
CLEAR GRAPH <urn:owl.tests>
## Create Instance Data for Relationship Ontology
PREFIX rel: <http://purl.org/vocab/relationship/>
INSERT into GRAPH <urn:owl.tests>
{
<http://dbpedia.org/resource/Prince_William_of_Wales> rel:siblingOf <http://dbpedia.org/resource/Prince_Harry_of_Wales>.
<http://dbpedia.org/resource/Elizabeth_Bowes-Lyon> rel:ancestorOf <http://dbpedia.org/resource/Elizabeth_II_of_the_United_Kingdom>.
<http://dbpedia.org/resource/Elizabeth_II_of_the_United_Kingdom> rel:ancestorOf
<http://dbpedia.org/resource/Charles%2C_Prince_of_Wales>.
<http://dbpedia.org/resource/Charles%2C_Prince_of_Wales> rel:ancestorOf <http://dbpedia.org/resource/Prince_William_of_Wales>.
};
## Verify
SELECT *
FROM <urn:owl.tests>
WHERE
{
?s ?p ?o
}
## Create an Inference Rule that references the Relationship Ontology Named Graph
rdfs_rule_set ('urn:owl.tests', 'http://vocab.org/relationship') ;
## Verify Rule's existence
SELECT * FROM sys_rdf_schema ;
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleowlrelationexample2"><title>Example 2</title>
<programlisting><![CDATA[
## Test owl:TransitiveProperty Reasoning
## Start with a specific URI
## Goal: See inferred Triples
## In this case, relationship between: <http://dbpedia.org/resource/Elizabeth_Bowes-Lyon>
## and her descendants: Queen Elizabeth, Prince Charles, Prince William, and Prince Harry)
DEFINE input:inference 'urn:owl.tests'
PREFIX rel: <http://purl.org/vocab/relationship/>
SELECT *
FROM <urn:owl.tests>
WHERE
{
<http://dbpedia.org/resource/Elizabeth_Bowes-Lyon> rel:ancestorOf ?o
}
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleowlrelationexample3"><title>Example 3</title>
<programlisting><![CDATA[
## Test owl:SymmetricalProperty Reasoning
## Should show same result irrespective of rel:siblingOf URI in Subject or Object slots of Triple
DEFINE input:inference 'urn:owl.tests'
PREFIX rel: <http://purl.org/vocab/relationship/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT *
FROM <urn:owl.tests>
WHERE
{
<http://dbpedia.org/resource/Prince_William_of_Wales> rel:siblingOf ?o
}
## OR
DEFINE input:inference 'urn:owl.tests'
PREFIX rel: <http://purl.org/vocab/relationship/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT *
FROM <urn:owl.tests>
WHERE
{
?s rel:siblingOf <http://dbpedia.org/resource/Prince_William_of_Wales>
}
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleowlrelationexample4"><title>Example 4</title>
<programlisting><![CDATA[
## Test owl:inverseOf Reasoning
## Should show triples exposing the inverseOf relation.
## In this case rel:ancestorOf instance data triples exist,so the system must infer rel:descendant Of triples
DEFINE input:inference 'urn:owl.tests'
PREFIX rel: <http://purl.org/vocab/relationship/>
SELECT *
FROM <urn:owl.tests>
WHERE
{
<http://dbpedia.org/resource/Elizabeth_II_of_the_United_Kingdom> rel:descendantOf ?o
}
## OR with Transitivity Option applied
DEFINE input:inference 'urn:owl.tests'
PREFIX rel: <http://purl.org/vocab/relationship/>
SELECT *
FROM <urn:owl.tests>
WHERE
{
<http://dbpedia.org/resource/Prince_William_of_Wales> rel:descendantOf ?o
OPTION (T_DISTINCT)
}
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleowlrelationexample5"><title>Example 5</title>
<programlisting><![CDATA[
## Test owl:inverseOf Reasoning
## Should show triples exposing the inverseOf relation.
## In this case rel:employedBy instance data triples exist,
## the system must infer rel:employerOf triples.
DEFINE input:inference 'urn:owl.tests'
PREFIX rel: <http://purl.org/vocab/relationship/>
SELECT *
FROM <urn:owl.tests>
WHERE
{
?s rel:employerOf ?o
}
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlruleowlrelationexample6"><title>Example 6</title>
<para>Example based on Relationship Vocab and SKOS</para>
<programlisting><![CDATA[
## Graph Cleanup
CLEAR GRAPH <urn:owl.test2.tbox>
CLEAR GRAPH <http://turnguard.com/virtuoso/test10.rdf>
## Load Instance Data into Quad Store
## PL Procedure
## SQL realm
DB.DBA.RDF_LOAD_RDFXML
(
http_get('http://www.w3.org/2009/08/skos-reference/skos-owl1-dl.rdf'),
'no',
'urn:owl.test2.tbox'
);
DB.DBA.RDF_LOAD_RDFXML
(
http_get ('http://www.w3.org/2002/07/owl.rdf'),
'no',
'urn:owl.test2.tbox'
);
DB.DBA.RDF_LOAD_RDFXML
(
http_get ('http://turnguard.com/virtuoso/test10.rdf'),
'no',
'http://turnguard.com/virtuoso/test10.rdf'
);
SELECT *
FROM <http://www.w3.org/2004/02/skos/core>
WHERE
{
{
<http://www.w3.org/2004/02/skos/core#related> ?p ?o
}
UNION
{
?s ?p <http://www.w3.org/2004/02/skos/core#related>
}
}
## Create Rules
## SQL Realm
rdfs_rule_set ('urn:owl.test2.rules', 'urn:owl.test2.tbox');
## Transitivity Query re. SKOS concept hierarchy
DEFINE input:inference "urn:owl.test2.rules"
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
SELECT *
FROM <http://turnguard.com/virtuoso/test10.rdf>
WHERE
{
<http://www.turnguard.com/ElectroPop> skos:broaderTransitive ?o
OPTION (T_DISTINCT).
}
]]></programlisting>
</sect3>
</sect2>
</sect1>
<sect1 id="rdfsparqlgeospat"><title>RDF and Geometry</title>
<para>A geometry may occur as an object of an RDF quad. The SQL MM functions can then be used for
querying for geometries.
</para>
<para>
For geometry functions, see the <link linkend="sqlrefgeospatial">SQL Geometry support section</link>.
</para>
<para>A geometry may occur as an object value in an RDF quad. In such a
case, the bare geometry object is not used but instead a special RDF
typed literal is made with the type virtrdf:Geometry. Such a literal
is automatically indexed in an R tree index containing all distinct
geometries occurring in any quad of any graph under any predicate.
Normally, WGS84, SRID 4326 is the SRID of any such geometry.
</para>
<para>In this section, the geo namespace prefix is used to mean <http://www.w3.org/2003/01/geo/wgs84_pos#>.
</para>
<para>The preferred way of adding geometries to RDF graphs is with the ttlp and related functions
which parse a text string in the Turtle syntax and insert the result in a graph.
</para>
<para>For example:</para>
<programlisting><![CDATA[
ttlp ('@prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#>
<point> geo:geometry "point(1.2 22.4"^^virtrdf:Geometry .',
'xxx', 'graph');
]]></programlisting>
<para>A typed literal whose text is a WKT representation of a geometry and whose type is virtrdf:geometry
creates a geometry object and adds it to the R tree index of all RDF geometries.
</para>
<para>
Geometries can be queried with geometry predicates, st_intersects, st_contains and st_within, as follows.
As usual, the bif: namespace is used since these are SQL built-in functions.
</para>
<programlisting><![CDATA[
SQL>
SPARQL
SELECT ?c COUNT (*)
WHERE
{
?m geo:geometry ?geo .
?m a ?c .
FILTER (bif:st_intersects (?geo, bif:st_point (0, 52), 100))
}
GROUP BY ?c
ORDER BY DESC 2;
c callret-1
VARCHAR VARCHAR
____________________________________________________________
http://linkedgeodata.org/vocabulary#node 2317684
http://linkedgeodata.org/vocabulary#way 85315
http://linkedgeodata.org/vocabulary#building 14257
http://dbpedia.org/class/yago/Landmark108624891 9093
http://linkedgeodata.org/vocabulary#wood 7155
http://linkedgeodata.org/vocabulary#gate 7079
http://www.w3.org/2002/07/owl#Thing 6788
http://linkedgeodata.org/vocabulary#post_box 6144
http://linkedgeodata.org/vocabulary#pub 5697
http://dbpedia.org/ontology/Place 5670
http://linkedgeodata.org/vocabulary#hedge 5391
...
]]></programlisting>
<para>
This would return the classes of things within 100 km of 0, 52, which is near London.
</para>
<programlisting><![CDATA[
SQL>
SPARQL
SELECT ?m (bif:st_distance (?geo, bif:st_point (0, 52)))
WHERE
{
?m geo:geometry ?geo .
?m a <http://dbpedia.org/ontology/City> .
FILTER (bif:st_intersects (?geo, bif:st_point (0, 52), 30))
}
ORDER BY DESC 2
LIMIT 20;
m callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 39.13180985471543
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 39.13180985471543
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 39.13180985471543
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 39.13180985471543
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 37.36907252285992
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 34.49432513061792
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 33.7676326404143
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 33.24238654570499
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 32.60139660515003
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 32.60139660515003
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 32.17414911350438
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 31.45681319171456
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 31.17750625349044
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 31.115377038
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 31.115377038
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 30.56388658524301
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 29.89662974046085
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 29.85090625132639
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 29.82605254366244
http://dbpedia.org/resource/Kingston%2C_Cambridgeshire 29.60102064794003
20 Rows. -- 13600 msec.
]]></programlisting>
<para>This would be the cities within 20 km of 0, 52, ordered by increasing distance from this point.
</para>
<para>When SPARQL is called from SQL, the geometries can be bound to SQL
variables as anything else returned from SPARQL. The <emphasis>st_</emphasis> functions
can then be used for retrieving properties of these objects.
</para>
<tip><title>See Also</title>
<para><link linkend="fn_st_point"><function>st_point</function></link></para>
<para><link linkend="fn_st_x"><function>st_x</function></link></para>
<para><link linkend="fn_st_y"><function>st_y</function></link></para>
<para><link linkend="fn_st_distance"><function>st_distance</function></link></para>
<para><link linkend="fn_st_srid"><function>st_srid</function></link></para>
<para><link linkend="fn_st_setsrid"><function>st_setsrid</function></link></para>
<para><link linkend="fn_st_astext"><function>st_astext</function></link></para>
<para><link linkend="fn_st_geomfromtext"><function>st_geomfromtext</function></link></para>
<para><link linkend="fn_st_contains"><function>st_contains</function></link></para>
<para><link linkend="fn_st_intersects"><function>st_intersects</function></link></para>
<para><link linkend="fn_st_within"><function>st_within</function></link></para>
<para><link linkend="fn_isgeometry"><function>isgeometry</function></link></para>
<para><link linkend="fn_geo_insert"><function>geo_insert</function></link></para>
<para><link linkend="fn_geo_delete"><function>geo_delete</function></link></para>
</tip>
<sect2 id="rdfsparqlgeospatprog"><title>Programmatic Manipulation of Geometries in RDF</title>
<para>The <link linkend="fn_ttlp"><function>ttlp</function></link> function is the preferred
way of inserting geometries. The more are inserted at one time, the more efficient the operation is.
This loader function will also deal with cluster message optimization.
</para>
<para>For deleting quads with geometries, normal
<link linkend="rdfsparqlimplementationextent">SPARUL operations</link> apply.
</para>
<para>A geometry occurring in an RDF quad object is a member of the RDF box data type. This data type
stands for a typed RDF literal. The type of all geometries is 256. This is mapped to a URI in
the RDF_DATATYPE system table.
</para>
<para>A geometry does not occur directly in the object position of a quad. It is referenced by an id
that is stored in the RDF typed literal box and references RO_ID of the RDF_OBJ system table.
To translate a geometry into a RDF box that can be stored, do as in the example below:
</para>
<programlisting><![CDATA[
INSERT INTO RDF_QUAD (g, s, p, o)
VALUES (
"g",
"s",
iri_to_id ('http://www.w3.org/2003/01/geo/wgs84_pos#geometry'),
DB.DBA.rdf_geo_add (rdf_box (st_point (lng, lat), 256, 257, 0, 1)));
]]></programlisting>
<para>The DB.DBA.RDF_GEO_ADD function looks if an identical geometry already exists and if so assigns the
existing id to it. If the geometry is new, it gets a new ID and is stored in the RDF literals
table RDF_OBJ. At this time it is also automatically inserted into the RDF geometry index.
</para>
<para>In a cluster situation one should use the dpipe mechanism for inserting into RDF quad so as to
get large numbers of inserts into a single message. This is essential for performance.
</para>
</sect2>
<sect2 id="rdfsparqlgeospatcrg"><title>Creating Geometries From RDF Data</title>
<para>Many data sets use the geo:lat and geo:long properties for describing a position.
Virtuoso comes with a function for converting these properties into geometries. This operation
reads through all graphs and for each subject with at least one geo:lat and geo:long, a point
geometry is made for each distinct lat/long pair where lat and long are in the same graph. It
should not happen in practice that a single subject has multiple lats or long within one graph.
If this still happens, a geometry is made for each combination.
The geometry is added to the subject with the lat and long as the value of the geo:geometry property.
This is added to the same graph where the lat and long were.
</para>
<para>The SQL procedure DB.DBA.RDF_GEO_FILL () performs this operation. This is performed in parallel on
multiple threads and is optimized for cluster execution. This is done without transaction logging
and is not transactional. To make the result persistent, the operator should do an explicit checkpoint.
This is done by executing:</para>
<programlisting><![CDATA[
SQL>cl_exec ('checkpoint');
]]></programlisting>
<para>on any process of a cluster or single server.
Otherwise the result may be lost if the server terminates abnormally before an automatic checkpoint is made.
</para>
<para>The DB.DBA.RDF_GEO_FILL procedure may in principle be called several times but it will read
every lat and long in the database. This is inefficient if there are large numbers of geometries.
</para>
<para>Application logic must generally be used for constructing geometries and adding these to RDF subjects.
It is easiest for the application to construct a text representation of the geometries in TTL and to
use the <link linkend="fn_ttlp"><function>ttlp</function></link> function for loading this.
</para>
</sect2>
<sect2 id="rdfsparqlgeospatusg"><title>Using Geometries With Existing Databases</title>
<para>
The geometry feature is compatible with any Virtuoso 6 databases.
Once geometries are used, the database should not be opened with a
server older than the one used for first inserting geometries, older
servers will consider the storage format a physical corruption.
</para>
</sect2>
<sect2 id="rdfsparqlgeospatexmp"><title>GEO Spatial Examples</title>
<sect3 id="rdfsparqlgeospatexmp1"><title>Example 1</title>
<programlisting><![CDATA[
## Get All Stuff For Given Coordinates
SQL>SPARQL
SELECT ?c COUNT (*)
WHERE
{
?m geo:geometry ?geo .
?m a ?c .
FILTER (bif:st_intersects (?geo, bif:st_point (0, 52), 100))
}
GROUP BY ?c
ORDER BY desc 2;
c callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://linkedgeodata.org/vocabulary#node 2317684
http://linkedgeodata.org/vocabulary#way 85315
http://linkedgeodata.org/vocabulary#building 14257
http://dbpedia.org/class/yago/Landmark108624891 9093
http://linkedgeodata.org/vocabulary#wood 7155
....
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp2"><title>Example 2</title>
<programlisting><![CDATA[
## Get City Stuff Around Catholic Churches In Paris
SQL>
SPARQL
SELECT ?m (bif:st_distance (?geo, bif:st_point (0, 52)))
WHERE
{
?m geo:geometry ?geo .
?m a <http://dbpedia.org/ontology/City> .
FILTER (bif:st_intersects (?geo, bif:st_point (0, 52), 30))
}
ORDER BY DESC 2
LIMIT 20;
m callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Stansted_Mountfitchet 39.13180985471543
http://dbpedia.org/resource/Stansted_Mountfitchet 39.13180985471543
http://dbpedia.org/resource/Stansted_Mountfitchet 39.13180985471543
http://dbpedia.org/resource/Stansted_Mountfitchet 39.13180985471543
http://dbpedia.org/resource/Stansted_Mountfitchet 37.36907252285992
http://dbpedia.org/resource/Stansted_Mountfitchet 34.49432513061792
http://dbpedia.org/resource/Stansted_Mountfitchet 33.7676326404143
http://dbpedia.org/resource/Stansted_Mountfitchet 33.24238654570499
http://dbpedia.org/resource/Stansted_Mountfitchet 32.60139660515003
http://dbpedia.org/resource/Stansted_Mountfitchet 32.60139660515003
http://dbpedia.org/resource/Stansted_Mountfitchet 31.45681319171456
http://dbpedia.org/resource/Stansted_Mountfitchet 31.115377038
http://dbpedia.org/resource/Stansted_Mountfitchet 31.115377038
http://dbpedia.org/resource/Stansted_Mountfitchet 30.56388658524301
http://dbpedia.org/resource/Stansted_Mountfitchet 29.89662974046085
http://dbpedia.org/resource/Stansted_Mountfitchet 29.85090625132639
http://dbpedia.org/resource/Stansted_Mountfitchet 29.82605254366244
http://dbpedia.org/resource/Stansted_Mountfitchet 29.60102064794003
http://dbpedia.org/resource/Stansted_Mountfitchet 29.44147385851453
http://dbpedia.org/resource/Stansted_Mountfitchet 29.421242437379
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp3"><title>Example 3</title>
<programlisting><![CDATA[
## Get City Stuff Around Catholic Churches In Paris Extended
SQL>
SPARQL
SELECT ?m (bif:st_distance (?geo, bif:st_point (0, 52)))
WHERE
{
?m geo:geometry ?geo .
?m a <http://dbpedia.org/ontology/City> .
FILTER (bif:st_intersects (?geo, bif:st_point (0, 52), 100))
}
ORDER BY DESC 2
LIMIT 20;
m callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Weston-on-Trent 138.7082197019335
http://dbpedia.org/resource/Weston-on-Trent 137.7213767969613
http://dbpedia.org/resource/Weston-on-Trent 136.4597167847218
http://dbpedia.org/resource/Weston-on-Trent 134.1807668663677
http://dbpedia.org/resource/Weston-on-Trent 133.104337839536
http://dbpedia.org/resource/Weston-on-Trent 133.104337839536
http://dbpedia.org/resource/Nonington 132.7368236183588
http://dbpedia.org/resource/Nonington 132.1339163200362
http://dbpedia.org/resource/Nonington 132.1339163200362
http://dbpedia.org/resource/Nonington 130.5478483560461
http://dbpedia.org/resource/Nonington 130.1620410981843
http://dbpedia.org/resource/Nonington 129.8549842943355
http://dbpedia.org/resource/Nonington 129.6459280567849
http://dbpedia.org/resource/Nonington 129.4504858595742
http://dbpedia.org/resource/Nonington 129.2790713235814
http://dbpedia.org/resource/Nonington 128.9081040147881
http://dbpedia.org/resource/Nonington 128.8845164618929
http://dbpedia.org/resource/Nonington 128.6676189617872
http://dbpedia.org/resource/Nonington 128.2565253458452
http://dbpedia.org/resource/Nonington 128.2551696344652
20 Rows. -- 120 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp4"><title>Example 4</title>
<programlisting><![CDATA[
## Text Or Geo
SQL>
SPARQL
SELECT ?c COUNT (*)
WHERE
{
?m geo:geometry ?geo .
?m a ?c .
FILTER (bif:st_intersects (?geo, bif:st_point (0, 52), 100) && REGEX (str (?c), "London") )
}
GROUP BY ?c
ORDER BY DESC 2
LIMIT 10;
c callret-1
____________________________________________________________________________
http://dbpedia.org/class/yago/DistrictsOfLondon 861
http://dbpedia.org/class/yago/GradeIListedBuildingsInLondon 199
http://dbpedia.org/class/yago/MuseumsInLondon 107
http://dbpedia.org/class/yago/ArtMuseumsAndGalleriesInLondon 92
http://dbpedia.org/class/yago/GradeIIListedBuildingsInLondon 89
http://dbpedia.org/class/yago/SportsVenuesInLondon 80
http://dbpedia.org/class/yago/RoyalBuildingsInLondon 72
http://dbpedia.org/class/yago/LondonOvergroundStations 69
http://dbpedia.org/class/yago/NationalGovernmentBuildingsInLondon 69
http://dbpedia.org/class/yago/SkyscrapersInLondon 60
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp5"><title>Example 5</title>
<programlisting><![CDATA[
## Example "Places Of Worship, Within 5 km Of Paris":
## Describes places of worship, within 5 km of Paris,
## that have cafes in close proximity(0.2 km).
## The query requires V6 or higher.
SQL>
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
DESCRIBE ?cafe ?church
WHERE
{
?church a lgv:place_of_worship .
?church geo:geometry ?churchgeo .
?church lgv:name ?churchname .
?cafe a lgv:cafe .
?cafe lgv:name ?cafename .
?cafe geo:geometry ?cafegeo .
?cafe geo:lat ?lat .
?cafe geo:long ?long .
FILTER ( bif:st_intersects ( ?churchgeo, bif:st_point ( 2.3498, 48.853 ), 5 ) &&
bif:st_intersects ( ?cafegeo, ?churchgeo, 0.2 ) )
}
LIMIT 10;
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <http://linkedgeodata.org/triplify/node/243360870#> .
@prefix ns2: <http://linkedgeodata.org/vocabulary#> .
ns1:id rdf:type ns2:place_of_worship ,
ns2:node .
@prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> .
ns1:id geo:lat 48.8794 ;
geo:long 2.3748 ;
ns2:created_by "Potlatch 0.6c" ;
ns2:name "Saint-Georges de la Villette" ;
ns2:religion "christian" ,
ns2:christian .
@prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#> .
ns1:id geo:geometry "POINT(2.3748 48.8794)"^^virtrdf:Geometry .
@prefix ns5: <http://linkedgeodata.org/triplify/node/266632049#> .
ns5:id rdf:type ns2:node ,
ns2:cafe ;
geo:lat 48.8518 ;
geo:long 2.325 ;
ns2:created_by "Potlatch 0.9a" ;
ns2:name "Le Babylone" ;
geo:geometry "POINT(2.325 48.8518)"^^virtrdf:Geometry .
....
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp6"><title>Example 6</title>
<programlisting><![CDATA[
## Count Geo
SQL>
SPARQL
SELECT ?c COUNT (*)
WHERE
{
?s geo:geometry ?geo .
FILTER (bif:st_intersects (?geo, bif:st_point (2.3498, 48.853), 5)) .
?s a ?c
}
GROUP BY ?c
ORDER BY desc 2
LIMIT 10;
c callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://linkedgeodata.org/vocabulary#node 37792
http://dbpedia.org/class/yago/Landmark108624891 4003
http://linkedgeodata.org/vocabulary#way 1688
http://linkedgeodata.org/vocabulary#building 719
http://linkedgeodata.org/vocabulary#station 257
http://linkedgeodata.org/vocabulary#post_box 247
http://www.w3.org/2002/07/owl#Thing 227
http://linkedgeodata.org/vocabulary#park 208
http://linkedgeodata.org/vocabulary#restaurant 198
http://dbpedia.org/ontology/Place 192
10 Rows. -- 932 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp7"><title>Example 7</title>
<programlisting><![CDATA[
## Get Stuff Around Notre Dame De Paris
SQL>
SPARQL
SELECT ?c COUNT (*)
WHERE
{
?s a ?c .
?s geo:geometry ?geo .
FILTER (bif:st_intersects (?geo, bif:st_point (2.3498, 48.853), 0.3))
}
GROUP BY ?c
ORDER BY desc 2
LIMIT 10;
c callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://linkedgeodata.org/vocabulary#node 408
http://dbpedia.org/class/yago/Landmark108624891 134
http://linkedgeodata.org/vocabulary#way 17
http://dbpedia.org/class/yago/RomanCatholicChurchesInParis 17
http://dbpedia.org/class/yago/TallBuildingsAndStructuresInParis 13
http://dbpedia.org/class/yago/CathedralsInFrance 13
http://sw.opencyc.org/2008/06/10/concept/Mx4rvVigPpwpEbGdrcN5Y29ycA 13
http://sw.opencyc.org/2008/06/10/concept/Mx4rjm5QanS6EdaAAACgyZzFrg 13
http://sw.opencyc.org/2008/06/10/concept/Mx4rwQwtGpwpEbGdrcN5Y29ycA 13
http://www.w3.org/2002/07/owl#Thing 10
10 Rows. -- 241 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp8"><title>Example 8</title>
<programlisting><![CDATA[
## Things within 10 km proximity of place of worship
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
SELECT ?c COUNT (*)
WHERE
{
?s a ?c .
?s a lgv:place_of_worship .
?s geo:geometry ?geo .
FILTER (bif:st_intersects (?geo, bif:st_point (2.3498, 48.853), 10))
}
GROUP BY ?c
ORDER BY desc 2
LIMIT 10;
c callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
http://linkedgeodata.org/vocabulary#place_of_worship 147
http://linkedgeodata.org/vocabulary#node 146
http://linkedgeodata.org/vocabulary#way 46
http://linkedgeodata.org/vocabulary#building 36
http://linkedgeodata.org/vocabulary#attraction 3
http://linkedgeodata.org/vocabulary#church 1
6 Rows. -- 120 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp9"><title>Example 9</title>
<programlisting><![CDATA[
## Get Stuff Around Notre Dame De Paris with Names
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
SELECT ?cn
WHERE
{
?s lgv:name ?cn .
?s geo:geometry ?geo .
FILTER (bif:st_intersects (?geo, bif:st_point (2.3498, 48.853), 0.3))
}
LIMIT 20;
cn
VARCHAR
_______________________________________________________________________________
Parking Lagrange
Maitre Albert B&B
Le Grenier de Notre Dame
Eglise Saint-Julien-le-Pauvre
Eglise Saint Julien le Pauvre
Polly Magoo
Point 0 des Routes de France
Square Jean XXIII
....
20 Rows. -- 140 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp10"><title>Example 10</title>
<programlisting><![CDATA[
## Get Churches With The Most Bars
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
SELECT ?churchname ?cafename (bif:st_distance (?churchgeo, ?cafegeo))
WHERE
{
?church a lgv:place_of_worship .
?church geo:geometry ?churchgeo .
?church lgv:name ?churchname .
?cafe a lgv:cafe .
?cafe lgv:name ?cafename .
?cafe geo:geometry ?cafegeo .
FILTER (bif:st_intersects (?churchgeo, bif:st_point (2.3498, 48.853), 5)
&& bif:st_intersects (?cafegeo, ?churchgeo, 0.2))
}
LIMIT 10;
churchname cafename callret-2
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
Eglise Saint-Julien-le-Pauvre Le Saint R+?-?gis 0.09759308692691648
Eglise Saint-Germain des Pr+?-?s Caf+?-? de Flore 0.08774468391412803
Eglise Saint-Germain des Pr+?-?s Les Deux Magots 0.05235923473923059
Eglise Saint-Germain des Pr+?-?s Caf+?-? Mabillon 0.1712042770289815
Eglise Saint-Germain-des-Pr+?-?s Caf+?-? de Flore 0.1466502865197912
Eglise Saint-Germain-des-Pr+?-?s Les Deux Magots 0.1096767137079839
Eglise Saint-Germain-des-Pr+?-?s Bar du march+?-? 0.1831441251868126
Eglise Saint-Germain-des-Pr+?-?s Caf+?-? Mabillon 0.1174051745495528
Synagogue La Chaise au Plafond 0.1038387283609551
Synagogue Le Loir dans la Th+?-?i+?-?re 0.1632848322062273
10 Rows. -- 511225 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp11"><title>Example 11</title>
<programlisting><![CDATA[
## Things around highly populated places
SQL>
SPARQL
SELECT ?s ( sql:num_or_null (?o) ) COUNT (*)
WHERE
{
?s <http://dbpedia.org/ontology/populationTotal> ?o .
FILTER ( sql:num_or_null (?o) > 6000000 ) .
?s geo:geometry ?geo .
FILTER ( bif:st_intersects (?pt, ?geo,2) ) .
?xx geo:geometry ?pt
}
GROUP BY ?s ( sql:num_or_null (?o) )
ORDER BY desc 3
LIMIT 20;
s callret-1 callret-2
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/London 7556900 312307
http://dbpedia.org/resource/Toronto 8102163 115859
http://dbpedia.org/resource/New_York_City 8363710 95629
http://dbpedia.org/resource/The_Hague 6659300 84410
http://dbpedia.org/resource/Tokyo 12790000 78618
http://dbpedia.org/resource/Philadelphia 6385461 67115
http://dbpedia.org/resource/Los_Angeles 17755322 64394
http://dbpedia.org/resource/Bangkok 8160522 62519
http://dbpedia.org/resource/Barcelona 2147483648 57635
http://dbpedia.org/resource/Cairo 6758581 52738
http://dbpedia.org/resource/Istanbul 12697164 50745
http://dbpedia.org/resource/Seoul 10421782 43962
http://dbpedia.org/resource/Beijing 17430000 35979
http://dbpedia.org/resource/Purmerend 6659300 33508
http://dbpedia.org/resource/Baghdad 6554126 33426
http://dbpedia.org/resource/Bogot%C3%A1 6776009 30429
http://dbpedia.org/resource/Mexico_City 8836045 30127
http://dbpedia.org/resource/Jakarta 8500000 28944
http://dbpedia.org/resource/Boston 7514759 27705
http://dbpedia.org/resource/Baden-W%C3%BCrttemberg 10755000 25112
20 Rows. -- 4296 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp12"><title>Example 12</title>
<programlisting><![CDATA[
## Example "Places Of Worship, Within 5 km Of Paris":
## Constructs a custom Linked Data Mesh (graph) about
## places of worship, within 5 km of Paris, that have
## cafes in close proximity(0.2 km).
## Note: we have distinct pin colors that identify
## for places of worship distinct from cafes.
## The query requires V6 or higher.
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
PREFIX rtb: <http://www.openlinksw.com/schemas/oat/rdftabs#>
CONSTRUCT
{
?cafe geo:geometry ?cafegeo ;
rtb:useMarker '01' ;
lgv:name ?cafename .
?church geo:geometry ?churchgeo ;
rtb:useMarker '02' ;
lgv:name ?churchname .
}
WHERE
{
?church a lgv:place_of_worship .
?church geo:geometry ?churchgeo .
?church lgv:name ?churchname .
?cafe a lgv:cafe .
?cafe lgv:name ?cafename .
?cafe geo:geometry ?cafegeo .
?cafe geo:lat ?lat .
?cafe geo:long ?long .
FILTER ( bif:st_intersects ( ?churchgeo, bif:st_point ( 2.3498, 48.853 ), 5 ) &&
bif:st_intersects ( ?cafegeo, ?churchgeo, 0.2 ) )
}
LIMIT 10;
@prefix ns0: <http://linkedgeodata.org/vocabulary#> .
@prefix ns1: <http://linkedgeodata.org/triplify/node/237435716#> .
ns1:id ns0:name "Chapelle du Val de Gr\u00C3\u00A2ce" .
@prefix ns2: <http://www.openlinksw.com/schemas/oat/rdftabs#> .
ns1:id ns2:useMarker "02" .
@prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#> .
@prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> .
ns1:id geo:geometry "POINT(2.3418 48.8406)"^^virtrdf:Geometry .
@prefix ns5: <http://linkedgeodata.org/triplify/node/218147750#> .
ns5:id ns0:name "Synagogue" ;
ns2:useMarker "02" ;
geo:geometry "POINT(2.3593 48.857)"^^virtrdf:Geometry .
@prefix ns6: <http://linkedgeodata.org/triplify/node/218145208#> .
ns6:id ns0:name "Synagogue" ;
ns2:useMarker "02" ;
geo:geometry "POINT(2.3589 48.8567)"^^virtrdf:Geometry .
...
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp13"><title>Example 13</title>
<programlisting><![CDATA[
## Example "Places Of Worship, Within 5 km Of Paris":
## Asks for places of worship, within 5 km of Paris,
## that have cafes in close proximity(0.2 km).
## The query requires V6 or higher.
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
ASK
WHERE
{
?church a lgv:place_of_worship .
?church geo:geometry ?churchgeo .
?church lgv:name ?churchname .
?cafe a lgv:cafe .
?cafe lgv:name ?cafename .
?cafe geo:geometry ?cafegeo .
?cafe geo:lat ?lat .
?cafe geo:long ?long .
FILTER ( bif:st_intersects ( ?churchgeo, bif:st_point ( 2.3498, 48.853 ), 5 ) &&
bif:st_intersects ( ?cafegeo, ?churchgeo, 0.2 ) )
};
Done.
true
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp14"><title>Example 14</title>
<programlisting><![CDATA[
## Places of worship, within 5 km of Paris,
## that have cafes in close proximity(0.2 km)
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
SELECT DISTINCT ?cafe ?lat ?long ?cafename ?churchname
(bif:round(bif:st_distance (?churchgeo, ?cafegeo)))
WHERE
{
?church a lgv:place_of_worship .
?church geo:geometry ?churchgeo .
?church lgv:name ?churchname .
?cafe a lgv:cafe .
?cafe lgv:name ?cafename .
?cafe geo:geometry ?cafegeo .
?cafe geo:lat ?lat.
?cafe geo:long ?long.
FILTER ( bif:st_intersects (?churchgeo, bif:st_point (2.3498, 48.853), 5) &&
bif:st_intersects (?cafegeo, ?churchgeo, 0.2) )
}
LIMIT 10;
cafe lat long cafename churchname callret-5
VARCHAR VARCHAR VARCHAR VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________________________________________________________________________________________
http://linkedgeodata.org/triplify/node/321932192#id 48.8522 2.3484 Le Saint R+?-?gis Eglise Saint-Julien-le-Pauvre 0
http://linkedgeodata.org/triplify/node/251699776#id 48.8541 2.3326 Caf+?-? de Flore Eglise Saint-Germain des Pr+?-?s 0
http://linkedgeodata.org/triplify/node/251699775#id 48.854 2.3331 Les Deux Magots Eglise Saint-Germain des Pr+?-?s 0
http://linkedgeodata.org/triplify/node/315769036#id 48.8533 2.3358 Caf+?-? Mabillon Eglise Saint-Germain des Pr+?-?s 0
http://linkedgeodata.org/triplify/node/251699776#id 48.8541 2.3326 Caf+?-? de Flore Eglise Saint-Germain-des-Pr+?-?s 0
http://linkedgeodata.org/triplify/node/251699775#id 48.854 2.3331 Les Deux Magots Eglise Saint-Germain-des-Pr+?-?s 0
http://linkedgeodata.org/triplify/node/315769035#id 48.8539 2.3371 Bar du march+?-? Eglise Saint-Germain-des-Pr+?-?s 0
http://linkedgeodata.org/triplify/node/315769036#id 48.8533 2.3358 Caf+?-? Mabillon Eglise Saint-Germain-des-Pr+?-?s 0
http://linkedgeodata.org/triplify/node/251126326#id 48.8572 2.3577 La Chaise au Plafond Synagogue 0
http://linkedgeodata.org/triplify/node/251043135#id 48.8562 2.361 Le Loir dans la Th+?-?i+?-?re Synagogue 0
10 Rows. -- 120 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp15"><title>Example 15</title>
<programlisting><![CDATA[
## Stuff around Notre Dame de Paris
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
SELECT ?s ?cn ?lat ?long
WHERE
{
?s lgv:name ?cn .
?s geo:geometry ?geo .
?s geo:lat ?lat.
?s geo:long ?long.
FILTER ( bif:st_intersects (?geo, bif:st_point (2.3498, 48.853), 0.3) )
}
LIMIT 20;
s cn lat long
VARCHAR VARCHAR VARCHAR VARCHAR
______________________________________________________________________________________________________________
http://linkedgeodata.org/triplify/node/237004656#id Parking Lagrange 48.8506 2.3487
http://linkedgeodata.org/triplify/node/237003117#id Mus+?-?e de l'Assistance Publique H+?-pitaux de Paris 48.8507 2.3519
http://linkedgeodata.org/triplify/way/23071565#id Jardin de la Rue de Bi+?-?vre 48.8504 2.3502
http://linkedgeodata.org/triplify/node/251652818#id Maitre Albert B&B 48.8507 2.3496
http://linkedgeodata.org/triplify/node/251373384#id Le Grenier de Notre Dame 48.8513 2.35
http://linkedgeodata.org/triplify/node/205266764#id Eglise Saint-Julien-le-Pauvre 48.852 2.3471
http://linkedgeodata.org/triplify/way/19741083#id Eglise Saint Julien le Pauvre 48.8521 2.3469
http://linkedgeodata.org/triplify/node/251474112#id Polly Magoo 48.8526 2.3467
http://linkedgeodata.org/triplify/node/251531803#id H+?-tel Esmerelda 48.8523 2.3468
http://linkedgeodata.org/triplify/node/191031796#id Point 0 des Routes de France 48.8533 2.3489
http://linkedgeodata.org/triplify/way/20444455#id Square Jean XXIII 48.8529 2.3511
http://linkedgeodata.org/triplify/way/19740745#id Square Ren+?-? Viviani 48.8525 2.3476
http://linkedgeodata.org/triplify/node/321932192#id Le Saint R+?-?gis 48.8522 2.3484
http://linkedgeodata.org/triplify/node/27440965#id Notre-Dame de Paris 48.853 2.3499
http://linkedgeodata.org/triplify/node/243461762#id Parking Notre-Dame 48.8537 2.3475
http://linkedgeodata.org/triplify/way/21816758#id Notre-Dame de Paris 48.8531 2.349
http://linkedgeodata.org/triplify/way/22972062#id La Seine 48.8538 2.3531
http://linkedgeodata.org/triplify/way/25463927#id La Seine 48.8548 2.3518
http://linkedgeodata.org/triplify/node/251128395#id H+?-tel Hospitel 48.854 2.3484
http://linkedgeodata.org/triplify/way/14155323#id H+?-tel Dieu 48.8555 2.3485
20 Rows. -- 167 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp16"><title>Example 16</title>
<programlisting><![CDATA[
## Stuff around Notre Dame de Paris
SQL>
SPARQL
PREFIX lgv: <http://linkedgeodata.org/vocabulary#>
DESCRIBE ?s
WHERE
{
?s lgv:name ?cn .
?s geo:geometry ?geo .
?s geo:lat ?lat.
?s geo:long ?long.
FILTER (bif:st_intersects (?geo, bif:st_point (2.3498, 48.853), 0.3))
}
LIMIT 20;
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix ns1: <http://linkedgeodata.org/triplify/node/27440966#> .
@prefix ns2: <http://linkedgeodata.org/vocabulary#> .
ns1:id rdf:type ns2:node ,
ns2:police .
@prefix geo: <http://www.w3.org/2003/01/geo/wgs84_pos#> .
ns1:id geo:lat 48.8542 ;
geo:long 2.3473 ;
ns2:created_by "Potlatch 0.6a" ;
ns2:name "Pr\u00C3\u00A9fecture de Police de Paris" ,
"Pr\u00E9fecture de Police de Paris" .
@prefix virtrdf: <http://www.openlinksw.com/schemas/virtrdf#> .
ns1:id geo:geometry "POINT(2.3473 48.8542)"^^virtrdf:Geometry .
@prefix ns5: <http://linkedgeodata.org/triplify/node/27440965#> .
ns5:id rdf:type ns2:node ,
ns2:place_of_worship ;
geo:lat 48.853 ;
geo:long 2.3499 ;
ns2:denomination "catholic" ;
ns2:name "Notre-Dame de Paris" ;
ns2:religion "christian" ,
ns2:christian ;
geo:geometry "POINT(2.3499 48.853)"^^virtrdf:Geometry .
......
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp17"><title>Example 17</title>
<programlisting><![CDATA[
## Cities within 30 km proximity of London
SQL>
SPARQL
SELECT ?m (bif:round(bif:st_distance (?geo, ?gm)))
WHERE
{
<http://dbpedia.org/resource/London> geo:geometry ?gm .
?m geo:geometry ?geo .
?m a <http://dbpedia.org/ontology/City> .
FILTER (bif:st_intersects (?geo, ?gm, 30))
}
ORDER BY DESC 2
LIMIT 20;
m callret-1
VARCHAR VARCHAR
____________________________________________________________
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Ebbsfleet_Valley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
http://dbpedia.org/resource/Bletchingley 30
20 Rows. -- 727666 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp18"><title>Example 18</title>
<programlisting><![CDATA[
## Motorways across England & Scotland from DBpedia
SQL>
SPARQL
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dbpprop: <http://dbpedia.org/property/>
PREFIX yago: <http://dbpedia.org/class/yago/>
SELECT ?road ?services ?lat ?long
WHERE
{
{
?services dbpprop:road ?road .
?road a yago:MotorwaysInEngland .
?services dbpprop:lat ?lat .
?services dbpprop:long ?long .
}
UNION
{
?services dbpprop:road ?road .
?road a yago:MotorwaysInScotland .
?services dbpprop:lat ?lat .
?services dbpprop:long ?long .
}
}
LIMIT 20;
road services lat long
VARCHAR VARCHAR VARCHAR VARCHAR
______________________________________________________________________________________________________________________________________
http://dbpedia.org/resource/M90_motorway http://dbpedia.org/resource/Kinross_services 56.209628 -3.439257
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Leicester_Forest_East_services 52.6192 -1.206
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Woodall_services 53.3152 -1.2813
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Tibshelf_services 53.13708 -1.33179
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/London_Gateway_services 51.631 -0.264
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Donington_Park_services 52.823651 -1.305887
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Watford_Gap_services 52.3069 -1.1226
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Newport_Pagnell_services 52.083066 -0.748508
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Trowell_services 52.963198 -1.265988
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Woolley_Edge_services 53.62259 -1.549422
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Toddington_services 51.9478 -0.502075
http://dbpedia.org/resource/M1_motorway http://dbpedia.org/resource/Northampton_services 52.209201 -0.944799
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Chieveley_services 51.449 -1.3112
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Magor_services 51.58786 -2.83713
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Pont_Abraham_services 51.74712 -4.0655
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Swansea_services 51.678197 -3.994646
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Leigh_Delamere_services 51.511528 -2.159468
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Reading_services 51.424527 -1.035633
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Cardiff_West_services 51.50626 -3.30535
http://dbpedia.org/resource/M4_motorway http://dbpedia.org/resource/Heston_services 51.48807 -0.39106
20 Rows. -- 531 msec.
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp18"><title>Example 19</title>
<programlisting><![CDATA[
SELECT DISTINCT ?s (bif:round(?lat)) as ?lat (bif:round(?long)) as ?long
WHERE
{
{
SELECT ?g ?s WHERE
{
graph ?g {
?s geo:geometry ?geo }
}
LIMIT 100
}
graph ?g {
?s geo:lat ?lat .
?s geo:long ?long . }
FILTER (datatype (?lat) in (xsd:integer, xsd:float, xsd:double)) .
FILTER (datatype (?long) in (xsd:integer, xsd:float, xsd:double))
}
s lat long
ANY ANY ANY
________________________________________________________________________________________________
http://dbpedia.org/resource/QUaD -90 -139
http://dbpedia.org/resource/Amundsen-Scott_South_Pole_Station -90 -139
http://dbpedia.org/resource/Amundsen-Scott_South_Pole_Station -90 0
http://dbpedia.org/resource/Degree_Angular_Scale_Interferometer -90 -139
http://dbpedia.org/resource/South_Pole_Telescope -90 -139
http://dbpedia.org/resource/Arcminute_Cosmology_Bolometer_Array_Receiver -90 -139
http://dbpedia.org/resource/Viper_telescope -90 -139
http://dbpedia.org/resource/Mount_Weaver -87 -154
http://dbpedia.org/resource/Axel_Heiberg_Glacier -85 -163
http://dbpedia.org/resource/Mount_Ray -85 -171
http://linkedgeodata.org/triplify/node/275487234#id -85 -142
http://linkedgeodata.org/triplify/node/303732928#id -85 -142
http://linkedgeodata.org/triplify/node/332036611#id -85 -85
http://linkedgeodata.org/triplify/node/303732935#id -85 -143
http://linkedgeodata.org/triplify/node/303732951#id -85 -144
http://linkedgeodata.org/triplify/node/303732953#id -85 -144
http://linkedgeodata.org/triplify/node/276208684#id -85 -166
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp19"><title>Example 19</title>
<programlisting><![CDATA[
## "Find things within 20km of New York City":
SELECT DISTINCT ?resource ?label ?location
WHERE
{
<http://dbpedia.org/resource/New_York_City>
geo:geometry ?sourcegeo .
?resource geo:geometry ?location ;
rdfs:label ?label .
FILTER( bif:st_intersects( ?location, ?sourcegeo, 20 ) ) .
FILTER( lang(?label) = "en" )
}
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp20"><title>Example 20</title>
<programlisting><![CDATA[
## "Find Distance between New York City
## and London, England":
SELECT ( bif:st_distance( ?nyl,?ln ) )
AS ?distanceBetweenNewYorkCityAndLondon
WHERE
{
<http://dbpedia.org/resource/New_York_City>
geo:geometry ?nyl .
<http://dbpedia.org/resource/London>
geo:geometry ?ln .
}
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp21"><title>Example 21</title>
<programlisting><![CDATA[
## "Find "All Educational Institutions
## within 10km of Oxford, UK; ordered by
## date of establishment":
SELECT DISTINCT ?thing AS ?uri
?thingLabel AS ?name
?date AS ?established
?matchgeo AS ?location
WHERE
{
<http://dbpedia.org/resource/Oxford>
geo:geometry ?sourcegeo .
?resource geo:geometry ?matchgeo .
FILTER( bif:st_intersects( ?matchgeo, ?sourcegeo, 5 ) ) .
?thing ?somelink ?resource ;
<http://dbpedia.org/ontology/established> ?date ;
rdfs:label ?thingLabel .
FILTER( lang(?thingLabel) = "en" )
}
ORDER BY ASC( ?date )
]]></programlisting>
</sect3>
<sect3 id="rdfsparqlgeospatexmp22"><title>Example 22</title>
<programlisting><![CDATA[
## "Find Historical cross section of events related
## to Edinburgh and the surrounding area (within 30km)
## during the 19th century":
SELECT DISTINCT ?thing ?thingLabel
?dateMeaningLabel ?date ?matchgeo
WHERE
{
{
SELECT DISTINCT ?thing ?matchgeo
WHERE
{
<http://dbpedia.org/resource/Edinburgh>
geo:geometry ?sourcegeo .
?resource geo:geometry ?matchgeo .
FILTER( bif:st_intersects (
?matchgeo, ?sourcegeo, 30 ) ) .
?thing ?somelink ?resource
}
}
{
?property rdf:type owl:DatatypeProperty ;
rdfs:range xsd:date
} .
?thing ?dateMeaning ?date .
FILTER( ?dateMeaning IN ( ?property ) ) .
FILTER( ?date >= xsd:gYear("1800")
&& ?date <= xsd:gYear("1900") )
?dateMeaning rdfs:label ?dateMeaningLabel .
FILTER( lang(?dateMeaningLabel) = "en" ) .
?thing rdfs:label ?thingLabel .
FILTER( lang(?thingLabel) = "en" )
}
ORDER BY ASC ( ?date )
]]></programlisting>
</sect3>
</sect2>
</sect1>
<!--
<sect1 id="rdfreplication"><title>RDF Replication</title>
<para>
Tables of RDF storage, such as DB.DBA.RDF_QUAD and DB.DBA.RDF_OBJ, can not be replicated in a usual way,
because it's content is cached in memory in special ways and synchronized with values outside these tables,
such as current values of special sequence objects.
Moreover, same IRI may have different internal IRI_IDs on different boxes, because the assigned IDs vary if new IRIs appear in data in different order.
Similarly, there will be different IDs of RDF literal, datatypes and languages, blocking any attempt of one-to-one replication between RDF storages.</para>
<para>
However, a special asynchronous RDF replication makes it possible to configure a "publisher" Virtuoso instance to keep the log of changes in some RDF graphs
and subscribe some Virtuoso instances to replay all these changes.</para>
<para>
Configuration functions are quite straightforward.</para>
<para>
RDF graphs to replicate are all members of <http://www.openlinksw.com/schemas/virtrdf#rdf_repl_graph_group> graph group.
That group can be filled in with graphs like any other graph group, but it is better to get the advantage of proper security check made by
</para>
<funcprototype id="fproto_DB.DBA.RDF_REPL_GRAPH_INS">
<funcdef>procedure <function>DB.DBA.RDF_REPL_GRAPH_INS</function></funcdef>
<paramdef>in <parameter>memb_iri</parameter> varchar</paramdef>
</funcprototype>
<para>
that inserts a graph to the group and</para>
<funcprototype id="fproto_DB.DBA.RDF_REPL_GRAPH_DEL">
<funcdef>procedure <function>DB.DBA.RDF_REPL_GRAPH_DEL</function></funcdef>
<paramdef>in <parameter>memb_iri</parameter> varchar</paramdef>
</funcprototype>
<para>
that removes a graph from the group.
Only publicly readable graphs can be replicated, an error is signalled otherwise, and it is better to know about a security issue as early as possible.</para>
<funcprototype id="fproto_DB.DBA.RDF_REPL_START">
<funcdef>procedure <function>DB.DBA.RDF_REPL_START</function></funcdef>
<paramdef>in <parameter>quiet</parameter> integer := 0</paramdef>
</funcprototype>
<para>
starts the RDF replication at the publishing side.
It creates replication "publication" named '__rdf_repl' and makes a log file '__rdf_repl.log' to record changes in replicated graphs.
If the replication has been started before then an error is signalled; passing value 1 for parameter "quiet" elimintaes the error so the incorrect call has no effect at all.
If the replication is enabled then the value of registry variable 'DB.DBA.RDF_REPL' indicates the moment of replication start.</para>
<para>
<function>DB.DBA.RDF_REPL_START</function>() performs a security check before starting the replication to check.</para>
<funcprototype id="fproto_DB.DBA.RDF_REPL_STOP">
<funcdef>procedure <function>DB.DBA.RDF_REPL_STOP</function></funcdef>
<paramdef> in <parameter>quiet</parameter> integer := 0</paramdef>
</funcprototype>
<para>
stops the RDF replication at the publishing side.
It calls <function><link linkend="fn_repl_unpublish">repl_unpublish</link></function> but does not make empty reates replication "publication" named '__rdf_repl' and makes a log file '__rdf_repl.log' to record changes in replicated graphs.</para>
<para>
Replication is asynchronous and the order of insertion and removal operations at the subscriber's side may not match the order at the publisher.
As a result, it is not recommended to make few subscriptions that writes changes of few publishers into one common graph.
A client-side application can force the synchronuzation by calling</para>
<funcprototype id="fproto_DB.DBA.RDF_REPL_SYNC">
<funcdef>procedure <function>DB.DBA.RDF_REPL_SYNC</function></funcdef>
<paramdef>in <parameter>publisher</parameter> varchar</paramdef>
<paramdef>in <parameter>user</parameter> varchar</paramdef>
<paramdef>in <parameter>pwd</parameter> varchar</paramdef>
</funcprototype>
<para>
that acts like <function><link linkend="fn_repl_sync">repl_sync</link></function> but for an RDF subscription.
<function>DB.DBA.RDF_REPL_SYNC</function> will not only initial synchronisation but also wait for the end of subscription to guarantee that the total effect of INSERT and DELETE operations is correct even if these operations were made in an order that differs from the original one.</para>
</sect1>
-->
<sect1 id="rdfperformancetuning"><title>Performance Tuning</title>
<para>For RDF query performance, we have the following possible questions:</para>
<itemizedlist mark="bullet" spacing="compact">
<listitem>Is the Virtuoso process properly configured to handle big data sets?</listitem>
<listitem>Is the graph always specified?</listitem>
<listitem>Are public web service endpoints protected against bad queries?</listitem>
<listitem>Are there patterns where only a predicate is given?</listitem>
<listitem>Is there a bad query plan because of cost model error?</listitem>
</itemizedlist>
<sect2 id="rdfperfgeneral"><title>General</title>
<para>For running with large data sets, one should configure the Virtuoso process to use between 2/3 to 3/5 of system RAM and to stripe storage on all available disks. See <link linkend="VIRTINI">NumberOfBuffers</link> and <link linkend="VIRTINI">Striping</link> ini parameters.</para>
<para> Also, if running with a large database, setting <link linkend="VIRTINI">MaxCheckpointRemap</link> to 1/4th of
the database size is recommended. This is in pages, 8K per page.</para>
</sect2>
<sect2 id="rdfperfrdfscheme"><title>RDF Index Scheme</title>
<para>
Starting with version 6.00.3126 the default RDF index scheme consists
of 2 full indices over RDF quads plus 3 partial indices. This index
scheme is generally adapted to all kinds of workloads, regardless of
whether queries generally specify a graph.
</para>
<para>
Alternate indexing schemes are possible but will not be generally needed.
For upgrading old databases with a different index scheme see the corresponding documentation.
</para>
<para>
The index scheme consists of the following indices:
</para>
<itemizedlist mark="bullet">
<listitem><emphasis>PSOG</emphasis> - primary key</listitem>
<listitem><emphasis>POGS</emphasis> - bitmap index for lookups on object value.</listitem>
<listitem><emphasis>SP</emphasis> - partial index for cases where only S is specified.</listitem>
<listitem><emphasis>OP</emphasis> - partial index for cases where only O is specified.</listitem>
<listitem><emphasis>GS</emphasis> - partial index for cases where only G is specified.</listitem>
</itemizedlist>
<para>
This index scheme is created by the following statements:
</para>
<programlisting><![CDATA[
create table DB.DBA.RDF_QUAD (
G IRI_ID_8,
S IRI_ID_8,
P IRI_ID_8,
O any,
primary key (P, S, O, G)
)
alter index RDF_QUAD on DB.DBA.RDF_QUAD partition (S int (0hexffff00));
create distinct no primary key ref bitmap index RDF_QUAD_SP on RDF_QUAD (S, P) partition (S int (0hexffff00));
create bitmap index RDF_QUAD_POGS on RDF_QUAD (P, O, G, S) partition (O varchar (-1, 0hexffff));
create distinct no primary key ref bitmap index RDF_QUAD_GS on RDF_QUAD (G, S) partition (S int (0hexffff00));
create distinct no primary key ref index RDF_QUAD_OP on RDF_QUAD (O, P) partition (O varchar (-1, 0hexffff));
;
]]></programlisting>
<para>
The idea is to favor queries where the predicate is specified in
triple patterns. The entire quad can be efficiently accessed when P
and either or both S and O are known. This has the advantage of
clustering data by the predicate which improves working set: A page
read from disk will only have entries pertaining to the same
predicate, chances of accessing other entries of the page are thus
higher than if the page held values for arbitrary predicates. For
less frequent cases where only S is known, as in describe, the
distinct P's of the S are found in the SP index. These SP pairs are
then used for accessing the PSOG index to get the O and G. For cases
where only the G is known, as in dropping a graph, the distinct S's of
the G are found in the GS index. The P's of the S are then found in
the SP index. After this the whole quad is found in the PSOG index.
</para>
<para>
The SP, OP and GS indices do not store duplicates. If a S has many
values of the P, there is only one entry. Extries are not deleted
from SP, OP or GS. This does not lead to erroneous results since a
full index, that is either POSG or PSOG is always consulted in order
to know if a quad actually exists. For cases of updating data, most
often a graph is entirely dropped and a substantially similar graph is
inserted in its place. The SP, OP and GS indices get to stay relatively unaffected.
</para>
<para>
Still over time specially if there are frequent updates and values do not repeat between
consecutive states the SP, OP and GS indices will get polluted which may affect performance.
Dropping and recreating the index will then remedy the situation.
</para>
<para>
For cases where this is not practical the index scheme should only have full indices, i.e.
each key holds all columns of the primary key of the quad. This will be the case if the
distinct no primary key ref options are not specified in the create index statement. In
such cases all indices remain in strict sync across deletes.
</para>
<para>
Many RDF workloads have bulk load and read intensive access patterns with few deletes.
The default index scheme is optimized for these. With these situations this scheme offers
significant space savings resulting in better working set. Typically this layout takes
60-70% of the space of a layout with 4 full indices.
</para>
</sect2>
<sect2 id="rdfperfindexes"><title>Index Scheme Selection</title>
<para>If the graph is always given, as one or more <emphasis>FROM</emphasis> or <emphasis>FROM NAMED</emphasis>, and there are no patterns where only graph and predicate are given, then the default indices should be appropriate.
If the predicate and graph are given but subject is not, then it is sometimes useful to add</para>
<programlisting><![CDATA[
create bitmap index RDF_QUAD_PGOS on DB.DBA.RDF_QUAD (G, P, O, S) partition (O varchar (-1, 0hexffff));
]]></programlisting>
<note><para>If the server is pre 5.0.7, leave out the partitioning clause.</para></note>
<para>Making the PGOS index can help in some cases even if it is not readily apparent from the queries that one is needed. This is so for example if the predicate by itself is selective, i.e. there is a predicate that occurs in only a few triples.</para>
<para>If the graph itself is not given in the queries, then the default index scheme will be unworkable.
For this, the appropriate scheme is:</para>
<programlisting><![CDATA[
create table RDF_QUAD (G iri_id_8, S iri_id_8, P iri_id_8, O any, primary key (S, P, O, G))
alter index RDF_QUAD on RDF_QUAD partition (S int (0hexffff00));
create bitmap index RDF_QUAD_OPGS on DB.DBA.RDF_QUAD (O, P, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_POGS on DB.DBA.RDF_QUAD (P, O, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_GPOS on DB.DBA.RDF_QUAD (G, P, O, S) partition (O varchar (-1, 0hexffff));
]]></programlisting>
<note><para>For a pre 5.0.7 server, leave the partition clauses and the alter index statement out.</para></note>
<para>If there are existing triples and one does not wish to reload them, then the following sequence will convert the data:</para>
<programlisting><![CDATA[
log_enable (2);
drop index RDF_QUAD_OGPS;
checkpoint;
create table R2 (G iri_id_8, S iri_id_8, P iri_id_8, O any, primary key (S, P, O, G))
alter index R2 on R2 partition (S int (0hexffff00));
insert into r2 (g, s, p, o) SELECT g, s, p, o from rdf_quad;
drop table RDF_QUAD;
checkpoint;
alter table r2 rename RDF_QUAD;
create bitmap index RDF_QUAD_OPGS on DB.DBA.RDF_QUAD (O, P, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_POGS on RDF_QUAD (P, O, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_GPOS on RDF_QUAD (G, P, O, S) partition (O varchar (-1, 0hexffff));
checkpoint;
log_enable (1);
]]></programlisting>
<para>First drop the OGPS index to make space. Then, in row autocommit mode
and without logging, copy the quads into a new primary key layout.
Drop the old and rename the new over the old. Make the additional
indices. Do a checkpoint after the drops so as to actually free the
space also in the checkpointed state. Finish with a checkpoint so as
to finalize the changes, since logging was turned off. Even if
logging had been on, one would not wish to have to replay the
reindexing if the server terminated abnormally.
Finally turn logging back on for the session.</para>
<note><para>This is all meant to be done with a SQL client like isql and not through a web interface.
The web interface has no real session and the log_enables do nothing there.</para></note>
<para>Other indexing schemes may be tried. We note however that in all
cases, one or other of the indices should begin with G. This is
because for schema operations it is necessary to read through a
graph. If no index begins with G, this becomes a full table scan and
is unworkable, leading to an extremely slow server start and making
operations like drop graph as good as unusable.</para>
<para>Public web service endpoints are proven to be sources of especially bad queries. While local
application develpers can obtain instructions from database administrator and use ISQL access to
the database in order to tune execution plans, "external" clients do not know details of
configuration and/or lacks appropriate skills. The most common problem is that public endpoints usually
get requests that does not mention the required graph, because that queries were initially written for
use with triple stores. If the web service provides access to a single graph (or to a short list of graphs)
then it is strongly recommended to configure it by adding a row into
<emphasis>DB.DBA.SYS_SPARQL_HOST</emphasis>. The idea is that if the client specifies default graph in
the request or uses named graphs and group graph patterns then he is probably smarter than average and
will provide meaningful queries. If no graph names are specified then the query will benefit from
preset graph because this will give the compiler some more indexes to choose from -- indexes taht begin
with G.</para>
<para>Sometimes web service endpoint is used to access data of only one application, not all data in the
system. In that case one may wish to declare a separate storage that consists of only RDF Views made
by that application and define <emphasis>input:storage</emphasis> in appropriate row of
<emphasis>DB.DBA.SYS_SPARQL_HOST</emphasis>.</para>
</sect2>
<sect2 id="rdfperfdumpandreloadgraphs"><title>Dump and Reload Graphs</title>
In order to dump all graphs with extension exclude those graphs of a certain type by using a
sparql ask query, you may use the following script sequence:
<programlisting><![CDATA[
create procedure dump_graphs (in dir varchar := 'dumps', in file_length_limit integer := 1000000000)
{
declare inx int;
inx := 1;
set isolation = 'uncommitted';
for (select * from (sparql define input:storage "" select distinct ?g { graph ?g { ?s ?p ?o } . filter ( ?g != virtrdf: ) } ) as sub option (loop)) do
{
dump_one_graph ("g", sprintf ('%s/graph%06d_', dir, inx), file_length_limit);
inx := inx + 1;
}
}
;
create procedure dump_one_graph (in srcgraph varchar, in out_file varchar, in file_length_limit integer := 1000000000)
{
declare file_name varchar;
declare env, ses any;
declare ses_len, max_ses_len, file_len, file_idx integer;
set isolation = 'uncommitted';
max_ses_len := 10000000;
file_len := 0;
file_idx := 1;
file_name := sprintf ('%s%06d.ttl', out_file, file_idx);
string_to_file (file_name || '.graph', srcgraph, -2);
string_to_file (file_name, sprintf ('# Dump of graph <%s>, as of %s\n', srcgraph, cast (now() as varchar)), -2);
--env := vector (dict_new (16000), 0, '', '', '', 0, 0);
env := vector (dict_new (16000), 0, '', '', '', 0, 0, 0, 0);
ses := string_output ();
for (select * from (sparql define input:storage "" select ?s ?p ?o { graph `iri(?:srcgraph)` { ?s ?p ?o } } ) as sub option (loop)) do
{
http_ttl_triple (env, "s", "p", "o", ses);
ses_len := length (ses);
if (ses_len > max_ses_len)
{
file_len := file_len + ses_len;
if (file_len > file_length_limit)
{
http (' .\n', ses);
string_to_file (file_name, ses, -1);
file_len := 0;
file_idx := file_idx + 1;
file_name := sprintf ('%s%06d.ttl', out_file, file_idx);
string_to_file (file_name, sprintf ('# Dump of graph <%s>, as of %s (part %d)\n', srcgraph, cast (now() as varchar), file_idx), -2);
env := vector (dict_new (16000), 0, '', '', '', 0, 0);
}
else
string_to_file (file_name, ses, -1);
ses := string_output ();
}
}
if (length (ses))
{
http (' .\n', ses);
string_to_file (file_name, ses, -1);
}
}
;
create procedure load_graphs (in dir varchar := 'dumps/')
{
declare arr any;
declare g varchar;
arr := sys_dirlist (dir, 1);
log_enable (2, 1);
foreach (varchar f in arr) do
{
if (f like '*.ttl')
{
declare continue handler for sqlstate '*'
{
log_message (sprintf ('Error in %s', f));
};
g := file_to_string (dir || '/' || f || '.graph');
DB.DBA.TTLP_MT (file_open (dir || '/' || f), g, g, 255);
}
}
exec ('checkpoint');
}
;
]]></programlisting>
</sect2>
<sect2 id="rdfperfdumpandreloadgraphsn3"><title>Dump RDF View Graph to n3</title>
<para>The RDF_QM_TREE_DUMP procedure and its associated procedures below are used
for dumping one or more RDFView Graphs in a Virtuoso server to a set of
turtle ttl dataset files in the specified dump directory. The dump generation
is made as fast as possible by grouping mappings by underlying tables so many
properties from neighbor database columns can be extracted in one table scan.
The size of the generated files is limited to 5MB. The dump process creates
internal stored procedures; their texts are saved in file .dump_procedures.sql in
the directory of dump files for debugging purposes.
</para>
<para>Note that the dump directory must be included in the <code>DirsAllowed</code>
parameter of the Virtuoso configuration file (e.g., <code>virtuoso.ini</code>), or the
server will not be allowed to create nor access the dataset file(s).
</para>
<para>
The <ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtBulkRDFLoader">Virtuoso RDF bulk loader</ulink>
scripts can then be used to load the dumped datasets for the RDFView graphs directly into
a Virtuoso RDF QUAD store.
</para>
<sect3 id="rdfperfdumpandreloadgraphsn3params"><title>Parameters</title>
<itemizedlist mark="bullet">
<listitem><code>in</code> <emphasis>dest_dir</emphasis> <code>VARCHAR</code> - dump directory </listitem>
<listitem><code>in</code> <emphasis>graph_iri</emphasis> <code>VARCHAR</code> - IRI of the graph to be dumped; triples from other graphs will be excluded. If NULL, then there's no restriction by graph.</listitem>
<listitem><code>in</code> <emphasis>storage</emphasis> <code>VARCHAR</code> - IRI of the quad map storage to use. NULL means use default storage.</listitem>
<listitem><code>in</code> <emphasis>root</emphasis> <code>VARCHAR</code> - IRI of the quad map to use, e.g., an IRI of an RDF View (or its part). NULL means use all RDF Views of the storage (and the default mapping as well).</listitem>
</itemizedlist>
</sect3>
<sect3 id="rdfperfdumpandreloadgraphsn3code"><title>Procedure Code</title>
<programlisting><![CDATA[
CREATE PROCEDURE DB.DBA.RDF_QM_TREE_DUMP
( in dest_dir VARCHAR,
in graph_iri VARCHAR := NULL,
in storage VARCHAR := NULL,
in root VARCHAR := NULL
)
{
DECLARE all_qms,
grouped_qmvs,
launcher_text ANY;
DECLARE grp_ctr,
qm_ctr,
qm_count INTEGER;
DECLARE sql_file,
launcher_name VARCHAR;
IF (NOT (dest_dir LIKE '%/'))
dest_dir := dest_dir || '/';
sql_file := dest_dir || '.dump_procedures.sql';
IF (storage IS NULL)
storage := 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage';
string_to_file (
sql_file,
'-- This file contains procedure created by DB.DBA.RDF_QM_TREE_DUMP() for storage '
|| COALESCE (storage, 'NULL')
|| ' and root quad map '
|| COALESCE (root, 'NULL')
|| '\n\n',
-2);
all_qms := dict_list_keys (DB.DBA.RDF_QM_CONTENT_OF_QM_TREE (graph_iri, storage, root), 2);
grouped_qmvs := DB.DBA.RDF_QM_GROUP_BY_SOURCE_TABLES (all_qms);
launcher_name := 'RDF_QM_TREE_DUMP_BATCH_' || md5 (serialize (graph_iri) || storage || serialize (root));
launcher_text := string_output ();
http ('CREATE PROCEDURE DB.DBA."' || launcher_name || '" (in dest_dir VARCHAR)\n{\n', launcher_text);
FOR (grp_ctr := length (grouped_qmvs); grp_ctr > 0; grp_ctr := grp_ctr-2)
{
DECLARE tables, qms, proc_text ANY;
DECLARE group_key, proc_name, dump_prefix, cmt VARCHAR;
tables := grouped_qmvs [grp_ctr-2];
qms := grouped_qmvs [grp_ctr-1];
qm_count := length (qms);
group_key := md5 (serialize (graph_iri) || storage || serialize (root) || serialize (tables));
proc_name := 'RDF_QM_TREE_DUMP_GRP_' || group_key;
proc_text := string_output ();
cmt := sprintf ('%d quad maps on join of', qm_count);
FOREACH (VARCHAR t IN tables) DO cmt := cmt || ' ' || t;
http (' -- ' || cmt || '\n', launcher_text);
http (' DB.DBA."' || proc_name || '" (dest_dir);\n', launcher_text);
http ('CREATE PROCEDURE DB.DBA."' || proc_name || '" (in dest_dir VARCHAR)\n', proc_text);
http ('{\n', proc_text);
http (' -- ' || cmt || '\n', proc_text);
http (' DECLARE ses, env ANY;\n', proc_text);
http (' DECLARE file_ctr, cmt_len INTEGER;\n', proc_text);
http (' file_ctr := 0;\n', proc_text);
http (' dbg_obj_princ (' || WS.WS.STR_SQL_APOS (cmt) || ', '', file '', file_ctr);\n', proc_text);
http (' ses := string_output ();\n', proc_text);
http (' http (' || WS.WS.STR_SQL_APOS ('#' || cmt || '\n') || ', ses);\n', proc_text);
http (' env := VECTOR (dict_new (16000), 0, '''', '''', '''', 0, 0, 0, 0);\n', proc_text);
http (' cmt_len := LENGTH (ses);\n', proc_text);
http (' FOR (SPARQL DEFINE input:storage <' || storage || '>\n', proc_text);
http (' SELECT ?s1, ?p1, ?o1\n', proc_text);
IF (graph_iri IS NOT NULL)
{
http (' WHERE { GRAPH <', proc_text); http_escape (graph_iri, 12, proc_text, 1, 1); http ('> {\n', proc_text);
}
ELSE
http (' WHERE { GRAPH ?g1 {\n', proc_text);
FOR (qm_ctr := 0; qm_ctr < qm_count; qm_ctr := qm_ctr + 1)
{
IF (qm_ctr > 0) http (' UNION\n', proc_text);
http (' { quad map <' || qms[qm_ctr] || '> { ?s1 ?p1 ?o1 } }\n', proc_text);
}
http (' } } ) DO {\n', proc_text);
http (' http_ttl_triple (env, "s1", "p1", "o1", ses);\n', proc_text);
http (' IF (LENGTH (ses) > 5000000)\n', proc_text);
http (' {\n', proc_text);
http (' http ('' .\\n'', ses);\n', proc_text);
http (' string_to_file (sprintf (''%s' || group_key || '_%05d.ttl'', dest_dir, file_ctr), ses, -2);\n', proc_text);
http (' file_ctr := file_ctr + 1;\n', proc_text);
http (' dbg_obj_princ (' || WS.WS.STR_SQL_APOS (cmt) || ', '', file '', file_ctr);\n', proc_text);
http (' ses := string_output ();\n', proc_text);
http (' http (' || WS.WS.STR_SQL_APOS ('#' || cmt || '\n') || ', ses);\n', proc_text);
http (' env := VECTOR (dict_new (16000), 0, '''', '''', '''', 0, 0, 0, 0);\n', proc_text);
http (' }\n', proc_text);
http (' }\n', proc_text);
http (' IF (LENGTH (ses) > cmt_len)\n', proc_text);
http (' {\n', proc_text);
http (' http ('' .\\n'', ses);\n', proc_text);
http (' string_to_file (sprintf (''%s' || group_key || '_%05d.ttl'', dest_dir, file_ctr), ses, -2);\n', proc_text);
http (' }\n', proc_text);
http ('}\n', proc_text);
proc_text := string_output_string (proc_text);
string_to_file (sql_file, proc_text || ';\n\n' , -1);
EXEC (proc_text);
}
http ('}\n', launcher_text);
launcher_text := string_output_string (launcher_text);
string_to_file (sql_file, launcher_text || ';\n\n' , -1);
EXEC (launcher_text);
CALL ('DB.DBA.' || launcher_name)(dest_dir);
}
;
CREATE FUNCTION DB.DBA.RDF_QM_CONTENT_OF_QM_TREE
( in graph_iri VARCHAR := NULL,
in storage VARCHAR := NULL,
in root VARCHAR := NULL,
in dict ANY := NULL
) returns ANY
{
DECLARE res, subqms any;
DECLARE graphiri varchar;
graphiri := DB.DBA.JSO_SYS_GRAPH();
IF (storage IS NULL)
storage := 'http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage';
DB.DBA.RDF_QM_ASSERT_STORAGE_FLAG (storage, 0);
IF (dict IS NULL)
dict := dict_new ();
IF (root IS NULL)
{
subqms := ((SELECT DB.DBA.VECTOR_AGG (sub."qmiri")
FROM (
SPARQL DEFINE input:storage ""
SELECT DISTINCT (str(?qm)) AS ?qmiri
WHERE { GRAPH `iri(?:graphiri)` {
{ `iri(?:storage)` virtrdf:qsUserMaps ?lst .
?lst ?p ?qm .
FILTER (0 = bif:strstr (str(?p), str(rdf:_)))
} UNION {
`iri(?:storage)` virtrdf:qsDefaultMap ?qm .
} } } ) AS sub ) );
FOREACH (varchar qmid IN subqms) DO
DB.DBA.RDF_QM_CONTENT_OF_QM_TREE (graph_iri, storage, qmid, dict);
RETURN dict;
}
DB.DBA.RDF_QM_ASSERT_JSO_TYPE (root, 'http://www.openlinksw.com/schemas/virtrdf#QuadMap');
IF (graph_iri IS NOT NULL AND
EXISTS ((SPARQL DEFINE input:storage ""
SELECT (1) WHERE {
GRAPH `iri(?:graphiri)` {
`iri(?:root)` virtrdf:qmGraphRange-rvrFixedValue ?g .
FILTER (str (?g) != str(?:graph_iri))
} } ) ) )
RETURN dict;
IF (NOT EXISTS ((SPARQL DEFINE input:storage ""
SELECT (1) WHERE {
GRAPH `iri(?:graphiri)` {
`iri(?:root)` virtrdf:qmMatchingFlags virtrdf:SPART_QM_EMPTY .
} } ) ) )
dict_put (dict, root, 1);
subqms := ((SELECT DB.DBA.VECTOR_AGG (sub."qmiri")
FROM (
SPARQL DEFINE input:storage ""
SELECT DISTINCT (str(?qm)) as ?qmiri
WHERE { GRAPH `iri(?:graphiri)` {
`iri(?:root)` virtrdf:qmUserSubMaps ?lst .
?lst ?p ?qm .
FILTER (0 = bif:strstr (str(?p), str(rdf:_)))
} } ) AS sub ) );
FOREACH (VARCHAR qmid IN subqms) DO
DB.DBA.RDF_QM_CONTENT_OF_QM_TREE (graph_iri, storage, qmid, dict);
RETURN dict;
}
;
CREATE FUNCTION DB.DBA.RDF_QM_GROUP_BY_SOURCE_TABLES (in qms ANY) returns ANY
{
DECLARE res ANY;
DECLARE ctr INTEGER;
DECLARE graphiri VARCHAR;
graphiri := DB.DBA.JSO_SYS_GRAPH();
res := dict_new (LENGTH (qms) / 20);
FOREACH (VARCHAR qmiri IN qms) DO
{
DECLARE tbls, acc ANY;
tbls := ((SELECT DB.DBA.VECTOR_AGG (sub."tbl")
FROM (SELECT subsub."tbl"
FROM (
SPARQL DEFINE input:storage ""
SELECT DISTINCT ?tbl
WHERE { GRAPH `iri(?:graphiri)` {
{ `iri(?:qmiri)` virtrdf:qmTableName ?tbl .
} UNION {
`iri(?:qmiri)` virtrdf:qmATables ?atbls .
?atbls ?p ?atbl .
?atbl virtrdf:qmvaTableName ?tbl
} UNION {
`iri(?:qmiri)` ?fldmap ?qmv .
?qmv virtrdf:qmvATables ?atbls .
?atbls ?p ?atbl .
?atbl virtrdf:qmvaTableName ?tbl .
} } } ) subsub
ORDER BY 1 ) AS sub ) );
acc := dict_get (res, tbls);
IF (acc IS NULL)
vectorbld_init (acc);
vectorbld_acc (acc, qmiri);
dict_put (res, tbls, acc);
}
res := dict_to_vector (res, 2);
FOR (ctr := LENGTH (res); ctr > 0; ctr := ctr-2)
{
DECLARE acc ANY;
acc := aref_set_0 (res, ctr-1);
vectorbld_final (acc);
aset_zap_arg (res, ctr-1, acc);
}
RETURN res;
}
;
--test dbg_obj_princ (DB.DBA.RDF_QM_GROUP_BY_SOURCE_TABLES (dict_list_keys (DB.DBA.RDF_QM_CONTENT_OF_QM_TREE (null), 2)));
--test dbg_obj_princ (dict_list_keys (DB.DBA.RDF_QM_CONTENT_OF_QM_TREE (null), 2));
--test DB.DBA.RDF_QM_TREE_DUMP ('dump/demo', null, null, null);
--test DB.DBA.RDF_QM_TREE_DUMP ('dump/tpch', 'http://localhost:8600/tpch', null, null);
]]></programlisting>
</sect3>
</sect2>
<sect2 id="rdfperfcost"><title>Erroneous Cost Estimates and Explicit Join Order</title>
<para>The selectivity of triple patterns is determined at query compile time from sampling the data.
It is possible that misleading data is produced.
To see if the cardinality guesses are generally valid, look at the query plan with <link linkend="fn_explain"><function>explain</function> ()</link>.</para>
<para>Below is a sample from the LUBM qualification data set in the Virtuoso distribution.
After running <emphasis>make test</emphasis> in <emphasis>binsrc/test/lubm</emphasis>, there is a loaded database with the data.
Start a server in the same directory to see the data.</para>
<programlisting><![CDATA[
SQL> explain ('SPARQL prefix ub: <http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#>
SELECT *
FROM <lubm>
WHERE { ?x rdf:type ub:GraduateStudent }');
REPORT
VARCHAR
_______________________________________________________________________________
{
Precode:
0: $25 "callret" := Call __BOX_FLAGS_TWEAK (<constant (lubm)>, <constant (1)>)
5: $26 "lubm" := Call DB.DBA.RDF_MAKE_IID_OF_QNAME_SAFE ($25 "callret")
12: $27 "callret" := Call __BOX_FLAGS_TWEAK (<constant (http://www.w3.org/1999/02/22-rdf-syntax-ns#type)>, <constant (1)>)
17: $28 "-ns#type" := Call DB.DBA.RDF_MAKE_IID_OF_QNAME_SAFE ($27 "callret")
24: $29 "callret" := Call __BOX_FLAGS_TWEAK (<constant (http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#GraduateStudent)>, <constant (1)>)
29: $30 "owl#GraduateStudent" := Call DB.DBA.RDF_MAKE_IID_OF_QNAME_SAFE ($29 "callret")
36: BReturn 0
from DB.DBA.RDF_QUAD by RDF_QUAD_OGPS 1.9e+03 rows
Key RDF_QUAD_OGPS ASC ($32 "s-3-1-t0.S")
<col=415 O = $30 "owl#GraduateStudent"> , <col=412 G = $26 "lubm"> , <col=414 P = $28 "-ns#type">
row specs: <col=415 O LIKE <constant (T)>>
Current of: <$34 "<DB.DBA.RDF_QUAD s-3-1-t0>" spec 5>
After code:
0: $35 "x" := Call ID_TO_IRI ($32 "s-3-1-t0.S")
5: BReturn 0
Select ($35 "x", <$34 "<DB.DBA.RDF_QUAD s-3-1-t0>" spec 5>)
}
22 Rows. -- 1 msec.
]]></programlisting>
<para>
This finds the graduate student instances in the lubm graph. First
the query converts the IRI literals to id's. Then, using a match of
OG on OGPS it finds the IRI's of the graduate students. Then it
converts the IRI id to return to the string form.</para>
<para>The cardinality estimate of 1.9e+03 rows is on the FROM line.</para>
<para>Doing an explain on the queries will show the cardinality estimates. To drill down further, one can split the query into smaller chunks and see the estimates for these, up to doing it at the triple pattern level.
To indicate a variable that is bound but whose value is not a literal known at compile time, one can use the parameter marker <emphasis>??</emphasis>.</para>
<programlisting><![CDATA[
SQL>explain ('SPARQL define sql:table-option "order" prefix ub: <http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#>
SELECT *
FROM <lubm>
WHERE { ?x rdf:type ?? }');
]]></programlisting>
<para>This will not know the type but will know that a type will be
provided. So instead of guessing 1900 matches, this will guess a
smaller number, which is obviously less precise. Thus literals are generally better.</para>
<para>In some cases, generally to work around an optimization error, one can specify an explicit join order.
This is done with the sql:select-option "order" clause in the SPARQL query prefix.</para>
<programlisting><![CDATA[
SQL>SELECT SPARQL_to_sql_text (' define sql:select-option "order" prefix ub: <http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#>
SELECT *
FROM <lubm>
WHERE
{
?x rdf:type ub:GraduateStudent .
?x ub:takesCourse <http://www.Department0.University0.edu/GraduateCourse0>
}');
]]></programlisting>
<para>shows the SQL text with the order option at the end.</para>
<para>If an estimate is radically wrong then this should be reported as a bug.</para>
<para>If there is a FROM with a KEY on the next line and no column specs then this is a full table scan. The more columns are specified the less rows will be passed to the next operation in the chain. In the example above, there are three columns whose values are known before reading the table and these columns are leading columns of the index in use so column specs are</para>
<programlisting><![CDATA[
<col=415 O = $30 "owl#GraduateStudent"> , <col=412 G = $26 "lubm"> , <col=414 P = $28 "-ns#type">
]]></programlisting>
<note><para>A KEY with only a row spec is a full table scan with the row spec applied as a filter.
This is usually not good unless this is specifically intended.</para></note>
<para>If queries are compiled to make full table scans when this is not specifically intended, this should be reported as a bug.
The explain output and the query text should be included in the report.</para>
<para>An explicit join order is specified by the <emphasis>define sql:select-option "order"</emphasis> clause in the SPARQL query prefix:
Consider:</para>
<programlisting><![CDATA[
SQL>explain ('SPARQL define sql:select-option "order, loop" prefix ub: <http://www.lehigh.edu/~zhp2/2004/0401/univ-bench.owl#>
SELECT *
FROM <lubm>
WHERE
{
?x ub:takesCourse ?c .
?x rdf:type ub:GraduateStudent
}');
]]></programlisting>
<para>One will see in the output that the first table access is to retrieve
all in the lubm graph which take some course and then later to check
if this is a graduate student. This is obviously not the preferred
order but the <emphasis>sql:select-option "order"</emphasis> forces the optimizer to join
from left to right.</para>
<para>It is very easy to end up with completely unworkable query plans in
this manner but if the optimizer really is in error, then this is the
only way of overriding its preferences. The effect of <emphasis>sql:select-option</emphasis> is pervasive, extending inside unions, optionals, subqueries etc within the statement.</para>
<para>We note that if, in the above query, both the course taken by the
student and the type of the student are given, the query compilation
will be, at least for all non-cluster cases, an index intersection.
This is not overridden by the sql:select-option clause since an index
intersection is always a safe guess, regardless of the correctness of
the cardinality guesses of the patterns involved.</para>
</sect2>
<sect2 id="rdfperfloading"><title>Loading</title>
<para>There are many functions for loading RDF text, in RDF/XML and Turtle.</para>
<para>For loading RDF/XML, the best way is to split the data to be loaded into
multiple streams and load these in parallel using <link linkend="fn_rdf_load_rdfxml"><function>RDF_LOAD_RDFXML ()</function></link>.
To avoid running out of rollback space for large files and in order to have multiple concurrent loads not
interfere with each other, the row autocommit mode should be enabled.</para>
<para>For example, </para>
<programlisting><![CDATA[
log_enable (2);
-- switch row-by-row autocommit on and logging off for this session
DB.DBA.RDF_LOAD_RDFXML (file_to_string_output ('file.xml'), 'base_uri', 'target_graph');
-- more files here ...
checkpoint;
]]></programlisting>
<para>Loading a file with text like the above with isql will load the data. Since the transaction
logging is off, make a manual checkpoint at the end to ensure that data is persisted upon server
restart since there is no roll forward log.</para>
<para>If large amounts of data are to be loaded, run multiple such streams in parallel. One may have
for example 6 streams for 4 cores. This means that if up to two threads wait for disk, there is still work
for all cores.</para>
<para>Having substantially more threads than processors or disks is not particularly useful.</para>
<para>There exist multithreaded load functions which will load one file on multiple threads. Experience
shows that loading multiple files on one thread per file is better.</para>
<para>For loading Turtle, some platforms may have a non-reentrant Turtle parser. This means that only
one load may run at a time. One can try this by calling
<link linkend="rdfapidataimport"><function>ttlp ()</function></link> from two sessions at the same time.
If these do not execute concurrently, then the best way may be to try
<link linkend="rdfapidataimport"><function>ttlp_mt</function></link> and see if this runs faster than
a single threaded ttlp call.</para>
<sect3 id="rdfperfloadinglod"><title>Loading LOD RDF data</title>
<para>To load the rdf data to LOD instance, perform the following steps:
</para>
<itemizedlist mark="bullet">
<listitem>Configure & start cluster</listitem>
<listitem>Execute the file:
<programlisting><![CDATA[
--
-- $Id: rdfandsparql.xml,v 1.95.2.36 2010/07/08 15:18:23 source Exp $
--
-- Alternate RDF index scheme for cases where G unspecified
--
-- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
-- project.
--
-- Copyright (C) 1998-2009 OpenLink Software
--
-- This project is free software; you can redistribute it and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation; only version 2 of the License, dated June 1991.
--
-- This program is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program; if not, write to the Free Software Foundation, Inc.,
-- 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
--
--
drop index RDF_QUAD_OGPS;
checkpoint;
create table R2 (G iri_id_8, S iri_id_8, P iri_id_8, O any, primary key (S, P, O, G))
alter index R2 on R2 partition (S int (0hexffff00));
log_enable (2);
insert into R2 (G, S, P, O) SELECT G, S, P, O from rdf_quad;
drop table RDF_QUAD;
alter table r2 rename RDF_QUAD;
checkpoint;
create bitmap index RDF_QUAD_OPGS on RDF_QUAD (O, P, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_POGS on RDF_QUAD (P, O, G, S) partition (O varchar (-1, 0hexffff));
create bitmap index RDF_QUAD_GPOS on RDF_QUAD (G, P, O, S) partition (O varchar (-1, 0hexffff));
checkpoint;
]]></programlisting>
</listitem>
<listitem>Execute the file:
<programlisting><![CDATA[
create table load_list (
ll_file varchar,
ll_graph varchar,
ll_state int default 0, -- 0 not started, 1 going, 2 done
ll_started datetime,
ll_done datetime,
ll_host int,
ll_work_time integer,
ll_error varchar,
primary key (ll_file))
alter index load_list on load_list partition (ll_file varchar)
;
create index ll_state on load_list (ll_state, ll_file, ll_graph) partition (ll_state int)
;
create table ldlock (id int primary key)
alter index ldlock on ldlock partition (id int)
;
insert into ldlock values (0);
create procedure
ld_dir (in path varchar, in mask varchar, in graph varchar)
{
declare ls any;
declare inx int;
ls := sys_dirlist (path, 1);
for (inx := 0; inx < length (ls); inx := inx + 1)
{
if (ls[inx] like mask)
{
set isolation = 'serializable';
if (not (exists (SELECT 1 FROM DB.DBA.LOAD_LIST WHERE LL_FILE = path || '/' || ls[inx] for update)))
{
declare gfile, cgfile, ngraph varchar;
gfile := path || '/' || replace (ls[inx], '.gz', '') || '.graph';
cgfile := path || '/' || regexp_replace (replace (ls[inx], '.gz', ''), '\\-[0-9]+\\.n', '.n') || '.graph';
if (file_stat (gfile) <> 0)
ngraph := trim (file_to_string (gfile), ' \r\n');
else if (file_stat (cgfile) <> 0)
ngraph := trim (file_to_string (cgfile), ' \r\n');
else if (file_stat (path || '/' || 'global.graph') <> 0)
ngraph := trim (file_to_string (path || '/' || 'global.graph'), ' \r\n');
else
ngraph := graph;
if (ngraph is not null)
{
insert into DB.DBA.LOAD_LIST (ll_file, ll_graph) values (path || '/' || ls[inx], ngraph);
}
}
commit work;
}
}
}
;
create procedure
ld_dir_all (in path varchar, in mask varchar, in graph varchar)
{
declare ls any;
declare inx int;
ls := sys_dirlist (path, 0);
ld_dir (path, mask, graph);
for (inx := 0; inx < length (ls); inx := inx + 1)
{
if (ls[inx] <> '.' and ls[inx] <> '..')
{
ld_dir_all (path||'/'||ls[inx], mask, graph);
}
}
}
;
create procedure
ld_add (in _fname varchar, in _graph varchar)
{
--log_message (sprintf ('ld_add: %s, %s', _fname, _graph));
set isolation = 'serializable';
if (not (exists (SELECT 1 FROM DB.DBA.LOAD_LIST WHERE LL_FILE = _fname for update)))
{
insert into DB.DBA.LOAD_LIST (LL_FILE, LL_GRAPH) values (_fname, _graph);
}
commit work;
}
;
create procedure ld_ttlp_flags (in fname varchar)
{
if (fname like '%/btc-2009%' or fname like '%.nq%')
return 255 + 512;
return 255;
}
create procedure
ld_file (in f varchar, in graph varchar)
{
declare gzip_name varchar;
declare exit handler for sqlstate '*' {
rollback work;
UPDATE DB.DBA.LOAD_LIST
SET LL_STATE = 2,
LL_DONE = curdatetime (),
LL_ERROR = __sql_state || ' ' || __sql_message
WHERE LL_FILE = f;
commit work;
log_message (sprintf (' File %s error %s %s', f, __sql_state, __sql_message));
return;
};
if (f like '%.grdf' or f like '%.grdf.gz')
{
load_grdf (f);
}
else if (f like '%.gz')
{
gzip_name := regexp_replace (f, '\.gz\x24', '');
if (gzip_name like '%.xml' or gzip_name like '%.owl' or gzip_name like '%.rdf')
DB.DBA.RDF_LOAD_RDFXML (gz_file_open (f), graph, graph);
else if (gzip_name like '%.n4')
TTLP (gz_file_open (f), graph, graph, 512 + 255);
else
TTLP (gz_file_open (f), graph, graph, ld_ttlp_flags (f));
}
else
{
if (f like '%.xml' or f like '%.owl' or f like '%.rdf')
DB.DBA.RDF_LOAD_RDFXML (file_open (f), graph, graph);
else if (f like '%.n4')
TTLP (file_open (f), graph, graph, 512 + 255);
else
TTLP (file_open (f), graph, graph, ld_ttlp_flags (f));
}
--log_message (sprintf ('loaded %s', f));
}
;
create procedure
rdf_load_dir (in path varchar,
in mask varchar := '%.nt',
in graph varchar := 'http://dbpedia.org')
{
DELETE FROM DB.DBA.LOAD_LIST WHERE LL_FILE = '##stop';
commit work;
ld_dir (path, mask, graph);
rdf_loader_run ();
}
;
create procedure ld_array ()
{
declare first, last, arr, len, local any;
declare cr cursor for
SELECT top 100 LL_FILE, LL_GRAPH
FROM DB.DBA.LOAD_LIST table option (index ll_state)
WHERE LL_STATE = 0
for update;
declare fill int;
declare f, g varchar;
declare r any;
whenever not found goto done;
first := 0;
last := 0;
arr := make_array (100, 'any');
fill := 0;
open cr;
len := 0;
for (;;)
{
fetch cr into f, g;
if (0 = first) first := f;
last := f;
arr[fill] := vector (f, g);
len := len + cast (file_stat (f, 1) as int);
fill := fill + 1;
if (len > 2000000)
goto done;
}
done:
if (0 = first)
return 0;
if (1 <> sys_stat ('cl_run_local_only'))
local := sys_stat ('cl_this_host');
UPDATE load_list set ll_state = 1, ll_started = curdatetime (), LL_HOST = local
WHERE ll_file >= first and ll_file <= last;
return arr;
}
;
create procedure
rdf_loader_run (in max_files integer := null, in log_enable int := 2)
{
declare sec_delay float;
declare _f, _graph varchar;
declare arr any;
declare xx, inx, tx_mode, ld_mode int;
ld_mode := log_enable;
if (0 = sys_stat ('cl_run_local_only'))
{
if (log_enable = 2 and cl_this_host () = 1)
{
cl_exec ('checkpoint_interval (0)');
cl_exec ('__dbf_set (''cl_non_logged_write_mode'', 1)');
}
if (cl_this_host () = 1)
cl_exec('__dbf_set(''cl_max_keep_alives_missed'',3000)');
}
tx_mode := bit_and (1, log_enable);
log_message ('Loader started');
DELETE FROM DB.DBA.LOAD_LIST WHERE LL_FILE = '##stop';
commit work;
while (1)
{
set isolation = 'repeatable';
declare exit handler for sqlstate '40001' {
rollback work;
sec_delay := rnd(1000)*0.001;
log_message(sprintf('deadlock in loader, waiting %d milliseconds', cast (sec_delay * 1000 as integer)));
delay(sec_delay);
goto again;
};
again:;
if (exists (SELECT 1 FROM DB.DBA.LOAD_LIST WHERE LL_FILE = '##stop'))
{
log_message ('File load stopped by rdf_load_stop.');
return;
}
log_enable (tx_mode, 1);
if (max_files is not null and max_files <= 0)
{
commit work;
log_message ('Max_files reached. Finishing.');
return;
}
whenever not found goto looks_empty;
-- log_message ('Getting next file.');
set isolation = 'serializable';
SELECT id into xx FROM ldlock WHERE id = 0 for update;
arr := ld_array ();
commit work;
if (0 = arr)
goto looks_empty;
log_enable (ld_mode, 1);
for (inx := 0; inx < 100; inx := inx + 1)
{
if (0 = arr[inx])
goto arr_done;
ld_file (arr[inx][0], arr[inx][1]);
UPDATE DB.DBA.LOAD_LIST set LL_STATE = 2, LL_DONE = curdatetime () WHERE LL_FILE = arr[inx][0];
}
arr_done:
log_enable (tx_mode, 1);
if (max_files is not null) max_files := max_files - 100;
commit work;
}
looks_empty:
commit work;
log_message ('No more files to load. Loader has finished,');
return;
}
;
create procedure rdf_load_stop (in force int := 0)
{
insert into DB.DBA.LOAD_LIST (LL_FILE) values ('##stop');
commit work;
if (force)
cl_exec ('txn_killall (1)');
}
;
create procedure RDF_LOADER_RUN_1 (in x int, in y int)
{
rdf_loader_run (x, y);
}
;
create procedure rdf_ld_srv (in log_enable int)
{
declare aq any;
aq := async_queue (1);
aq_request (aq, 'DB.DBA.RDF_LOADER_RUN_1', vector (null, log_enable));
aq_wait_all (aq);
}
;
create procedure load_grdf (in f varchar)
{
declare line any;
declare inx int;
declare ses any;
declare gr varchar;
if (f like '%.gz')
ses := gz_file_open (f);
else
ses := file_open (f);
inx := 0;
line := '';
while (line <> 0)
{
gr := ses_read_line (ses, 0, 0, 1);
if (gr = 0) return;
line := ses_read_line (ses, 0, 0, 1);
if (line = 0) return;
DB.DBA.RDF_LOAD_RDFXML (line, gr, gr);
inx := inx + 1;
}
}
;
-- cl_exec ('set lock_escalation_pct = 110');
-- cl_exec ('DB.DBA.RDF_LD_SRV (1)') &
-- cl_exec ('DB.DBA.RDF_LD_SRV (2)') &
]]></programlisting>
</listitem>
<listitem>Execute:
<programlisting><![CDATA[
SQL>cl_exec ('checkpoint);
]]></programlisting>
</listitem>
<listitem>Execute ld_dir ('directory' , 'mask' , 'graph'), for ex:
<programlisting><![CDATA[
SQL>ld_dir ('/dbs/data', '*.gz', 'http://dbpedia.org');
]]></programlisting>
</listitem>
<listitem>Execute on every node with separate client:
<programlisting><![CDATA[
SQL>rdf_loader_run();
]]></programlisting>
</listitem>
</itemizedlist>
</sect3>
<sect3 id="rdfperfloadingunitpro"><title>Loading UniProt RDF data</title>
<para>To load the uniprot data, create a function for example such as:</para>
<programlisting><![CDATA[
create function DB.DBA.UNIPROT_LOAD (in log_mode integer := 1)
{
DB.DBA.RDF_LOAD_RDFXML_MT (file_to_string_output('filename1'),'http://base_uri_1', 'destination_graph_1', log_mode, 3);
DB.DBA.RDF_LOAD_RDFXML_MT (file_to_string_output('filename2'),'http://base_uri_2', 'destination_graph_2', log_mode, 3);
...
DB.DBA.RDF_LOAD_RDFXML_MT (file_to_string_output('filename9'),'http://base_uri_9', 'destination_graph_9', log_mode, 3);
}
]]></programlisting>
<para>If you are starting from blank database and you can drop it and re-create in case of error signaled, use it this way:</para>
<programlisting><![CDATA[
checkpoint;
checkpoint_interval(6000);
DB.DBA.UNIPROT_LOAD (0),
checkpoint;
checkpoint_interval(60);
]]></programlisting>
<para>If the database contains important data already and there's no way to stop it and backup before the load then use:</para>
<programlisting><![CDATA[
checkpoint;
checkpoint_interval(6000);
DB.DBA.UNIPROT_LOAD (),
checkpoint;
checkpoint_interval(60);
]]></programlisting>
<para>Note that the 'number of threads' parameter of DB.DBA.RDF_LOAD_RDFXML() mentions threads
used to process data from file, an extra thread will read the text and parse it,
so for 4 CPU cores there's no need in parameter value greater than 3. Three processing
threads per one parsing tread is usually good ratio because parsing is usually three
times faster than the rest of loading so CPU loading is well balanced.
If for example you are using 2 x Quad Xeon, then you can choose between 8
single-threaded parsers or 2 parsers with 3 processing threads each. With 4 cores you may simply load
file after file with 3 processing threads. The most important performance tuning is to set the
[Parameters] section of virtuoso configuration file:</para>
<programlisting><![CDATA[
NumberOfBuffers = 1000000
MaxDirtyBuffers = 800000
MaxCheckpointRemap = 1000000
DefaultIsolation = 2
]]></programlisting>
<para>Note: these numbers are reasonable for 16 GB RAM Linux box. Usually when there are no such massive operations as loading huge database, you can set up the values as:</para>
<programlisting><![CDATA[
NumberOfBuffers = 1500000
MaxDirtyBuffers = 1200000
MaxCheckpointRemap = 1500000
DefaultIsolation = 2
]]></programlisting>
<para>Tip: Thus after loading all data you may wish to shutdown, tweak and start server again.
If you have ext2fs or ext3fs filesystem, then it's better to have enough free space on disk not to
make it more than 80% full. When it's almost full it may allocate database file badly, resulting
in measurable loss of disk access speed. That is not Virtuoso-specific fact, but a common hint
for all database-like applications with random access to big files.</para>
<para>Here is an example of using awk file for splitting big file smaller ones:</para>
<programlisting><![CDATA[
BEGIN {
file_part=1000
e_line = "</rdf:RDF>"
cur=0
cur_o=0
file=0
part=file_part
}
{
res_file_i="res/"FILENAME
line=$0
s=$1
res_file=res_file_i"_"file".rdf"
if (index (s, "</rdf:Description>") == 1)
{
cur=cur+1
part=part-1
}
if (part > 0)
{
print line >> res_file
}
if (part == 0)
{
# print "===================== " cur
print line >> res_file
print e_line >> res_file
close (res_file)
file=file+1
part=file_part
res_file=res_file_i"_"file".rdf"
system ("cp beg.txt " res_file)
}
}
END { }
]]></programlisting>
</sect3>
<sect3 id="rdfperfloadingdbpedia"><title>Loading DBPedia RDF data</title>
<para>You can use the following script as an example for loading DBPedia RDF data in Virtuoso:</para>
<programlisting><![CDATA[
#!/bin/sh
PORT=$1
USER=$2
PASS=$3
file=$4
g=$5
LOGF=`basename $0`.log
if [ -z "$PORT" -o -z "$USER" -o -z "$PASS" -o -z "$file" -o -z "$g" ]
then
echo "Usage: `basename $0` [DSN] [user] [password] [ttl-file] [graph-iri]"
exit
fi
if [ ! -f "$file" -a ! -d "$file" ]
then
echo "$file does not exists"
exit 1
fi
mkdir READY 2>/dev/null
rm -f $LOGF $LOGF.*
echo "Starting..."
echo "Logging into: $LOGF"
DOSQL ()
{
isql $PORT $USER $PASS verbose=on banner=off prompt=off echo=ON errors=stdout exec="$1" > $LOGF
}
LOAD_FILE ()
{
f=$1
g=$2
echo "Loading $f (`cat $f | wc -l` lines) `date \"+%H:%M:%S\"`" | tee -a $LOG
DOSQL "ttlp_mt (file_to_string_output ('$f'), '', '$g', 17); checkpoint;" > $LOGF
if [ $? != 0 ]
then
echo "An error occurred, please check $LOGF"
exit 1
fi
line_no=`grep Error $LOGF | awk '{ match ($0, /line [0-9]+/, x) ; match (x[0], /[0-9]+/, y); print y[0] }'`
newf=$f.part
inx=1
while [ ! -z "$line_no" ]
do
cat $f | awk "BEGIN { i = 1 } { if (i==$line_no) { print \$0; exit; } i = i + 1 }" >> bad.nt
line_no=`expr $line_no + 1`
echo "Retrying from line $line_no"
echo "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> ." > tmp.nt
cat $f | awk "BEGIN { i = 1 } { if (i>=$line_no) print \$0; i = i + 1 }" >> tmp.nt
mv tmp.nt $newf
f=$newf
mv $LOGF $LOGF.$inx
DOSQL "ttlp_mt (file_to_string_output ('$f'), '', '$g', 17); checkpoint;" > $LOGF
if [ $? != 0 ]
then
echo "An error occurred, please check $LOGF"
exit 1
fi
line_no=`grep Error $LOGF | awk '{ match ($0, /line [0-9]+/, x) ; match (x[0], /[0-9]+/, y); print y[0] }'`
inx=`expr $inx + 1`
done
rm -f $newf 2>/dev/null
echo "Loaded. "
}
echo "======================================="
echo "Loading started."
echo "======================================="
if [ -f "$file" ]
then
LOAD_FILE $file $g
mv $file READY 2>> /dev/null
elif [ -d "$file" ]
then
for ff in `find $file -name '*.nt'`
do
LOAD_FILE $ff $g
mv $ff READY 2>> /dev/null
done
else
echo "The input is not file or directory"
fi
echo "======================================="
echo "Final checkpoint."
DOSQL "checkpoint;" > temp.res
echo "======================================="
echo "Check bad.nt file for skipped triples."
echo "======================================="
exit 0
]]></programlisting>
</sect3>
<sect3 id="rdfperfloadingbio2rdf"><title>Loading Bio2RDF data</title>
<para>The shell script below was used to import files in n3 notation into OpenLink Virtuoso RDF storage.</para>
<para>When an syntax error it will cut content from next line and will retry. This was used on ubuntu linux to import bio2rdf and freebase dumps.</para>
<para>Note it uses gawk, so it must be available on system where is tried. Also for recovery additional disk space is needed at max the size of original file.</para>
<programlisting><![CDATA[
#!/bin/bash
PASS=$1
f=$2
g=$3
# Usage
if [ -z "$PASS" -o -z "$f" -o -z "$g" ]
then
echo "Usage: $0 [password] [ttl-file] [graph-iri]"
exit
fi
if [ ! -f "$f" ]
then
echo "$f does not exists"
exit
fi
# Your port here
PORT=1111 #`inifile -f dbpedia.ini -s Parameters -k ServerPort`
if test -z "$PORT"
then
echo "Cannot find INI and inifile command"
exit
fi
# Initial run
isql $PORT dba $PASS verbose=on banner=off prompt=off echo=ON errors=stdout exec="ttlp_mt (file_to_string_output ('$f'), '', '$g'); checkpoint;" > $0.log
# If disconnect etc.
if [ $? != 0 ]
then
echo "An error occurred, please check $0.log"
exit
fi
# Check for error
line_no=`grep Error $0.log | awk '{ match ($0, /line [0-9]+/, x) ; match (x[0], /[0-9]+/, y); print y[0] }'`
newf=$f.part
inx=1
# Error recovery
while [ ! -z "$line_no" ]
do
cat $f | awk "BEGIN { i = 0 } { if (i==$line_no) { print \$0; exit; } i = i + 1 }" >> bad.nt
line_no=`expr $line_no + 1`
echo "Retrying from line $line_no"
cat $f | awk "BEGIN { i = 0 } { if (i>=$line_no) print \$0; i = i + 1 }" > tmp.nt
mv tmp.nt $newf
f=$newf
mv $0.log $0.log.$inx
# Run the recovered part
isql $PORT dba $PASS verbose=on banner=off prompt=off echo=ON errors=stdout exec="ttlp_mt (file_to_string_output ('$f'), '', '$g'); checkpoint;" > $0.log
if [ $? != 0 ]
then
echo "An error occurred, please check $0.log"
exit
fi
line_no=`grep Error $0.log | awk '{ match ($0, /line [0-9]+/, x) ; match (x[0], /[0-9]+/, y); print y[0] }'`
inx=`expr $inx + 1`
done
]]></programlisting>
</sect3>
</sect2>
<sect2 id="rdfperfsparul"><title>Using SPARUL</title>
<para>Since SPARUL updates are generally not ment to be transactional, it is
best to run these in <link linkend="fn_log_enable"><function>log_enable (2)</function></link> mode,
which commits every operation as it is done. This prevents one from running out of rollback space. Also for bulk updates, transaction logging can be turned off. If so, one should do a manual checkpoint after the operation to ensure persistence across server restart since there is no roll forward log.</para>
<para>To have a roll forward log and row by row autocommit, one may use <link linkend="fn_log_enable"><function>log_enable (3)</function></link>. This will write constantly into the log which takes extra time. Having no logging and doing a checkpoint when the whole work is finished is faster.</para>
<para>Many SPARUL operations can be run in parallel in this way. If they are independent with respect to their input and output, they can run in parallel and row by row autocommit will ensure they do not end up waiting for each others' locks.</para>
</sect2>
<sect2 id="rdfperfgeneraldbpedia"><title>DBpedia Benchmark</title>
<para>We ran the DBpedia benchmark queries again with different configurations of Virtuoso.
Comparing numbers given by different parties is a constant problem. In the case reported here,
we loaded the full DBpedia 3, all languages, with about 198M triples, onto Virtuoso v5 and Virtuoso Cluster
v6, all on the same 4 core 2GHz Xeon with 8G RAM. All databases were striped on 6 disks. The Cluster
configuration was with 4 processes in the same box.
We ran the queries in two variants:
</para>
<itemizedlist>
<listitem>With graph specified in the SPARQL FROM clause, using the default indices.</listitem>
<listitem>With no graph specified anywhere, using an alternate indexing scheme.</listitem>
</itemizedlist>
<para>The times below are for the sequence of 5 queries.
As there is a query in the set that specifies no condition on S or O and only P,
thus cannot be done with the default indices With Virtuoso v5. With Virtuoso Cluster v6 it can,
because v6 is more space efficient. So we added the index:</para>
<programlisting><![CDATA[
create bitmap index rdf_quad_pogs on rdf_quad (p, o, g, s);
]]></programlisting>
<table>
<tgroup cols="4">
<thead>
<row>
<entry></entry>
<entry>Virtuoso v5 with gspo, ogps, pogs</entry>
<entry>Virtuoso Cluster v6 with gspo, ogps</entry>
<entry>Virtuoso Cluster v6 with gspo, ogps, pogs</entry>
</row>
</thead>
<tbody>
<row><entry>cold</entry><entry>210 s</entry><entry>136 s</entry><entry>33.4 s</entry></row>
<row><entry>warm</entry><entry>0.600 s</entry><entry>4.01 s</entry><entry>0.628 s</entry></row>
</tbody>
</tgroup>
</table>
<para>Now let us do it without a graph being specified. Note that alter index is valid for v6 or higher.
For all platforms, we drop any existing indices, and:</para>
<programlisting><![CDATA[
create table r2 (g iri_id_8, s, iri_id_8, p iri_id_8, o any, primary key (s, p, o, g))
alter index R2 on R2 partition (s int (0hexffff00));
log_enable (2);
insert into r2 (g, s, p, o) SELECT g, s, p, o from rdf_quad;
drop table rdf_quad;
alter table r2 rename RDF_QUAD;
create bitmap index rdf_quad_opgs on rdf_quad (o, p, g, s) partition (o varchar (-1, 0hexffff));
create bitmap index rdf_quad_pogs on rdf_quad (p, o, g, s) partition (o varchar (-1, 0hexffff));
create bitmap index rdf_quad_gpos on rdf_quad (g, p, o, s) partition (o varchar (-1, 0hexffff));
]]></programlisting>
<para>The code is identical for v5 and v6, except that with v5 we use iri_id (32 bit) for
the type, not iri_id_8 (64 bit). We note that we run out of IDs with v5 around a few billion
triples, so with v6 we have double the ID length and still manage to be vastly more space efficient.</para>
<para>With the above 4 indices, we can query the data pretty much in any combination without hitting
a full scan of any index. We note that all indices that do not begin with s end with s as a bitmap.
This takes about 60% of the space of a non-bitmap index for data such as DBpedia.</para>
<para>If you intend to do completely arbitrary RDF queries in Virtuoso, then chances are
you are best off with the above index scheme.</para>
<table>
<tgroup cols="3">
<thead>
<row>
<entry></entry>
<entry>Virtuoso v5 with gspo, ogps, pogs</entry>
<entry>Virtuoso Cluster v6 with gspo, ogps, pogs</entry>
</row>
</thead>
<tbody>
<row><entry>warm</entry><entry>0.595 s</entry><entry>0.617 s</entry></row>
</tbody>
</tgroup>
</table>
<para>The cold times were about the same as above, so not reproduced.</para>
<para>It is in the SPARQL spirit to specify a graph and for pretty much any application,
there are entirely sensible ways of keeping the data in graphs and specifying which ones are
concerned by queries. This is why Virtuoso is set up for this by default.</para>
<para>On the other hand, for the open web scenario, dealing with an unknown large number of graphs,
enumerating graphs is not possible and questions like which graph of which source asserts x become
relevant. We have two distinct use cases which warrant different setups of the database, simple as that.</para>
<para>The latter use case is not really within the SPARQL spec, so implementations may or may not
support this.</para>
<para>Once the indices are right, there is no difference between specifying a graph and not specifying a
graph with the queries considered. With more complex queries, specifying a graph or set of graphs does
allow some optimizations that cannot be done with no graph specified. For example, bitmap intersections
are possible only when all leading key parts are given.</para>
<para>The best warm cache time is with v5; the five queries run under 600 ms after the first go.
This is noted to show that all-in-memory with a single thread of execution is hard to beat.</para>
<para>Cluster v6 performs the same queries in 623 ms. What is gained in parallelism is lost in latency
if all operations complete in microseconds. On the other hand, Cluster v6 leaves v5 in the dust in any
situation that has less than 100% hit rate. This is due to actual benefit from parallelism if operations
take longer than a few microseconds, such as in the case of disk reads. Cluster v6 has substantially
better data layout on disk, as well as fewer pages to load for the same content.</para>
<para>This makes it possible to run the queries without the pogs index on Cluster v6 even when v5 takes prohibitively long.</para>
<para>The purpose is to have a lot of RAM and space-efficient data representation.</para>
<para>For reference, the query texts specifying the graph are below. To run without specifying
the graph, just drop the FROM <http://dbpedia.org> from each query. The returned row counts are
indicated below each query's text.</para>
<programlisting><![CDATA[
SQL>SPARQL
SELECT ?p ?o
FROM <http://dbpedia.org>
WHERE
{
<http://dbpedia.org/resource/Metropolitan_Museum_of_Art> ?p ?o .
};
p o
VARCHAR VARCHAR
_______________________________________________________________________________
http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://umbel.org/umbel/ac/Artifact
http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://dbpedia.org/class/yago/MuseumsInNewYorkCity
http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://dbpedia.org/class/yago/ArtMuseumsAndGalleriesInTheUnitedStates
http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://dbpedia.org/class/yago/Museum103800563
..
-- 335 rows
SQL>SPARQL
PREFIX p: <http://dbpedia.org/property/>
SELECT ?film1 ?actor1 ?film2 ?actor2
FROM <http://dbpedia.org>
WHERE
{
?film1 p:starring <http://dbpedia.org/resource/Kevin_Bacon> .
?film1 p:starring ?actor1 .
?film2 p:starring ?actor1 .
?film2 p:starring ?actor2 .
};
film1 actor1 film2 ctor2
VARCHAR VARCHAR VARCHAR ARCHAR
http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Kevin_Bacon http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Kevin_Bacon
http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Kevin_Bacon http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Meryl_Streep
http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Kevin_Bacon http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Joseph_Mazzello
http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Kevin_Bacon http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/David_Strathairn
http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/Kevin_Bacon http://dbpedia.org/resource/The_River_Wild http://dbpedia.org/resource/John_C._Reilly
...
-- 23910 rows
SQL>SPARQL
PREFIX p: <http://dbpedia.org/property/>
SELECT ?artist ?artwork ?museum ?director
FROM <http://dbpedia.org>
WHERE
{
?artwork p:artist ?artist .
?artwork p:museum ?museum .
?museum p:director ?director
};
artist artwork museum director
VARCHAR VARCHAR VARCHAR VARCHAR
_______________________________________________
http://dbpedia.org/resource/Paul_C%C3%A9zanne http://dbpedia.org/resource/The_Basket_of_Apples http://dbpedia.org/resource/Art_Institute_of_Chicago James Cuno
http://dbpedia.org/resource/Paul_Signac http://dbpedia.org/resource/Neo-impressionism http://dbpedia.org/resource/Art_Institute_of_Chicago James Cuno
http://dbpedia.org/resource/Georges_Seurat http://dbpedia.org/resource/Neo-impressionism http://dbpedia.org/resource/Art_Institute_of_Chicago James Cuno
http://dbpedia.org/resource/Edward_Hopper http://dbpedia.org/resource/Nighthawks http://dbpedia.org/resource/Art_Institute_of_Chicago James Cuno
http://dbpedia.org/resource/Mary_Cassatt http://dbpedia.org/resource/The_Child%27s_Bath http://dbpedia.org/resource/Art_Institute_of_Chicago James Cuno
..
-- 303 rows
SQL>SPARQL
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?s ?homepage
FROM <http://dbpedia.org>
WHERE
{
<http://dbpedia.org/resource/Berlin> geo:lat ?berlinLat .
<http://dbpedia.org/resource/Berlin> geo:long ?berlinLong .
?s geo:lat ?lat .
?s geo:long ?long .
?s foaf:homepage ?homepage .
FILTER (
?lat <= ?berlinLat + 0.03190235436 &&
?long >= ?berlinLong - 0.08679199218 &&
?lat >= ?berlinLat - 0.03190235436 &&
?long <= ?berlinLong + 0.08679199218) };
s homepage
VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/Berlin_University_of_the_Arts http://www.udk-berlin.de/
http://dbpedia.org/resource/Berlin_University_of_the_Arts http://www.udk-berlin.de/
http://dbpedia.org/resource/Berlin_Zoological_Garden http://www.zoo-berlin.de/en.html
http://dbpedia.org/resource/Federal_Ministry_of_the_Interior_%28Germany%29 http://www.bmi.bund.de
http://dbpedia.org/resource/Neues_Schauspielhaus http://www.goya-berlin.com/
http://dbpedia.org/resource/Bauhaus_Archive http://www.bauhaus.de/english/index.htm
http://dbpedia.org/resource/Canisius-Kolleg_Berlin http://www.canisius-kolleg.de
http://dbpedia.org/resource/Franz%C3%B6sisches_Gymnasium_Berlin http://www.fg-berlin.cidsnet.de
..
-- 48 rows
SQL>SPARQL
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX p: <http://dbpedia.org/property/>
SELECT ?s ?a ?homepage
FROM <http://dbpedia.org>
WHERE
{
<http://dbpedia.org/resource/New_York_City> geo:lat ?nyLat .
<http://dbpedia.org/resource/New_York_City> geo:long ?nyLong .
?s geo:lat ?lat .
?s geo:long ?long .
?s p:architect ?a .
?a foaf:homepage ?homepage .
FILTER (
?lat <= ?nyLat + 0.3190235436 &&
?long >= ?nyLong - 0.8679199218 &&
?lat >= ?nyLat - 0.3190235436 &&
?long <= ?nyLong + 0.8679199218) };
s a homepage
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://dbpedia.org/resource/GE_Building http://dbpedia.org/resource/Associated_Architects http://www.associated-architects.co.uk
http://dbpedia.org/resource/Giants_Stadium http://dbpedia.org/resource/HNTB http://www.hntb.com/
http://dbpedia.org/resource/Fort_Tryon_Park_and_the_Cloisters http://dbpedia.org/resource/Frederick_Law_Olmsted http://www.asla.org/land/061305/olmsted.html
http://dbpedia.org/resource/Central_Park http://dbpedia.org/resource/Frederick_Law_Olmsted http://www.asla.org/land/061305/olmsted.html
http://dbpedia.org/resource/Prospect_Park_%28Brooklyn%29 http://dbpedia.org/resource/Frederick_Law_Olmsted http://www.asla.org/land/061305/olmsted.html
http://dbpedia.org/resource/Meadowlands_Stadium http://dbpedia.org/resource/360_Architecture http://oakland.athletics.mlb.com/oak/ballpark/new/faq.jsp
http://dbpedia.org/resource/Citi_Field http://dbpedia.org/resource/HOK_Sport_Venue_Event http://www.hoksve.com/
http://dbpedia.org/resource/Citigroup_Center http://dbpedia.org/resource/Hugh_Stubbins_Jr. http://www.klingstubbins.com
http://dbpedia.org/resource/150_Greenwich_Street http://dbpedia.org/resource/Fumihiko_Maki http://www.pritzkerprize.com/maki2.htm
http://dbpedia.org/resource/Freedom_Tower http://dbpedia.org/resource/David_Childs http://www.som.com/content.cfm/www_david_m_childs
http://dbpedia.org/resource/7_World_Trade_Center http://dbpedia.org/resource/David_Childs http://www.som.com/content.cfm/www_david_m_childs
http://dbpedia.org/resource/The_New_York_Times_Building http://dbpedia.org/resource/Renzo_Piano http://www.rpbw.com/
http://dbpedia.org/resource/Trump_World_Tower http://dbpedia.org/resource/Costas_Kondylis http://www.kondylis.com
13 Rows. -- 2183 msec.
]]></programlisting>
</sect2>
<sect2 id="rdfstorebenchmarks"><title>RDF Store Benchmarks</title>
<sect3 id="rdfstorebenchmarksintroduction"><title>Introduction</title>
<para>In a particular RDF Store Benchmarks there is difference if the queries are
executed with specified graph or with specified multiple graphs. As Virtuoso is quad store,
not triple store with many tables, it runs queries inefficiently if graphs are specified
and there are no additional indexes except pre-set GSPO and OGPS. Proper use of the FROM clause
or adding indexes with graph column will contribute for better results.
</para>
</sect3>
<sect3 id="rdfstorebenchmarksindexusage"><title>Using bitmap indexes</title>
<para>If is known in advance for the current RDF Store Benchmarks that some
users will not indicate specific graphs then should be done: </para>
<itemizedlist>
<listitem>either create indexes with graph in last position</listitem>
<listitem>or load everything into single graph and specify it somewhere in querying application.</listitem>
</itemizedlist>
<para>Both methods do not require any changes in query texts</para>
<itemizedlist mark="bullet">
<listitem>For users using Virtuoso 5 is strongly recommended is the usage of additional bitmap indexes:
<programlisting><![CDATA[
SQL> create bitmap index RDF_QUAD_POGS on DB.DBA.RDF_QUAD (P,O,G,S);
SQL> create bitmap index RDF_QUAD_PSOG on DB.DBA.RDF_QUAD (P,S,O,G);
]]></programlisting>
</listitem>
<listitem>For users using Virtuoso 6 or higher, see the new layout <link linkend="rdfperfrdfscheme">here</link>.</listitem>
</itemizedlist>
<para>You can create other indexes as well. Bitmap indexes are preferable, but
if O is the last column, then the index can not be bitmap, so it could be, for e.g.:</para>
<programlisting><![CDATA[
create index RDF_QUAD_PSGO on DB.DBA.RDF_QUAD (P, S, G, O);
]]></programlisting>
<para>but cannot be:</para>
<programlisting><![CDATA[
create bitmap index RDF_QUAD_PSGO on DB.DBA.RDF_QUAD (P, S, G, O);
]]></programlisting>
</sect3>
</sect2>
</sect1>
<sect1 id="rdfnativestorageproviders"><title>RDF Data Access Providers (Drivers)</title>
<sect2 id="rdfnativestorageprovidersjena"><title>Virtuoso Jena Provider</title>
<sect3 id="rdfnativestorageprovidersjenawhatis"><title>What is Jena</title>
<para>Jena is an open source Semantic Web framework for Java. It provides an API to
extract data from and write to RDF graphs. The graphs are represented as an abstract "model".
A model can be sourced with data from files, databases, URIs or a combination of these. A Model
can also be queried through SPARQL and updated through SPARUL.
</para>
</sect3>
<sect3 id="rdfnativestorageprovidersjenawhatisv"><title>What is the Virtuoso Jena Provider</title>
<para>The Virtuoso Jena RDF Data Provider is a fully operational Native Graph Model Storage
Provider for the Jena Framework, enables Semantic Web applications written using the Jena RDF
Frameworks to query the Virtuoso RDF Quad store directly. The Provider has been tested against
the <ulink url="http://jena.sourceforge.net/">Jena 2.5.5</ulink> version currently available.
</para>
<figure id="rdfnativestorageprovidersjena1" float="1">
<title>Virtuoso Jena RDF Data Provider</title>
<graphic fileref="ui/VirtJenaProvider.png"/>
</figure>
</sect3>
<sect3 id="rdfnativestorageprovidersjenasetup"><title>Setup</title>
<sect4 id="rdfnativestorageprovidersjenareqfiles"><title>Required Files</title>
<itemizedlist mark="bullet">
<listitem>Virtuoso Jena Provider JAR file, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtJenaProvider/virt_jena.jar">virt_jena.jar</ulink></listitem>
<listitem>Virtuoso JDBC Driver JAR file, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtJenaProvider/virtjdbc3.jar">virtjdbc3.jar</ulink></listitem>
<listitem>Jena Framework and associated classes, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtJenaProvider/jenajars.zip">jenajars.zip</ulink></listitem>
<listitem>Sample programs, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtJenaProvider/virtjenasamples.zip">virtjenasamples.zip</ulink></listitem>
</itemizedlist>
</sect4>
<sect4 id="rdfnativestorageprovidersjenacmsmpr"><title>Compiling Jena Sample Programs</title>
<orderedlist>
<listitem>Edit the sample programs VirtuosoSPARQLExampleX.java, where X = 1 to 9.
Set the JDBC connection strings within to point to a valid Virtuoso Server instance of the form:
<programlisting><![CDATA[
"jdbc:virtuoso://localhost:1111/charset=UTF-8/log_enable=2"
]]></programlisting>
<itemizedlist>
<listitem>charset=UTF-8 will be added by Jena provider, if it isn't in connection string.
So now you don't need add "charset=UTF-8" to the connection string any more, it is done by Jena provider.
</listitem>
<listitem>log_enable=2: to use row auto commit
</listitem>
<listitem>use these settings to process large rdf data.
</listitem>
</itemizedlist>
</listitem>
<listitem>Ensure that full paths to <emphasis>jena.jar, arq.jar,</emphasis> and
<emphasis>virtjdbc3.jar</emphasis> are included in the active CLASSPATH setting.
</listitem>
<listitem>Compile the Jena Sample applications using the following command:
<programlisting><![CDATA[
javac -cp "jena.jar:arq.jar:virtjdbc3.jar:virt_jena.jar:." VirtuosoSPARQLExample1.java
VirtuosoSPARQLExample2.java VirtuosoSPARQLExample3.java VirtuosoSPARQLExample4.java
VirtuosoSPARQLExample5.java VirtuosoSPARQLExample6.java VirtuosoSPARQLExample7.java
VirtuosoSPARQLExample8.java VirtuosoSPARQLExample9.java
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
<sect4 id="rdfnativestorageprovidersjenatesting"><title>Testing</title>
<para>Once the Provider classes and sample program have been successfully compiled,
the Provider can be tested using the sample programs included. Ensure your active CLASSPATH
includes full paths to all of the following files, before executing the example commands:
</para>
<itemizedlist mark="bullet">
<listitem>icu4j_3_4.jar</listitem>
<listitem>iri.jar</listitem>
<listitem>xercesImpl.jar</listitem>
<listitem>axis.jar</listitem>
<listitem>commons-logging-1.1.1.jar</listitem>
<listitem>jena.jar</listitem>
<listitem>arq.jar</listitem>
<listitem>virtjdbc3.jar</listitem>
<listitem>virt_jena.jar</listitem>
</itemizedlist>
<orderedlist>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples1">VirtuosoSPARQLExample1</link> returns the contents of the RDF Quad store of the targeted Virtuoso instance, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample1
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples2">VirtuosoSPARQLExample2</link> reads in the contents of the following FOAF URIs --
<programlisting><![CDATA[
http://kidehen.idehen.net/dataspace/person/kidehen#this
http://www.w3.org/People/Berners-Lee/card#i
http://demo.openlinksw.com/dataspace/person/demo#this
]]></programlisting>
<para>-- and returns the RDF data stored, with the following command:</para>
<programlisting><![CDATA[
java VirtuosoSPARQLExample2
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples3">VirtuosoSPARQLExample3</link> performs simple addition and deletion operation on
the content of the triple store, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample3
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples4">VirtuosoSPARQLExample4</link> demonstrates the use of the <emphasis>graph.contains</emphasis> method for searching triples, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample4
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples5">VirtuosoSPARQLExample5</link> demonstrates the use of the <emphasis>graph.find</emphasis> method for searching triples, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample5
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples6">VirtuosoSPARQLExample6</link> demonstrates the use of the <emphasis>graph.getTransactionHandler</emphasis> method, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample6
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples7">VirtuosoSPARQLExample7</link> demonstrates the use of the graph.getBulkUpdateHandler method, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample7
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples8">VirtuosoSPARQLExample8</link> demonstrates how to insert triples into a graph, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample8
]]></programlisting>
</listitem>
<listitem><link linkend="rdfnativestorageprovidersjenaexamples9">VirtuosoSPARQLExample9</link> demonstrates the use of the <emphasis>CONSTRUCT, DESCRIBE,</emphasis> and <emphasis>ASK</emphasis> SPARQL query forms, with the following command:
<programlisting><![CDATA[
java VirtuosoSPARQLExample9
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
</sect3>
<sect3 id="rdfnativestorageprovidersjenaexamples"><title>Examples</title>
<sect4 id="rdfnativestorageprovidersjenaexamples1"><title>VirtJenaSPARQLExample1</title>
<programlisting><![CDATA[
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.RDFNode;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample1 {
/**
* Executes a SPARQL query against a virtuoso url and prints results.
*/
public static void main(String[] args) {
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
/* STEP 1 */
VirtGraph set = new VirtGraph (url, "dba", "dba");
/* STEP 2 */
/* STEP 3 */
/* Select all data in virtuoso */
Query sparql = QueryFactory.create("SELECT * WHERE { GRAPH ?graph { ?s ?p ?o } } limit 100");
/* STEP 4 */
VirtuosoQueryExecution vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
ResultSet results = vqe.execSelect();
while (results.hasNext()) {
QuerySolution result = results.nextSolution();
RDFNode graph = result.get("graph");
RDFNode s = result.get("s");
RDFNode p = result.get("p");
RDFNode o = result.get("o");
System.out.println(graph + " { " + s + " " + p + " " + o + " . }");
}
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples2"><title>VirtJenaSPARQLExample2</title>
<programlisting><![CDATA[
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.RDFNode;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample2 {
/**
* Executes a SPARQL query against a virtuoso url and prints results.
*/
public static void main(String[] args) {
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
/* STEP 1 */
VirtGraph graph = new VirtGraph ("Example2", url, "dba", "dba");
/* STEP 2 */
/* Load data to Virtuoso */
graph.clear ();
System.out.print ("Begin read from 'http://www.w3.org/People/Berners-Lee/card#i' ");
graph.read("http://www.w3.org/People/Berners-Lee/card#i", "RDF/XML");
System.out.println ("\t\t\t Done.");
System.out.print ("Begin read from 'http://demo.openlinksw.com/dataspace/person/demo#this' ");
graph.read("http://demo.openlinksw.com/dataspace/person/demo#this", "RDF/XML");
System.out.println ("\t Done.");
System.out.print ("Begin read from 'http://kidehen.idehen.net/dataspace/person/kidehen#this' ");
graph.read("http://kidehen.idehen.net/dataspace/person/kidehen#this", "RDF/XML");
System.out.println ("\t Done.");
/* STEP 3 */
/* Select only from VirtGraph */
Query sparql = QueryFactory.create("SELECT ?s ?p ?o WHERE { ?s ?p ?o }");
/* STEP 4 */
VirtuosoQueryExecution vqe = VirtuosoQueryExecutionFactory.create (sparql, graph);
ResultSet results = vqe.execSelect();
while (results.hasNext()) {
QuerySolution result = results.nextSolution();
RDFNode graph_name = result.get("graph");
RDFNode s = result.get("s");
RDFNode p = result.get("p");
RDFNode o = result.get("o");
System.out.println(graph_name + " { " + s + " " + p + " " + o + " . }");
}
System.out.println("graph.getCount() = " + graph.getCount());
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples3"><title>VirtJenaSPARQLExample3</title>
<programlisting><![CDATA[
import java.util.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample3
{
public static void main(String[] args)
{
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
Node foo1 = Node.createURI("http://example.org/#foo1");
Node bar1 = Node.createURI("http://example.org/#bar1");
Node baz1 = Node.createURI("http://example.org/#baz1");
Node foo2 = Node.createURI("http://example.org/#foo2");
Node bar2 = Node.createURI("http://example.org/#bar2");
Node baz2 = Node.createURI("http://example.org/#baz2");
Node foo3 = Node.createURI("http://example.org/#foo3");
Node bar3 = Node.createURI("http://example.org/#bar3");
Node baz3 = Node.createURI("http://example.org/#baz3");
List <Triple> triples = new ArrayList <Triple> ();
VirtGraph graph = new VirtGraph ("Example3", url, "dba", "dba");
graph.clear ();
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("Add 3 triples to graph <Example3>.");
graph.add(new Triple(foo1, bar1, baz1));
graph.add(new Triple(foo2, bar2, baz2));
graph.add(new Triple(foo3, bar3, baz3));
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
triples.add(new Triple(foo1, bar1, baz1));
triples.add(new Triple(foo2, bar2, baz2));
graph.isEmpty();
System.out.println("Remove 2 triples from graph <Example3>");
graph.remove(triples);
System.out.println("graph.getCount() = " + graph.getCount());
System.out.println("Please check result with isql tool.");
/* EXPECTED RESULT:
SQL> SPARQL
SELECT ?s ?p ?o
FROM <Example3>
WHERE {?s ?p ?o};
s p o
VARCHAR VARCHAR VARCHAR
_______________________________________________________________________________
http://example.org/#foo3 http://example.org/#bar3 http://example.org/#baz3
1 Rows. -- 26 msec.
SQL>
*/
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples4"><title>VirtJenaSPARQLExample4</title>
<programlisting><![CDATA[
import java.util.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample4
{
public static void main(String[] args)
{
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
Node foo1 = Node.createURI("http://example.org/#foo1");
Node bar1 = Node.createURI("http://example.org/#bar1");
Node baz1 = Node.createURI("http://example.org/#baz1");
Node foo2 = Node.createURI("http://example.org/#foo2");
Node bar2 = Node.createURI("http://example.org/#bar2");
Node baz2 = Node.createURI("http://example.org/#baz2");
Node foo3 = Node.createURI("http://example.org/#foo3");
Node bar3 = Node.createURI("http://example.org/#bar3");
Node baz3 = Node.createURI("http://example.org/#baz3");
VirtGraph graph = new VirtGraph ("Example4", url, "dba", "dba");
graph.clear ();
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("Add 3 triples to graph <Example4>.");
graph.add(new Triple(foo1, bar1, baz1));
graph.add(new Triple(foo2, bar2, baz2));
graph.add(new Triple(foo3, bar3, baz3));
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
System.out.println ("graph.contains(new Triple(foo2, bar2, baz2) - " + graph.contains(new Triple(foo2, bar2, baz2)));
System.out.println ("graph.contains(new Triple(foo2, bar2, baz3) - " + graph.contains(new Triple(foo2, bar2, baz3)));
graph.clear ();
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples5"><title>VirtJenaSPARQLExample5</title>
<programlisting><![CDATA[
import java.util.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample5
{
public static void main(String[] args)
{
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
Node foo1 = Node.createURI("http://example.org/#foo1");
Node bar1 = Node.createURI("http://example.org/#bar1");
Node baz1 = Node.createURI("http://example.org/#baz1");
Node foo2 = Node.createURI("http://example.org/#foo2");
Node bar2 = Node.createURI("http://example.org/#bar2");
Node baz2 = Node.createURI("http://example.org/#baz2");
Node foo3 = Node.createURI("http://example.org/#foo3");
Node bar3 = Node.createURI("http://example.org/#bar3");
Node baz3 = Node.createURI("http://example.org/#baz3");
VirtGraph graph = new VirtGraph ("Example5", url, "dba", "dba");
graph.clear ();
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("Add 3 triples to graph <Example5>.");
graph.add(new Triple(foo1, bar1, baz1));
graph.add(new Triple(foo2, bar2, baz2));
graph.add(new Triple(foo3, bar3, baz3));
graph.add(new Triple(foo1, bar2, baz2));
graph.add(new Triple(foo1, bar3, baz3));
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
ExtendedIterator iter = graph.find(foo1, Node.ANY, Node.ANY);
System.out.println ("\ngraph.find(foo1, Node.ANY, Node.ANY) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
iter = graph.find(Node.ANY, Node.ANY, baz3);
System.out.println ("\ngraph.find(Node.ANY, Node.ANY, baz3) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
iter = graph.find(foo1, Node.ANY, baz3);
System.out.println ("\ngraph.find(foo1, Node.ANY, baz3) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
graph.clear ();
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples6"><title>VirtJenaSPARQLExample6</title>
<programlisting><![CDATA[
import java.util.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample6
{
public static void main(String[] args)
{
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
Node foo1 = Node.createURI("http://example.org/#foo1");
Node bar1 = Node.createURI("http://example.org/#bar1");
Node baz1 = Node.createURI("http://example.org/#baz1");
Node foo2 = Node.createURI("http://example.org/#foo2");
Node bar2 = Node.createURI("http://example.org/#bar2");
Node baz2 = Node.createURI("http://example.org/#baz2");
Node foo3 = Node.createURI("http://example.org/#foo3");
Node bar3 = Node.createURI("http://example.org/#bar3");
Node baz3 = Node.createURI("http://example.org/#baz3");
VirtGraph graph = new VirtGraph ("Example6", url, "dba", "dba");
graph.clear ();
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("test Transaction Commit.");
graph.getTransactionHandler().begin();
System.out.println("begin Transaction.");
System.out.println("Add 3 triples to graph <Example6>.");
graph.add(new Triple(foo1, bar1, baz1));
graph.add(new Triple(foo2, bar2, baz2));
graph.add(new Triple(foo3, bar3, baz3));
graph.getTransactionHandler().commit();
System.out.println("commit Transaction.");
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
ExtendedIterator iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
System.out.println ("\ngraph.find(Node.ANY, Node.ANY, Node.ANY) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
graph.clear ();
System.out.println("\nCLEAR graph <Example6>");
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("Add 1 triples to graph <Example6>.");
graph.add(new Triple(foo1, bar1, baz1));
System.out.println("test Transaction Abort.");
graph.getTransactionHandler().begin();
System.out.println("begin Transaction.");
System.out.println("Add 2 triples to graph <Example6>.");
graph.add(new Triple(foo2, bar2, baz2));
graph.add(new Triple(foo3, bar3, baz3));
graph.getTransactionHandler().abort();
System.out.println("abort Transaction.");
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
System.out.println ("\ngraph.find(Node.ANY, Node.ANY, Node.ANY) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
graph.clear ();
System.out.println("\nCLEAR graph <Example6>");
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples7"><title>VirtJenaSPARQLExample7</title>
<programlisting><![CDATA[
import java.util.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Triple;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample7
{
public static void main(String[] args)
{
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
Node foo1 = Node.createURI("http://example.org/#foo1");
Node bar1 = Node.createURI("http://example.org/#bar1");
Node baz1 = Node.createURI("http://example.org/#baz1");
Node foo2 = Node.createURI("http://example.org/#foo2");
Node bar2 = Node.createURI("http://example.org/#bar2");
Node baz2 = Node.createURI("http://example.org/#baz2");
Node foo3 = Node.createURI("http://example.org/#foo3");
Node bar3 = Node.createURI("http://example.org/#bar3");
Node baz3 = Node.createURI("http://example.org/#baz3");
List triples1 = new ArrayList();
triples1.add(new Triple(foo1, bar1, baz1));
triples1.add(new Triple(foo2, bar2, baz2));
triples1.add(new Triple(foo3, bar3, baz3));
List triples2 = new ArrayList();
triples2.add(new Triple(foo1, bar1, baz1));
triples2.add(new Triple(foo2, bar2, baz2));
VirtGraph graph = new VirtGraph ("Example7", url, "dba", "dba");
graph.clear ();
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("Add List with 3 triples to graph <Example7> via BulkUpdateHandler.");
graph.getBulkUpdateHandler().add(triples1);
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
ExtendedIterator iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
System.out.println ("\ngraph.find(Node.ANY, Node.ANY, Node.ANY) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
System.out.println("\n\nDelete List of 2 triples from graph <Example7> via BulkUpdateHandler.");
graph.getBulkUpdateHandler().delete(triples2);
System.out.println("graph.isEmpty() = " + graph.isEmpty());
System.out.println("graph.getCount() = " + graph.getCount());
iter = graph.find(Node.ANY, Node.ANY, Node.ANY);
System.out.println ("\ngraph.find(Node.ANY, Node.ANY, Node.ANY) \nResult:");
for ( ; iter.hasNext() ; )
System.out.println ((Triple) iter.next());
graph.clear ();
System.out.println("\nCLEAR graph <Example7>");
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples8"><title>VirtJenaSPARQLExample8</title>
<programlisting><![CDATA[
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.RDFNode;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample8 {
/**
* Executes a SPARQL query against a virtuoso url and prints results.
*/
public static void main(String[] args) {
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
/* STEP 1 */
VirtGraph set = new VirtGraph (url, "dba", "dba");
/* STEP 2 */
System.out.println("\nexecute: CLEAR GRAPH <http://test1>");
String str = "CLEAR GRAPH <http://test1>";
VirtuosoUpdateRequest vur = VirtuosoUpdateFactory.create(str, set);
vur.exec();
System.out.println("\nexecute: INSERT INTO GRAPH <http://test1> { <aa> <bb> 'cc' . <aa1> <bb1> 123. }");
str = "INSERT INTO GRAPH <http://test1> { <aa> <bb> 'cc' . <aa1> <bb1> 123. }";
vur = VirtuosoUpdateFactory.create(str, set);
vur.exec();
/* STEP 3 */
/* Select all data in virtuoso */
System.out.println("\nexecute: SELECT * FROM <http://test1> WHERE { ?s ?p ?o }");
Query sparql = QueryFactory.create("SELECT * FROM <http://test1> WHERE { ?s ?p ?o }");
/* STEP 4 */
VirtuosoQueryExecution vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
ResultSet results = vqe.execSelect();
while (results.hasNext()) {
QuerySolution rs = results.nextSolution();
RDFNode s = rs.get("s");
RDFNode p = rs.get("p");
RDFNode o = rs.get("o");
System.out.println(" { " + s + " " + p + " " + o + " . }");
}
System.out.println("\nexecute: DELETE FROM GRAPH <http://test1> { <aa> <bb> 'cc' }");
str = "DELETE FROM GRAPH <http://test1> { <aa> <bb> 'cc' }";
vur = VirtuosoUpdateFactory.create(str, set);
vur.exec();
System.out.println("\nexecute: SELECT * FROM <http://test1> WHERE { ?s ?p ?o }");
vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
results = vqe.execSelect();
while (results.hasNext()) {
QuerySolution rs = results.nextSolution();
RDFNode s = rs.get("s");
RDFNode p = rs.get("p");
RDFNode o = rs.get("o");
System.out.println(" { " + s + " " + p + " " + o + " . }");
}
}
}
]]></programlisting>
</sect4>
<sect4 id="rdfnativestorageprovidersjenaexamples9"><title>VirtJenaSPARQLExample9</title>
<programlisting><![CDATA[
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.graph.Triple;
import com.hp.hpl.jena.graph.Node;
import com.hp.hpl.jena.graph.Graph;
import com.hp.hpl.jena.rdf.model.*;
import java.util.Iterator;
import virtuoso.jena.driver.*;
public class VirtuosoSPARQLExample9 {
/**
* Executes a SPARQL query against a virtuoso url and prints results.
*/
public static void main(String[] args) {
String url;
if(args.length == 0)
url = "jdbc:virtuoso://localhost:1111";
else
url = args[0];
/* STEP 1 */
VirtGraph set = new VirtGraph (url, "dba", "dba");
/* STEP 2 */
String str = "CLEAR GRAPH <http://test1>";
VirtuosoUpdateRequest vur = VirtuosoUpdateFactory.create(str, set);
vur.exec();
str = "INSERT INTO GRAPH <http://test1> { <http://aa> <http://bb> 'cc' . <http://aa1> <http://bb> 123. }";
vur = VirtuosoUpdateFactory.create(str, set);
vur.exec();
/* Select all data in virtuoso */
Query sparql = QueryFactory.create("SELECT * FROM <http://test1> WHERE { ?s ?p ?o }");
VirtuosoQueryExecution vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
ResultSet results = vqe.execSelect();
System.out.println("\nSELECT results:");
while (results.hasNext()) {
QuerySolution rs = results.nextSolution();
RDFNode s = rs.get("s");
RDFNode p = rs.get("p");
RDFNode o = rs.get("o");
System.out.println(" { " + s + " " + p + " " + o + " . }");
}
sparql = QueryFactory.create("DESCRIBE <http://aa> FROM <http://test1>");
vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
Model model = vqe.execDescribe();
Graph g = model.getGraph();
System.out.println("\nDESCRIBE results:");
for (Iterator i = g.find(Node.ANY, Node.ANY, Node.ANY); i.hasNext();)
{
Triple t = (Triple)i.next();
System.out.println(" { " + t.getSubject() + " " +
t.getPredicate() + " " +
t.getObject() + " . }");
}
sparql = QueryFactory.create("CONSTRUCT { ?x <http://test> ?y } FROM <http://test1> WHERE { ?x <http://bb> ?y }");
vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
model = vqe.execConstruct();
g = model.getGraph();
System.out.println("\nCONSTRUCT results:");
for (Iterator i = g.find(Node.ANY, Node.ANY, Node.ANY); i.hasNext();)
{
Triple t = (Triple)i.next();
System.out.println(" { " + t.getSubject() + " " +
t.getPredicate() + " " +
t.getObject() + " . }");
}
sparql = QueryFactory.create("ASK FROM <http://test1> WHERE { <http://aa> <http://bb> ?y }");
vqe = VirtuosoQueryExecutionFactory.create (sparql, set);
boolean res = vqe.execAsk();
System.out.println("\nASK results: "+res);
}
}
]]></programlisting>
</sect4>
</sect3>
<sect3 id="rdfnativestorageprovidersjenajavadoc"><title>Javadoc API Documentation</title>
<para><ulink url="http://docs.openlinksw.com/jena/">Jena Provider Javadoc API Documentation</ulink> is available enabling the complete set of classes, interfaces and methods implemented for the provider to be viewed.
</para>
</sect3>
</sect2>
<sect2 id="rdfnativestorageproviderssesame"><title>Virtuoso Sesame Provider</title>
<sect3 id="rdfnativestorageproviderssesamewhatis"><title>What is Sesame</title>
<para>Sesame is an open source Java framework for storing, querying and reasoning
with RDF and RDF Schema. It can be used as a database for RDF and RDF Schema, or as a Java
library for applications that need to work with RDF internally. For example, suppose you need
to read a big RDF file, find the relevant information for your application, and use that information.
Sesame provides you with the necessary tools to parse, interpret, query and store all this information,
embedded in your own application if you want, or, if you prefer, in a separate database or even on a remote
server. More generally: Sesame provides an application developer a toolbox that contains useful hammers
screwdrivers etc. for doing 'Do-It-Yourself' with RDF.
</para>
</sect3>
<sect3 id="rdfnativestorageproviderssesamewhatisvirtuososesameprovider"><title>What is the Virtuoso Sesame Provider</title>
<para>The Virtuoso Sesame Provider is a fully operational Native Graph Model Storage Providers
for the Sesame Framework, allowing users of Virtuoso to leverage the Sesame framework for modifying,
querying, and reasoning with the Virtuoso quad store using the Java language. The Sesame Repository
API offers a central access point for connecting to the Virtuoso quad store. Its purpose is to
provides a java-friendly access point to Virtuoso. It offers various methods for querying and
updating the data, while abstracting the details of the underlying machinery. The Provider has
been tested against the <ulink url="http://sourceforge.net/project/showfiles.php?group_id=46509&package_id=168413">Sesame 2.1.2</ulink> version currently available.
</para>
<figure id="rdfnativestorageproviderssesame1" float="1">
<title>Fig. 1 Sesame Component Stack</title>
<graphic fileref="ui/VirtSesame2Provider.png"/>
</figure>
<para>If you need more information about how to set up your environment for working with the
Sesame APIs, take a look at Chapter 4 of the Sesame User Guide, <ulink url="http://www.openrdf.org/doc/sesame2/users/RDF">Setting up to use the Sesame libraries</ulink>.
</para>
</sect3>
<sect3 id="rdfnativestorageproviderssesamesetup"><title>Setup Tutorial</title>
<sect4 id="rdfnativestorageproviderssesamereqfiles"><title>Required Files</title>
<para>This tutorial assumes you have Virtuoso server installed and that the database
is accessible at "localhost:1111". In addition, you will need the latest version of the
Virtuoso Sesame Provider, and Sesame 2 or greater installed.
</para>
<itemizedlist mark="bullet">
<listitem>Virtuoso Sesame 2 Provider JAR file, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtSesame2Provider/virt_sesame2.jar">virt_sesame2.jar</ulink></listitem>
<listitem>The Virtuoso JDBC Driver JAR file, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtSesame2Provider/virtjdbc3.jar">virtjdbc3.jar</ulink></listitem>
<listitem>Sesame Framework and associated classes, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtSesame2Provider/sesame2jars.zip">sesame2jars.zip</ulink></listitem>
<listitem>Sample programs, <ulink url="http://virtuoso.openlinksw.com/wiki/main/Main/VirtSesame2Provider/virtsesame2samples.zip">virtsesame2samples.zip</ulink></listitem>
</itemizedlist>
</sect4>
<sect4 id="rdfnativestorageproviderssesamecmppr"><title>Compiling Sesame Sample Programs</title>
<orderedlist>
<listitem>Ensure that full paths to the following files are all included in the active CLASSPATH setting --
<itemizedlist mark="bullet">
<listitem>openrdf-sesame-2.1.2-onejar.jar</listitem>
<listitem>slf4j-api-1.5.0.jar</listitem>
<listitem>slf4j-jdk14-1.5.0.jar</listitem>
<listitem>virtjdbc3.jar</listitem>
<listitem>virt_sesame2.jar</listitem>
</itemizedlist>
</listitem>
<listitem>Execute the following command --
<programlisting><![CDATA[
javac VirtuosoTest.java
]]></programlisting>
<para>Note: to use row auto commit is recommended to add the following to the connect string:
</para>
<programlisting><![CDATA[
"/log_enable=2"
-- i.e. in VirtuosoTest.java the line:
Repository repository = new VirtuosoRepository("jdbc:virtuoso://" + sa[0] + ":" + sa[1], sa[2], sa[3]);
-- should become:
Repository repository = new VirtuosoRepository("jdbc:virtuoso://" + sa[0] + ":" + sa[1]+ "/log_enable=2", sa[2], sa[3]);
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
<sect4 id="rdfnativestorageproviderssesametesting"><title>Testing</title>
<orderedlist>
<listitem>Ensure that full paths to the following files are all included in the active CLASSPATH setting --
<itemizedlist mark="bullet">
<listitem>openrdf-sesame-2.1.2-onejar.jar</listitem>
<listitem>slf4j-api-1.5.0.jar</listitem>
<listitem>slf4j-jdk14-1.5.0.jar</listitem>
<listitem>virtjdbc3.jar</listitem>
<listitem>virt_sesame2.jar</listitem>
<listitem>virtuoso_driver</listitem>
</itemizedlist>
</listitem>
<listitem>Test the Sesame 2 Provider with the following command
<programlisting><![CDATA[
java VirtuosoTest <hostname> <port> <uid> <pwd>
]]></programlisting>
</listitem>
<listitem>The test run should look like this --
<programlisting><![CDATA[
$ java VirtuosoTest localhost 1111 dba dba
== TEST 1: : Start
Loading data from URL: http://www.openlinksw.com/dataspace/person/kidehen@openlinksw.com/foaf.rdf
== TEST 1: : End
PASSED: TEST 1
== TEST 2: : Start
Clearing triple store
== TEST 2: : End
PASSED: TEST 2
== TEST 3: : Start
Loading data from file: virtuoso_driver/data.nt
== TEST 3: : End
PASSED: TEST 3
== TEST 4: : Start
Loading UNICODE single triple
== TEST 4: : End
PASSED: TEST 4
== TEST 5: : Start
Loading single triple
== TEST 5: : End
PASSED: TEST 5
== TEST 6: : Start
Casted value type
== TEST 6: : End
PASSED: TEST 6
== TEST 7: : Start
Selecting property
== TEST 7: : End
PASSED: TEST 7
== TEST 8: : Start
Statement does not exists
== TEST 8: : End
PASSED: TEST 8
== TEST 9: : Start
Statement exists (by resultset size)
== TEST 9: : End
PASSED: TEST 9
== TEST 10: : Start
Statement exists (by hasStatement())
== TEST 10: : End
PASSED: TEST 10
== TEST 11: : Start
Retrieving namespaces
== TEST 11: : End
PASSED: TEST 11
== TEST 12: : Start
Retrieving statement (http://myopenlink.net/dataspace/person/kidehen http://myopenlink.net/foaf/name null)
== TEST 12: : End
PASSED: TEST 12
== TEST 13: : Start
Writing the statements to file: (/Users/hughwilliams/src/virtuoso-opensource/binsrc/sesame2/results.n3.txt)
== TEST 13: : End
PASSED: TEST 13
== TEST 14: : Start
Retrieving graph ids
== TEST 14: : End
PASSED: TEST 14
== TEST 15: : Start
Retrieving triple store size
== TEST 15: : End
PASSED: TEST 15
== TEST 16: : Start
Sending ask query
== TEST 16: : End
PASSED: TEST 16
== TEST 17: : Start
Sending construct query
== TEST 17: : End
PASSED: TEST 17
== TEST 18: : Start
Sending describe query
== TEST 18: : End
PASSED: TEST 18
============================
PASSED:18 FAILED:0
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
</sect3>
<sect3 id="rdfnativestorageproviderssesamegettingstarted"><title>Getting Started</title>
<para>This section covers the essentials for connecting to and manipulating data stored in
a Virtuoso repository using the Sesame API. More information on the Sesame Framework, including
extended examples on how to use the API, can be found in Chapter 8 of the Sesame User's guide,
<ulink url="http://www.openrdf.org/doc/sesame2/2.1.2/users/ch08.html#d0e833">the RepositoryConnection API</ulink>.
</para>
<para>The interfaces for the Repository API can be found in packages virtuoso.sesame2.driver
and org.openrdf.repository. Several implementations for these interface exist in the
Virtuoso Provider download package.
The <ulink url="http://www.openrdf.org/doc/sesame2/2.1.2/apidocs/">Javadoc reference for the Sesame API</ulink>
is available online and can also be found in the doc directory of the download.
</para>
<sect4 id="rdfnativestorageproviderssesamegettingstartedcrrep"><title>Creating a VirtuosoRepositoryRDF object</title>
<para>The first step to connecting to Virtuoso through the Sesame API is to create a
Repository for it. The Repository object operates on (stacks of) Sail object(s) for storage
and retrieval of RDF data.
</para>
<para>One of the simplest configurations is a repository that just stores RDF data in main
memory without applying any inference or whatsoever. This is also by far the fastest type of
repository that can be used. The following code creates and initialize a non-inferencing main-memory
repository:
</para>
<programlisting><![CDATA[
import virtuoso.sesame2.driver.VirtuosoRepository;
Repository myRepository = VirtuosoRepository("jdbc:virtuoso://localhost:1111","dba","dba");
myRepository.initialize();
]]></programlisting>
<para>The constructor of the VirtuosoRepositoryRDF class accepts the JDBC URL of the Virtuoso
engine (the default port is 1111), the username and password of an authorized user. Following this
example, the repository needs to be initialized to prepare the Sail(s) that it operates on, which
includes operations such as restoring previously stored data, setting up connections to a relational
database, etc.
</para>
<para>The repository that is created by the above code is volatile: its contents are lost
when the object is garbage collected or when the program is shut down. This is fine for cases where,
for example, the repository is used as a means for manipulating an RDF model in memory. Using the
Virtuoso repository with RepositoryConnection.
</para>
<para>Now that we have created a VirtuosoRepositoryRDF, we want to do something with it.
This is achieved through the use of the VirtuosoRepositoryConnection, which can be created by
the VirtuosoRepositoryRDF.
</para>
<para>A VirtuosoRepositoryConnection represents - as the name suggests - a connection
to the actual Virtuoso quad store. We can issue operations over this connection, and close it
when we are done to make sure we are not keeping resources unnecessarily occupied.
</para>
<para>In the following sections, we will show some examples of basic operations
using the Northwind dataset.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamegettingstartedrdfvirt"><title>Adding RDF to Virtuoso</title>
<para>The Repository implements the Sesame Repository API offers various methods for adding
data to a repository. Data can be added pro grammatically by specifying the location of a file
that contains RDF data, and statements can be added individually or in collections.
</para>
<para>We perform operations on the repository by requesting a RepositoryConnection from
the repository, which returns a VirtuosoRepositoryConnection object. On this VirtuosoRepositoryConnection
object we can perform the various operations, such as query evaluation, getting, adding, or removing
statements, etc.
</para>
<para>The following example code adds two files, one local and one located on the WWW, to a repository:
</para>
<programlisting><![CDATA[
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.rio.RDFFormat;
import java.io.File;
import java.net.URL;
File file = new File("/path/to/example.rdf");
String baseURI = "http://example.org/example/localRDF";
try {
RepositoryConnection con = myRepository.getConnection();
try {
con.add(file, baseURI, RDFFormat.RDFXML);
URL url = new URL("http://example.org/example/remoteRDF");
con.add(url, url.toString(), RDFFormat.RDFXML);
}
finally {
con.close();
}
}
catch (RepositoryException rex) {
// handle exception
}
catch (java.io.IOEXception e) {
// handle io exception
}
]]></programlisting>
<para>More information on other available methods can be found in the javadoc
reference of the RepositoryConnection interface.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamegettingstartedqr"><title>Querying Virtuoso</title>
<para>The Repository API has a number of methods for creating and evaluating queries.
Three types of queries are distinguished: tuple queries, graph queries and boolean queries.
The query types differ in the type of results that they produce.
</para>
<para><emphasis>Select Query:</emphasis> The result of a select query is a set of tuples
(or variable bindings), where each tuple represents a solution of a query. This type of query
is commonly used to get specific values (URIs, blank nodes, literals) from the stored RDF data.
The method QueryFactory.executeQuery() returns a Value[][] for sparql "SELECT" queries.
The method QueryFactory.executeQuery() also calls the QueryFactory.setResult() which populates
a set of tuples for SPARQL "SELECT" queries. The graph can be retrieved using
QueryFactory.getBooleanResult().
</para>
<para><emphasis>Graph Query:</emphasis> The result of graph queries is an RDF graph
(or set of statements). This type of query is very useful for extracting sub-graphs from
the stored RDF data, which can then be queried further, serialized to an RDF document,
etc. The method QueryFactory.executeQuery() calls the QueryFactory.setGraphResult()
which populates a graph for SPARQL "DESCRIBE" and "CONSTRUCT" queries. The graph can
be retrieved using QueryFactory.getGraphResult().
</para>
<para><emphasis>Boolean Query:</emphasis> The result of boolean queries is a simple
boolean value, i.e. true of false. This type of query can be used to check if a repository
contains specific information. The method QueryFactory.executeQuery() calls the
QueryFactory.setBooleanResult() which sets a boolean value for sparql "ASK" queries.
The value can be retrieved using QueryFactory.getBooleanResult().
</para>
<para>Note: Although Sesame 2 currently supports two query languages: SeRQL and SPARQL,
the Virtuoso provider only supports the W3C SPARQL specification.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamegettingstartevq"><title>Evaluating a SELECT Query</title>
<para>To evaluate a tuple query we simply do the following:
</para>
<programlisting><![CDATA[
import java.util.List;
import org.openrdf.OpenRDFException;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.TupleQueryResult;
import org.openrdf.query.BindingSet;
import org.openrdf.query.QueryLanguage;
try {
RepositoryConnection? con = myRepository.getConnection();
try {
String queryString = "SELECT ?s ?p FROM <http://mygraph.com> WHERE { ?s ?p ?o }";
TupleQuery? tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
TupleQueryResult? result = tupleQuery.evaluate();
try {
? // do something with the result
}
finally {
result.close();
}
}
finally {
con.close();
}
}
catch (RepositoryException? e) {
// handle exception
}
]]></programlisting>
<para>This evaluates a SPARQL query and returns a TupleQueryResult, which consists of a
sequence of BindingSet objects. Each BindingSet contains a set of pairs called Binding objects.
A Binding object represents a name/value pair for each variable in the querys projection.
</para>
<para>We can use the TupleQueryResult to iterate over all results and get each individual
result for x and y:
</para>
<programlisting><![CDATA[
while (result.hasNext()) {
BindingSet bindingSet = result.next();
Value valueOfX = bindingSet.getValue("s");
Value valueOfY = bindingSet.getValue("p");
// do something interesting with the query variable values here?
}
]]></programlisting>
<para>As you can see, we retrieve values by name rather than by an index. The names used
should be the names of variables as specified in your query. The TupleQueryResult.getBindingNames()
method returns a list of binding names, in the order in which they were specified in the query.
To process the bindings in each binding set in the order specified by the projection, you can do
the following:
</para>
<programlisting><![CDATA[
List bindingNames = result.getBindingNames();
while (result.hasNext()) {
BindingSet bindingSet = result.next();
Value firstValue = bindingSet.getValue(bindingNames.get(0));
Value secondValue = bindingSet.getValue(bindingNames.get(1));
// do something interesting with the values here?
}
]]></programlisting>
<para>It is important to invoke the close() operation on the TupleQueryResult, after we are
done with it. A TupleQueryResult evaluates lazily and keeps resources (such as connections to
the underlying database) open. Closing the TupleQueryResult frees up these resources. Do not
forget that iterating over a result may cause exceptions! The best way to make sure no connections
are kept open unnecessarily is to invoke close() in the finally clause.
</para>
<para>An alternative to producing a TupleQueryResult is to supply an object that implements
the TupleQueryResultHandler interface to the query's evaluate() method. The main difference is that
when using a return object, the caller has control over when the next answer is retrieved, whereas
with the use of a handler, the connection simply pushes answers to the handler object as soon as it
has them available.
</para>
<para>As an example we will use SPARQLResultsXMLWriter, which is a TupleQueryResultHandler
implementation that writes SPARQL Results XML documents to an output stream or to a writer:
</para>
<programlisting><![CDATA[
import org.openrdf.query.resultio.sparqlxml.SPARQLResultsXMLWriter;
?
FileOutputStream out = new FileOutputStream("/path/to/result.srx");
try {
SPARQLResultsXMLWriter sparqlWriter = new SPARQLResultsXMLWriter(out);
RepositoryConnection con = myRepository.getConnection();
try {
String queryString = "SELECT * FROM WHERE { ?s ?p ?o }";
TupleQuery tupleQuery = con.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
tupleQuery.evaluate(sparqlWriter);
}
finally {
con.close();
}
}
finally {
out.close();
}
]]></programlisting>
<para>You can just as easily supply your own application-specific implementation of
TupleQueryResultHandler though.
</para>
<para>Lastly, an important warning: as soon as you are done with the RepositoryConnection
object, you should close it. Notice that during processing of the TupleQueryResult object
(for example, when iterating over its contents), the RepositoryConnection should still be open.
We can invoke con.close() after we have finished with the result.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamegettingstartevcnq"><title>Evaluating a CONSTRUCT query</title>
<para>The following code evaluates a graph query on a repository:
</para>
<programlisting><![CDATA[
import org.openrdf.query.GraphQueryResult;
GraphQueryResult graphResult = con.prepareGraphQuery(
QueryLanguage.SPARQL, "CONSTRUCT * FROM <http://mygraph.com> WHERE { ?s ?p ?o }").evaluate();
]]></programlisting>
<para>A GraphQueryResult is similar to TupleQueryResult in that is an object that iterates
over the query results. However, for graph queries the query results are RDF statements, so a
GraphQueryResult iterates over Statement objects:
</para>
<programlisting><![CDATA[
while (graphResult.hasNext()) {
Statement st = graphResult.next();
// ? do something with the resulting statement here.
}
]]></programlisting>
<para>The TupleQueryResultHandler equivalent for graph queries is org.openrdf.rio.RDFHandler.
Again, this is a generic interface, each object implementing it can process the reported RDF statements
in any way it wants.
</para>
<para>All writers from Rio (such as the RDFXMLWriter, TurtleWriter, TriXWriter, etc.) implement
the RDFHandler interface. This allows them to be used in combination with querying quite easily. In
the following example, we use a TurtleWriter to write the result of a SPARQL graph query to standard
output in Turtle format:
</para>
<programlisting><![CDATA[
import org.openrdf.rio.turtle.TurtleWriter;
RepositoryConnection con = myRepository.getConnection();
try {
TurtleWriter turtleWriter = new TurtleWriter(System.out);
con.prepareGraphQuery(QueryLanguage.SPARQL, "CONSTRUCT * FROM <http://mygraph.com> WHERE { ?s ?p ?o }").evaluate(turtleWriter);
}
finally {
con.close();
}
]]></programlisting>
<para>Again, note that as soon as we are done with the result of the query (either after iterating over the contents of the GraphQueryResult or after invoking the RDFHandler),
we invoke con.close() to close the connection and free resources.
</para>
</sect4>
</sect3>
<sect3 id="rdfnativestorageproviderssesamestpandtesting"><title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<sect4 id="rdfnativestorageproviderssesamestpandtestingwhat"><title>What</title>
<para>Sesame is an open source Java framework for storing, querying and reasoning with RDF and RDF Schema. It can be used as a
database for RDF and RDF Schema, or as a Java library for applications that need to work with RDF internally. The Sesame HTTP
repository serves as a proxy for a RDF store hosted on a remote Sesame server, enabling the querying of the RDF store using
the Sesame HTTP protocol.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamestpandtestingwhy"><title>Why</title>
<para>The Sesame HTTP repository endpoint provides users with the greater flexibility for manipulating the RDF store via a common
interface. Sesame provides you with the necessary tools to parse, interpret, query and store all this information, embedded
in your own application if you want, or, if you prefer, in a separate database or even on a remote server.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamestpandtestinghow"><title>How</title>
<para>To create a new Sesame HTTP repository, the Console needs to create such an RDF document and submit it to the SYSTEM
repository. The Console uses so called repository configuration templates to accomplish this. Repository configuration templates
are simple Turtle RDF files that describe a repository configuration, where some of the parameters are replaced with variables.
The Console parses these templates and asks the user to supply values for the variables. The variables are then substituted with
the specified values, which produces the required configuration data.
</para>
</sect4>
<sect4 id="rdfnativestorageproviderssesamestpandtestingmain"><title>Setup and Testing</title>
<para>This section details the steps required for configuring and testing a Virtuoso Sesame
Repository, both using the HTTP and Console Sesame repositories.</para>
<sect5 id="rdfnativestorageproviderssesamestpandtestingreq"><title>Requirements</title>
<itemizedlist mark="bullet">
<listitem><ulink url="http://www.openrdf.org/download.jsp">Sesame 2.3.1</ulink> or higher</listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSesame2HttpRepository/virt_sesame2.jar">Virtuoso Sesame 2 Provider </ulink> (virt_sesame2.jar)</listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSesame2HttpRepository/virtjdbc3.jar">Virtuoso JDBC Driver</ulink> (virtjdbc3.jar)</listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSesame2HttpRepository/create.xsl">Sesame System Repository config file</ulink> (create.xsl)</listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSesame2HttpRepository/create-virtuoso.xsl">Sesame Virtuoso Repository config file </ulink> (create-virtuoso.xsl)</listitem>
<listitem><ulink url="http://tomcat.apache.org/download-60.cgi">Apache Tomcat</ulink> version 5 or 6</listitem>
</itemizedlist>
</sect5>
<sect5 id="rdfnativestorageproviderssesamestpandtestinghttprep"><title>Setup Sesame HTTP Repository</title>
<para>This section details the steps required for configuring and testing a Virtuoso HTTP Sesame Repository.</para>
<orderedlist>
<listitem>Install <ulink url="http://tomcat.apache.org/tomcat-6.0-doc/index.html">Apache Tomcat</ulink> web server</listitem>
<listitem>From the Sesame 2.3.1 or higher "lib" directory copy the "openrdf-sesame.war" and "openrdf-worbbench.war" files to the
tomcat "webapps" directory where they will automatically be deployed creating two new sub directories "openrdf-sesame" and
"openrdf-workbench".</listitem>
<listitem>Place the Virtuoso Sesame Provider "virt_sesame2.jar" and JDBC Driver "virtjdbc3.jar" into the Tomcat
<code>~/webapps/openrdf-sesame/WEB-INF/lib/</code> and <code>~/webapps/openrdf-workbench/WEB-INF/lib/</code> directories for
use by the Sesame HTTP Repository for accessing the Virtuoso RDF repository.</listitem>
<listitem>Place the "create.xsl" and "create-virtuoso.xsl" files in the Tomcat
<code>~/webapps/openrdf-workbench/transformations/</code> directory. Note "create.xsl" replaces the default provided with Sesame and contains the necessary entries required to reference the new "create-virtuoso.xsl" template file for Virtuoso repository configuration.</listitem>
<listitem>The Sesame HTTP Repository will now be accessible on the URLs
<programlisting><![CDATA[
http://localhost:8080/openrdf-sesame
http://localhost:8080/openrdf-workbench
]]></programlisting>
</listitem>
<listitem>The Sesame OpenRDF Workbench is used for accessing the Sesame HTTP Repositories, loading
"<ulink url="http://localhost:8080/openrdf-workbench">http://localhost:8080/openrdf-workbench</ulink>" will enable the
default "SYSTEM" repository to be accessed.
<figure id="ss1" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss1.png"/>
</figure>
</listitem>
<listitem>Click on the "New Repository" link in the left frame to create a new Sesame Repository.
<figure id="ss2" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss2.png"/>
</figure>
</listitem>
<listitem>Select the "Virtuoso RDF Store" from the "Type" drop down list box presented.
<figure id="ss3" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss3.png"/>
</figure>
</listitem>
<listitem>Choose suitable repository "ID" and "Title" for the Virtuoso repository to be created and click "Next".
<figure id="ss4" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss4.png"/>
</figure>
</listitem>
<listitem>Fill in the connection parameters for the target Virtuoso sever the repository is to be created for and
click the "create" button. The minimum required are the hostname, port number, username and password of the Virtuoso Server.
<figure id="ss5" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss5.png"/>
</figure>
</listitem>
<listitem>The new Virtuoso respository will be created and its summary page displayed.
<figure id="ss6" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss6.png"/>
</figure>
</listitem>
<listitem>Click on the "Namespaces" link in the left frame to obtain a list of the available namespaces in the Virtuoso repository.
<figure id="ss7" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss7.png"/>
</figure>
</listitem>
<listitem>Click on the "Context" link in the left frame to obtain a list of the available contexts in the Virtuoso repository.
<figure id="ss8" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss8.png"/>
</figure>
</listitem>
<listitem>Click on the "Types" link in the left frame to obtain a list of the available types in the Virtuoso repository.
<figure id="ss9" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss9.png"/>
</figure>
</listitem>
<listitem>Click on the "Query" link in the left frame, enter a suitable SPARQL query to execute against the Virtuoso repository
and click the "execute" button.
<figure id="ss10" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss10.png"/>
</figure>
</listitem>
<listitem>The results of the SPARQL query are returned.
<figure id="ss11" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss11.png"/>
</figure>
</listitem>
<listitem>Click on the "Repositories" link in the left frame and the newly created Virtuoso repository entry is displayed along side
the default SYSTEM repository.
<figure id="ss12" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss12.png"/>
</figure>
</listitem>
</orderedlist>
</sect5>
<sect5 id="rdfnativestorageproviderssesamestpandtestingcons"><title>Setup Sesame Console Repository</title>
<para>This section details the steps required for configuring and testing a Virtuoso Sesame Console Repository:</para>
<orderedlist>
<listitem>Extract Sesame 2.3.1 or higher archive to a location of choice and place the virt_sesame2.jar and virtjdbc3.jar
files to the sesame 2.3.1 "lib" directory</listitem>
<listitem>Start the <ulink url="http://www.openrdf.org/doc/sesame2/users/ch07.html#section-console-repository-creation">sesame console application</ulink> by running the "console.bat" script in the sesame "bin" directory and then "exit." the program
<programlisting><![CDATA[
$ sh console.sh
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/myuser/openrdf-sesame-2.3.1/lib/logback-classic-0.9.18.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/myuser/openrdf-sesame-2.3.1/lib/slf4j-jdk14-1.5.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
10:32:38.317 [main] DEBUG info.aduna.platform.PlatformFactory - os.name <http://os.name> <http://os.name> = mac os x
10:32:38.351 [main] DEBUG info.aduna.platform.PlatformFactory - Detected Mac OS X platform
Connected to default data directory
Commands end with '.' at the end of a line
Type 'help.' for help
exit.
]]></programlisting>
</listitem>
<listitem>This will create the necessary sesame application data directories as detailed in the sesame
<ulink url="http://www.openrdf.org/doc/sesame2/2.3.1/users/userguide.html#chapter-datadir-config">data directory configuration</ulink> documentation.
<programlisting><![CDATA[
Windows - C:\Documents and Settings\LocalService\Application Data\Aduna\
Mac OS X - /Users/myuser/Library/Application Support/Aduna/
Linux - $HOME/.aduna/
]]></programlisting>
</listitem>
<listitem>If you do not want to use the default sesame data directory location the Sesame console application can be started by
specifying a custom data directory location with the "-d" option. Note in this case the directory "OpenRDF Sesame console" always
has to be manually appended to the directory as Sesame assumes the data file will reside in a sub directory of this name.
<programlisting><![CDATA[
$ sh console.sh -d /Users/myuser/OpenRDF Sesame console
]]></programlisting>
</listitem>
<listitem>Start the sesame console application with the required data directory location and create a Virtuoso repository as
detailed in the steps below, the key parameters to be specified being the target Virtuoso server hostname, port number,
username, password and a unique "Repository ID".
<programlisting><![CDATA[
$ sh console.sh
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/myuser/openrdf-sesame-2.3.1/lib/logback-classic-0.9.18.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/myuser/openrdf-sesame-2.3.1/lib/slf4j-jdk14-1.5.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
10:32:38.317 [main] DEBUG info.aduna.platform.PlatformFactory - os.name <http://os.name> <http://os.name> = mac os x
10:32:38.351 [main] DEBUG info.aduna.platform.PlatformFactory - Detected Mac OS X platform
Connected to default data directory
Commands end with '.' at the end of a line
Type 'help.' for help
create virtuoso .
Please specify values for the following variables:
Host list [localhost:1111]:
Username [dba]:
Password [dba]:
Default graph name [sesame:nil]:
Enable using batch optimization (false|true) [false]:
Use RoundRobin for connection (false|true) [false]:
Buffer fetch size [200]:
Inference RuleSet name [null]:
Repository ID [virtuoso]: myvirt
Repository title [Virtuoso repository]:
Repository created
show r .
+----------
|SYSTEM
|myvirt ("Virtuoso repository")
+----------
open myvirt .
Opened repository 'myvirt'
myvirt> show n .
+----------
|bif bif:
|dawgt http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#
|dbpedia http://dbpedia.org/resource/
|dbpprop http://dbpedia.org/property/
|dc http://purl.org/dc/elements/1.1/
|foaf http://xmlns.com/foaf/0.1/
|geo http://www.w3.org/2003/01/geo/wgs84_pos#
|go http://purl.org/obo/owl/GO#
|math http://www.w3.org/2000/10/swap/math#
|mesh http://purl.org/commons/record/mesh/
|mf http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#
|nci http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#
|obo http://www.geneontology.org/formats/oboInOwl#
|owl http://www.w3.org/2002/07/owl#
|protseq http://purl.org/science/protein/bysequence/
|rdf http://www.w3.org/1999/02/22-rdf-syntax-ns#
|rdfdf http://www.openlinksw.com/virtrdf-data-formats#
|rdfs http://www.w3.org/2000/01/rdf-schema#
|sc http://purl.org/science/owl/sciencecommons/
|scovo http://purl.org/NET/scovo#
|skos http://www.w3.org/2004/02/skos/core#
|sql sql:
|vcard http://www.w3.org/2001/vcard-rdf/3.0#
|virtrdf http://www.openlinksw.com/schemas/virtrdf#
|void http://rdfs.org/ns/void#
|xf http://www.w3.org/2004/07/xpath-functions
|xml http://www.w3.org/XML/1998/namespace
|xsd http://www.w3.org/2001/XMLSchema#
|xsl10 http://www.w3.org/XSL/Transform/1.0
|xsl1999 http://www.w3.org/1999/XSL/Transform
|xslwd http://www.w3.org/TR/WD-xsl
|yago http://dbpedia.org/class/yago/
+----------
exit.
]]></programlisting>
</listitem>
</orderedlist>
</sect5>
<sect5 id="rdfnativestorageproviderssesamestpandtestinghttpcons"><title>Connection to Sesame HTTP repository from Console repository</title>
<para>The Sesame Console repository can connect to a Sesame HTTP repository and vice-versa, enabling access to remote Sesame
HTTP repositories from a local server.</para>
<orderedlist>
<listitem>The Sesame Console repository can connect to a Sesame HTTP repository and query it as if local using the "connect" command.
<programlisting><![CDATA[
$ sh console.sh
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/myuser/openrdf-sesame-2.3.1/lib/logback-classic-0.9.18.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/myuser/openrdf-sesame-2.3.1/lib/slf4j-jdk14-1.5.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
10:32:38.317 [main] DEBUG info.aduna.platform.PlatformFactory - os.name <http://os.name> <http://os.name> = mac os x
10:32:38.351 [main] DEBUG info.aduna.platform.PlatformFactory - Detected Mac OS X platform
Connected to default data directory
Commands end with '.' at the end of a line
Type 'help.' for help
> connect http://localhost:8080/openrdf-sesame.
Connected to http://localhost:8080/openrdf-sesame
> show r.
+----------
|SYSTEM ("System configuration repository")
|VirtSesRep ("Virtuoso Sesame HTTP Repository")
+----------
> open VirtSesRep.
Opened repository 'VirtSesRep'
VirtSesRep> sparql select * from <http://localhost:8890/Northwind> where {?s ?p ?o} Limit 10.
Evaluating query...
+------------------------+------------------------+------------------------+
| s | p | o |
+------------------------+------------------------+------------------------+
| <http://localhost:8890/Northwind/CustomerContact/ALFKI#this>| rdf:type | foaf:Person |
| <http://localhost:8890/Northwind/CustomerContact/ALFKI#this>| rdf:type | northwind:CustomerContact|
| <http://localhost:8890/Northwind/CustomerContact/ALFKI#this>| opl:isDescribedUsing | northwind: |
| <http://localhost:8890/Northwind/CustomerContact/ANATR#this>| rdf:type | foaf:Person |
| <http://localhost:8890/Northwind/CustomerContact/ANATR#this>| rdf:type | northwind:CustomerContact|
| <http://localhost:8890/Northwind/CustomerContact/ANATR#this>| opl:isDescribedUsing | northwind: |
| <http://localhost:8890/Northwind/CustomerContact/ANTON#this>| rdf:type | foaf:Person |
| <http://localhost:8890/Northwind/CustomerContact/ANTON#this>| rdf:type | northwind:CustomerContact|
| <http://localhost:8890/Northwind/CustomerContact/ANTON#this>| opl:isDescribedUsing | northwind: |
| <http://localhost:8890/Northwind/CustomerContact/AROUT#this>| rdf:type | foaf:Person |
+------------------------+------------------------+------------------------+
10 result(s) (530 ms)
VirtSesRep> show n.
+----------
|SearchResults http://www.zillow.com/static/xsd/SearchResults.xsd
|UpdatedPropertyDetails http://www.zillow.com/static/xsd/UpdatedPropertyDetails.xsd
|a http://www.w3.org/2005/Atom
|aapi http://rdf.alchemyapi.com/rdf/v1/s/aapi-schema#
|address http://schemas.talis.com/2005/address/schema#
|admin http://webns.net/mvcb/
|amz http://webservices.amazon.com/AWSECommerceService/2005-10-05
|atom http://atomowl.org/ontologies/atomrdf#
|audio http://purl.org/media/audio#
|awol http://bblfish.net/work/atom-owl/2006-06-06/#
|aws http://soap.amazon.com/
|b3s http://b3s.openlinksw.com/
]]></programlisting>
</listitem>
<listitem>Conversely the Sesame HTTP repository can be configured to access the repository created by the Sesame console.
To do this the location of the data directory for both needs to be reconfigured using the Java system property
info.aduna.platform.appdata.basedir (does not include "OpenRDF Sesame console directory) to point to the same location.
When you are using Tomcat as the servlet container then you can set this property using the JAVA_OPTS parameter.
Note, if you are using Apache Tomcat as a Windows Service you should use the Windows Services configuration tool to
set this property. Other users can either edit the Tomcat startup script or set the property some other way.
<programlisting><![CDATA[
* set JAVA_OPTS=-Dinfo.aduna.platform.appdata.basedir=\path\to\other\dir\ (on Windows)
* export JAVA_OPTS='-Dinfo.aduna.platform.appdata.basedir=/path/to/other/dir/' (on Linux/UNIX/Mac OS X)
]]></programlisting>
<figure id="ss13" float="1">
<title>Virtuoso Sesame HTTP Repository Configuration and Usage</title>
<graphic fileref="ui/ss13.png"/>
</figure>
</listitem>
</orderedlist>
</sect5>
</sect4>
</sect3>
<sect3 id="rdfnativestorageproviderssesamejavadoc"><title>Javadoc API Documentation</title>
<para><ulink url="http://docs.openlinksw.com/sesame/">Sesame Provider Javadoc API Documentation</ulink>
is available enabling the complete set of classes, interfaces and methods implemented for the provider to be viewed.
</para>
</sect3>
</sect2>
<sect2 id="rdfnativestorageproviderredland"><title>Virtuoso Redland Provider</title>
<sect3 id="rdfnativestorageproviderredlandwhatis"><title>What is Redland</title>
<para><ulink url="http://librdf.org/">Redland</ulink> is a set of free software 'C' libraries that
provide support for the Resource Description Framework (RDF), providing modular, object based libraries
and APIs for manipulating the RDF graph, triples, URIs and Literals. Redland includes several high-level
language APIs providing RDF manipulation and storage and requires the
<ulink url="http://librdf.org/raptor/">Raptor</ulink> RDF parser and <ulink url="http://librdf.org/rasqal/">Rasqal</ulink>
RDF syntax and query library
for its use.
</para>
</sect3>
<sect3 id="rdfnativestorageproviderredlandwhatisv"><title>What is the Virtuoso Redland Provider</title>
<para>The Virtuoso Redland RDF Provider is an implementation of the Storage API, Model and Query
interfaces of the Redland framework for RDF. This provider enables the execution of queries via the
Redland Rasqal query engine or via Virtuoso query engine directly against the Virtuoso Quad store.
The Virtuoso Redland Provider uses ODBC as the data access mechanism for communicating the Virtuoso
Quad Store and requires the Virtuoso ODBC Driver be installed on the Redland client and a suitable
ODBC DSN be configured for connecting to the target Virtuoso Quad Store instance. The provider has
been tested against the <ulink url="http://download.librdf.org/source/">Redland 1.0.8</ulink> version currently available for download.
</para>
<figure id="rdfnativestorageproviderredland1" float="1">
<title>Redland Component Stack</title>
<graphic fileref="ui/VirtRedLand.png"/>
</figure>
<para>As indicated in the above diagram the Virtuoso Provider can be used to execute RDF queries either
directly against the Virtuoso graph storage module supporting the <ulink url="http://dbpedia.org/resource/SPARQL">SPARQL</ulink>,
<ulink url="http://dbpedia.org/resource/SPARUL">SPARQL</ulink>SPARUL, <ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VOSArticleBISPARQL2">SPARQL-BI</ulink>
query languages or via the Rasqal query engine built into Redland which supports the SPARQL query language.
This is done by simply changing the syntax of the query using the "vsparql" rather then default "sparql"
construct when executing a query as indicated in the sample queries below:
</para>
<programlisting><![CDATA[
rdfproc -r xml -t "user='dba',password='dba',dsn='Demo'" gr query sparql - "SELECT * WHERE { ?s ?p ?o }" ;; via Redland Rasqal engine
rdfproc -r xml -t "user='dba',password='dba',dsn='Demo'" gr query vsparql - "SELECT * WHERE { ?s ?p ?o }" ;; direct to Virtuoso storage module
]]></programlisting>
<para>The Virtuoso Provider uses the <ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VOSSQL2RDF">SPASQL</ulink> query language for querying the remote Virtuoso QUAD store.
</para>
</sect3>
<sect3 id="rdfnativestorageproviderredlandsetup"><title>Setup</title>
<sect4 id="rdfnativestorageproviderredlandreqfiles"><title>Required Files</title>
<para>The Virtuoso Redland Provider has been integrated into the Redland RDF Framework and submitted to
the open source project to become part of the standard distribution available for
<ulink url="http://librdf.org/INSTALL.html">download</ulink>. Until this
submission has been accepted and committed into the available Redland release a tar ball created by
OpenLink Software and a diff for application to a Redland 1.0.8 tree can be obtained from:
</para>
<itemizedlist mark="bullet">
<listitem><ulink url="ftp://download.openlinksw.com/support/vos/redland-vos-1.0.8.tar.gz"></ulink>Redland 1.0.8 tar ball with Virtuoso storage support</listitem>
<listitem><ulink url="ftp://download.openlinksw.com/support/vos/redland-vos.diff">Redland 1.0.8 Diff file of changes made for Virtuoso storage support</ulink></listitem>
</itemizedlist>
</sect4>
<sect4 id="rdfnativestorageprovidersredlandcmsmpr"><title>Compiling Redland with Virtuoso storage support</title>
<itemizedlist mark="bullet">
<listitem><ulink url="http://svn.librdf.org/">Download Redland</ulink>, extract and apply diff
above or download the tar ball above with diff already applied and extract to a location of choice.</listitem>
<listitem>The following additional configure options are available for enabling the Virtuoso
storage support:
<programlisting><![CDATA[
--with-virtuoso(=yes|no) Enable Virtuoso RDF store (default=auto)
--with-iodbc(=DIR) Select iODBC support
DIR is the iODBC base install directory
(default=/usr/local)
--with-unixodbc(=DIR) Select UnixODBC support
DIR is the UnixODBC base install directory
(default=/usr/local)
--with-datadirect(=DIR) Select DataDirect support
DIR is the DataDirect base install directory
(default=/usr/local)
--with-odbc-inc=DIR Specify custom ODBC include directory
(default=/usr/local/include)
--with-odbc-lib=DIR Specify custom ODBC lib directory
(default=/usr/local/lib)
]]></programlisting>
</listitem>
<listitem>The "--with-virtuoso" option default to being auto enable if a valid ODBC Driver Manager
(iODBC, UnixODBC? or DataDirect?) or include and lib directories for required ODBC header files and libraries
are located with the suitable setting for one or more of the other ODBC related options above. Assuming
iODBC is installed the following option can be used to enable Virtuoso storage support to be configured
for compilation into your Redland build:
<programlisting><![CDATA[
./configure --with-iodbc=/usr/local/iODBC
]]></programlisting>
</listitem>
<listitem>Run "make" to compile the Redland libraries and "sudo make install" to install in
the default "/usr/local" location</listitem>
<listitem>Test compilation with test utility utils/rdfproc:
<programlisting><![CDATA[
rdfproc test parse http://planetrdf.com/guide/rss.rdf
rdfproc test print
rdfproc test serialize ntriples
]]></programlisting>
<para>This test will use the default 'hashes' storage.</para>
</listitem>
<listitem>Ensure you have the Virtuoso ODBC Driver installed and a valid ODBC DSN called
"Local Virtuoso" configured for your target Virtuoso Server</listitem>
<listitem>Set the following environment variable:
<programlisting><![CDATA[
export RDFPROC_STORAGE_TYPE=virtuoso ;; Enable Virtuoso Storage
export ODBCINI=<path_to_odbcini_directory>/odbc.ini ;; Enable ODBC DSN to be located
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH ;; May be required to enable Redland libraries to be located
]]></programlisting>
</listitem>
<listitem>Test Virtuoso storage with the provided test program utils/vtest:
<programlisting><![CDATA[
$ utils/vtest
1: Remove all triples in <http://red> context
**PASSED**: removed context triples from the graph
2: Add triples to <http://red> context
**PASSED**: add triple to context
3: Print all triples in <http://red> context
[[
{[aa], [bb], [cc]} with context [http://red]
{[aa], [bb1], [cc]} with context [http://red]
{[aa], [a2], "cc"} with context [http://red]
{[aa], [a2], (cc)} with context [http://red]
{[mm], [nn], "Some long literal with language@en"} with context [http://red]
{[oo], [pp], "12345^^<http://www.w3.org/2001/XMLSchema#int>"} with context [http://red]
]]
**PASSED**:
4: Count of triples in <http://red> context
**PASSED**: graph has 6 triples
5: Exec: ARC aa bb
Matched node: [cc]
**PASSED**:
6: Exec: ARCS aa cc
Matched node: [bb] with context [http://red]
Matched node: [bb1] with context [http://red]
: matching nodes: 2
**PASSED**:
7: Exec: ARCS-IN cc
Matched arc: [bb] with context [http://red]
Matched arc: [bb1] with context [http://red]
**PASSED**: matching arcs: 2
8: Exec: ARCS-OUT aa
Matched arc: [bb] with context [http://red]
Matched arc: [bb1] with context [http://red]
Matched arc: [a2] with context [http://red]
Matched arc: [a2] with context [http://red]
**PASSED**: matching arcs: 4
9: Exec: CONTAINS aa bb1 cc
**PASSED**: the graph contains the triple
10: Exec: FIND aa - -
Matched triple: {[aa], [bb], [cc]} with context [http://red]
Matched triple: {[aa], [bb1], [cc]} with context [http://red]
Matched triple: {[aa], [a2], "cc"} with context [http://red]
Matched triple: {[aa], [a2], (cc)} with context [http://red]
**PASSED**: matching triples: 4
11: Exec: HAS-ARC-IN cc bb
**PASSED**: the graph contains the arc
12: Exec: HAS-ARC-OUT aa bb
**PASSED**: the graph contains the arc
13: Exec: SOURCE aa cc
Matched node: [aa]
**PASSED**:
14: Exec: SOURCES bb cc
Matched node: [aa] with context [http://red]
: matching nodes: 1
**PASSED**:
15: Exec: TARGET aa bb
Matched node: [cc]
**PASSED**:
16: Exec: TARGETS aa bb
Matched node: [cc] with context [http://red]
: matching nodes: 1
**PASSED**:
17: Exec: REMOVE aa bb1 cc
**PASSED**: removed triple from the graph
18: Exec: QUERY "CONSTRUCT {?s ?p ?o} FROM <http://red> WHERE {?s ?p ?o}"
Matched triple: {[aa], [a2], "cc"}
Matched triple: {[oo], [pp], "12345^^<http://www.w3.org/2001/XMLSchema#int>"}
Matched triple: {[aa], [a2], (cc)}
Matched triple: {[aa], [bb], [cc]}
Matched triple: {[mm], [nn], "Some long literal with language@en"}
**PASSED**: matching triples: 5
19: Exec1: QUERY_AS_BINDINGS "SELECT * WHERE {graph <http://red> { ?s ?p ?o }}"
**: Formatting query result as 'xml':
<?xml version="1.0" encoding="utf-8"?>
<sparql xmlns="http://www.w3.org/2005/sparql-results#">
<head>
<variable name="s"/>
<variable name="p"/>
<variable name="o"/>
</head>
<results>
<result>
<binding name="s"><uri>aa</uri></binding>
<binding name="p"><uri>bb</uri></binding>
<binding name="o"><uri>cc</uri></binding>
</result>
<result>
<binding name="s"><uri>aa</uri></binding>
<binding name="p"><uri>a2</uri></binding>
<binding name="o"><literal>cc</literal></binding>
</result>
<result>
<binding name="s"><uri>aa</uri></binding>
<binding name="p"><uri>a2</uri></binding>
<binding name="o"><bnode>cc</bnode></binding>
</result>
<result>
<binding name="s"><uri>mm</uri></binding>
<binding name="p"><uri>nn</uri></binding>
<binding name="o"><literal>Some long literal with language@en</literal></binding>
</result>
<result>
<binding name="s"><uri>oo</uri></binding>
<binding name="p"><uri>pp</uri></binding>
<binding name="o"><literal>12345^^<http://www.w3.org/2001/XMLSchema#int></literal></binding>
</result>
</results>
</sparql>
**PASSED**:
20: Exec2: QUERY_AS_BINDINGS "SELECT * WHERE {graph <http://red> { ?s ?p ?o }}"
: Query returned bindings results:
result: [s=[aa], p=[bb], o=[cc]]
result: [s=[aa], p=[a2], o=cc]
result: [s=[aa], p=[a2], o=(cc)]
result: [s=[mm], p=[nn], o=Some long literal with language@en]
result: [s=[oo], p=[pp], o=12345^^<http://www.w3.org/2001/XMLSchema#int>]
: Query returned 5 results
**PASSED**:
=============================================
PASSED: 20 FAILED: 0
]]></programlisting>
</listitem>
</itemizedlist>
</sect4>
<sect4 id="rdfnativestorageprovidersredlandcp"><title>Connection Parameters</title>
<para>The Virtuoso provider has the following connection parameters available fro use:</para>
<itemizedlist mark="bullet">
<listitem><emphasis>dsn</emphasis> - ODBC datasource name</listitem>
<listitem><emphasis>user</emphasis> - user name of database server</listitem>
<listitem><emphasis>password</emphasis> - password of database server</listitem>
<listitem><emphasis>host</emphasis> - hostname:portno of the database server</listitem>
<listitem><emphasis>charset</emphasis> - database charset to use</listitem>
</itemizedlist>
<para>NOTE: Take care exposing the password as for example, program arguments or environment
variables. The rdfproc utility can help this by reading the password from standard input. Inside programs,
one way to prevent storing the password in a string is to construct a Redland hash of the storage options
such as via librdf hash_from_string and use librdf_new_storage_with_options to create a storage. The
rdfproc utility source code demonstrates this.
</para>
<para>The storage name parameter given to the storage constructor librdf new_storage is used
inside the virtuoso store to allow multiple stores inside one Virtuoso database instance as parameterized
with the above options.
</para>
<para>This store always provides contexts; the boolean storage option contexts is not checked.</para>
<para>Examples:</para>
<programlisting><![CDATA[
/* A new Virtuoso store */
storage=librdf_new_storage(world, "virtuoso", "db1",
"dsn='Local Virtuoso',user='demo',password='demo'");
/* A different, existing Virtuoso store in the same database as above */
storage=librdf_new_storage(world, "virtuoso", "db2",
"dsn='Local Virtuoso',user='demo',password='demo'");
/* An existing Virtuoso store on a different database server */
storage=librdf_new_storage(world, "virtuoso", "http://red3",
"dsn='Remote Virtuoso',user='demo',password='demo'");
/* Opening with an options hash */
options=librdf_new_hash(world, NULL);
librdf_hash_from_string(options,
"dsn='Local Virtuoso',user='demo'");
librdf_hash_put_strings(options, "password", user_password);
storage=librdf_new_storage_with_options(world, "virtuoso", "http://red3", options);
]]></programlisting>
</sect4>
</sect3>
<sect3 id="rdfnativestorageprovidersredlandref"><title>References</title>
<itemizedlist mark="bullet">
<listitem><ulink url="http://librdf.org/docs/api/redland-storage.html">RedLand Triple Store</ulink></listitem>
<listitem><ulink url="http://librdf.org/docs/api/redland-storage-modules.html">RedLand Storage Modules</ulink></listitem>
</itemizedlist>
</sect3>
</sect2>
</sect1>
</chapter>
|