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
|
<?xml version="1.0" encoding="UTF-8"?>
<!--
-
- This file is part of the OpenLink Software Virtuoso Open-Source (VOS)
- project.
-
- Copyright (C) 1998-2018 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
-
-
-->
<chapter id="overview" label="overview.xml">
<title>Overview</title>
<abstract>
<para>A quick overview on Virtuoso providing answers to simple questions that may
already be in mind.</para>
</abstract>
<!-- ======================================== -->
<sect1 id="WhatIsVirtuoso">
<title>What is Virtuoso?</title>
<para>OpenLink Virtuoso is the first CROSS PLATFORM Universal Server to
implement Web, File, and Database server functionality alongside Native XML
Storage, and Universal Data Access Middleware, as a single server solution.
It includes support for key Internet, Web, and Data Access standards such
as: XML, XPATH, XSLT, SOAP, WSDL, UDDI, WebDAV, SMTP, SQL-92, ODBC, JDBC,
and OLE-DB. Virtuoso currently supports the following Operating systems -
Windows 95/98/NT/2000, Linux (Intel, Alpha, Mips, PPC), Solaris, AIX, HP-UX,
Unixware, IRIX, Digital UNIX, DYNIX/PTX, FreeBSD, SCO, MacOS X.</para>
<para>Virtuoso is a revolutionary, next generation, high-performance virtual database engine
for the Distributed Computing Age. It is a core universal data access technology set to
accelerate our advances into the emerging Information Age.</para>
<para>Virtuoso provides transparent access to your existing data sources, which are typically
databases from different database vendors.</para>
<para>Through a single connection, Virtuoso will simultaneously connect your ODBC, JDBC,
UDBC, OLE-DB client applications and services to data within Oracle, Microsoft SQL Server,
DB/2, Informix, Progress, CA-Ingres and other ODBC compliant database engines. All your
databases are treated as single logical unit.</para>
<para>The diagram below depicts how applications that are built in conformance with industry
standards (such as ODBC, JDBC, UDBC, and OLE-DB) only need to make a single connection via
Virtuoso's Virtual Database Engine and end up with concurrent and real-time access to data
within different database types.</para>
<para>Further still, Virtuoso exposes all of its functionality to Web Services.
This means that your existing infrastructure can be used support Web Services
directly without any hint of replacement.
</para>
</sect1>
<sect1 id="virtwhydoi">
<title>Why Do I Need Virtuoso?</title>
<para>You need Virtuoso because Knowledge is power or competitive advantage (depending on how
you choose to exploit it). All Knowledge comes from Information. Information is produced
from Data. </para>
<para>The Internet is reducing the cost of accessing Information, thereby increasing the
appetite and rates at which Information is produced and consumed. Unfortunately data
required for the production of Information simply does not reside within one database
engine within your organization. </para>
<para>Whether you know it or not it is highly probable that the quest for critical
information within your organization actually requires traversing several data sources
served by numerous database engines from different database vendors.</para>
<para>Virtuoso simply reduces the cost of bringing together data from different data sources
with the view to accelerating the production of information by your Query Tools, Web &
Internet Application Development Environments, Traditional Application Development Tools,
and Desktop Productivity Tools.</para>
<para>Virtuoso enables you to compete effectively in the Information Age.</para>
<para>One of the biggest challenges facing the uptake of XML is the
availability of key XML Data itself. Virtuoso simplifies the process of
creating XML data from existing HTML, syndicated XML, and SQL databases.
Virtuoso enables real-time creation of Dynamic XML documents (DTD or
XML Schema based) from homogeneous or heterogeneous SQL Databases "on the fly".</para>
<para>By implementing a number of protocols in a single server solution,
Virtuoso provides you with a unifying foundation upon which next generation
eBusiness solutions can be developed and deployed. Virtuoso reduces the cost
of bringing together data from different data sources and leverages this
into increased effectiveness of your Query Tools, Web & Internet Application
Development Environments, Traditional Application Development Tools, and
Desktop Productivity Tools. Virtuoso enables you compete effectively in the
Information Age.</para>
<para>OpenLink Software is an acclaimed technology innovator and leading
vendor of High-Performance & CROSS PLATFORM eBusiness solutions that
adhere to a broad range of industry standards that include: ODBC, JDBC,
OLE DB, SQL, WebDAV, HTTP, XML, SOAP, UDDI, WSDL, SMTP, NNTP, POP3, LDAP
amongst others.</para>
<para>Our product & services portfolio includes a suite of
High-Performance Universal Data Access Drivers for ODBC, OLE DB and JDBC,
Internet Data Integration Servers, Virtual and Federated Database Engines,
Embeddable SQL-Database Engines, Application Servers, Enterprise Portal
Servers and professional services expertise capable of handling the most
demanding eBusiness application development, deployment, and integration
challenges.</para>
</sect1>
<sect1 id="whatisnewto2x">
<title>Key Features of Virtuoso</title>
<figure id="varch32" float="1"><title>OpenLink Virtuoso Product Architecture</title>
<graphic fileref="varch32.jpg" width="384px" depth="377px"/></figure>
<sect2 id="oxmldocstore"><title>XML Document Storage & Creation</title>
<para>Virtuoso enables you to develop eBusiness solutions that use <emphasis>XML</emphasis>
as a common data access foundation layer that provides transparent access
to structured and unstructured data. XML Data documents can be created
internally, or imported from around the Web and then stored in Virtuoso.
You can also create dynamic XML documents by transforming SQL to XML
on the fly, leveraging data that resides within homogeneous and/or
heterogeneous database(s). <emphasis>XPATH 2.0</emphasis> query language support enables you to
query entire XML Documents using and industry standard query language.
The Virtuoso Server provides some basic support for the
<link linkend="xq"><emphasis>XQuery 1.0</emphasis> XML Query Language</link>
specification.
There is <emphasis>XML Schema</emphasis> support for extending Virtuoso Data
types used by SOAP Services.</para>
</sect2>
<sect2 id="ointernetsrv"><title>Web Page Hosting</title>
<para>Virtuoso has an integrated HTTP web server, for static HTML pages, or
dynamic content using <link linkend="vsp1">Virtuoso Server Pages
(<emphasis>VSP</emphasis>)</link>.
Hosting and execution of <emphasis>PHP4</emphasis> scripts is supported
via Virtuoso Server Extensions Interface (VSEI) for Zend.</para>
</sect2>
<sect2 id="owebsrvhost"><title>Web Services Creation & Hosting</title>
<para>Enables the creation of <emphasis>SOAP</emphasis> compliant Web Services from SQL Stored
Procedures, these procedures may be native to Virtuoso or resident in
third party databases that support ODBC or JDBC. Virtuoso automatically
generates <emphasis>WSDL</emphasis> files for the Stored Procedures that it exposes as Web
Services. As a <emphasis>UDDI</emphasis> server (registry) all of your Web Services can be
stored for access across the internet or within an intranet. It can also
synchronize data with other UDDI servers.</para>
</sect2>
<sect2 id="owebdavstore"><title>WebDAV Compliant Web Store</title>
<para><emphasis>WebDAV</emphasis> support enables Virtuoso to act as the Web Content Store for
all of your eBusiness data, this includes Text, Graphics and Multimedia
files. WebDAV support also enables Virtuoso to play the familiar roles of
a FILE & WEB SERVER, hosting entire Web sites within a single database
file, or across multiple database files.</para>
</sect2>
<sect2 id="oreplandsync"><title>Content Replication & Synchronization</title>
<para>Virtuoso's sophisticated data replication and synchronization engine
enables the automated distribution and updating of SQL and Web Content
across distributed Virtuoso servers.</para>
</sect2>
<sect2 id="ophetdata"><title>Transparent Access To Heterogeneous Data</title>
<para>Virtuoso's Virtual Database Engine enables you to produce Dynamic Web
Content from any major database management system. This enables dynamic,
real-time HTML and XML generation from any number of different database
engines concurrently.</para>
</sect2>
<sect2 id="omaildelresrv"><title>Mail Delivery & Retrieval Services</title>
<para>Virtuoso can act as an <emphasis>SMTP</emphasis>, <emphasis>POP3</emphasis>, and
<emphasis>IMAP4</emphasis> proxy to any email
client. This enables the development and deployment of sophisticated
database driven email solutions.</para>
</sect2>
<sect2 id="onntp"><title>NNTP Aggregation & Serving</title>
<para>Virtuoso supports the Network News Transfer Protocol used by Internet
newsgroup forums. <emphasis>NNTP</emphasis> servers manage the global network of collected
newsgroup postings and represent a vast repository of targeted information
archives. As an NNTP aggregator, Virtuoso enables integration of multiple
news forums around the world. All news content in Virtuoso is dynamically
indexed to provide keyword searches, enabling rapid transformation of
disparate text data into information. Virtuoso also acts as an NNTP server,
enabling creation of new Internet and Intranet News Forums to leverage the
global knowledgebase into eBusiness Intelligence.</para>
</sect2>
</sect1>
<sect1 id="virtuosofaq">
<title>Virtuoso FAQ</title>
<para>We have received various inquiries on high-end metadata stores. We will here go through some salient
questions. The requested features include:
</para>
<itemizedlist mark="bullet">
<listitem>Scaling to trillions of triples</listitem>
<listitem>Running on clusters of commodity servers</listitem>
<listitem>Running in federated environments, possibly over wide-area networks</listitem>
<listitem>Built-in inference</listitem>
<listitem>Transactions</listitem>
<listitem>Security</listitem>
<listitem>Support for extra triple level metadata, such as security attributes</listitem>
</itemizedlist>
<para><emphasis>Questions:</emphasis></para>
<sect2 id="virtuosofaq1"><title>What is the storage cost per triple?</title>
<para>This depends on the index scheme. If indexed 2 ways, assuming that the graph will
always be stated in queries, this is 31 bytes.</para>
<para>With 4 indices, supporting queries where the graph can be left unspecified (i.e., triples from
any graph will be considered in query evaluation), this is 39 bytes. The numbers are measured with
the LUBM validation data set of 121K triples, with no full-text index on literals.</para>
<para>With 4 indices and a full text index on all literals, the Billion Triples Challenge data set,
1115M triples, is about 120 GB of database pages. The database file size is larger due to space in
reserve and other factors. 120 GB is the number to use when assessing RAM-to-disk ratio, i.e., how
much RAM the system ought to have in order to provide good response. This data set is a heterogeneous
collection including social network data, conversations harvested from the Web, DBpedia, Freebase,
etc., with relatively numerous and long text literals.</para>
<para>The numbers do not involve any database page stream compression such as gzip. Using such
compression does not save in terms of RAM because cached pages must be kept uncompressed but
will cut the disk usage to about half.</para>
</sect2>
<sect2 id="virtuosofaq2"><title>What is the cost to insert a triple (for the insertion
itself, as well as for updating any indices)?</title>
<para>The more triples are inserted at a time, the faster this goes. Also, the more concurrent
triple insertions are going on, the better the throughput. When loading data such as the US Census,
a cluster of 2 commodity servers can insert up to 100,000 triples per second.</para>
<para>A single 4-core machine can load 1 billion triples of LUBM data at an average rate
of 36K triples per second. This is limited by disk.</para>
</sect2>
<sect2 id="virtuosofaq3"><title>What is the cost to delete a triple (for the deletion
itself, as well as for updating any indices)?</title>
<para>
The delete cost is similar to insert cost.
</para>
</sect2>
<sect2 id="virtuosofaq4"><title>What is the cost to search on a given property?</title>
<para>If we are looking for equality matches, a single 2GHz core can do about 250,000 single triple
random lookups per second as long as disk reads are not involved. If each triple requires a disk
seek the number is naturally lower.
</para>
<para>Parallelism depends on the query. With a query like counting all x and y such that x knows
y and y knows x, we get up to 3.4 million single-triple lookups-per-second on a cluster of 2 8-core
Xeon servers. With complex nested sub-queries the parallelism may be less.
</para>
<para>Lookups involving ranges of values, such as ranges of geographical coordinates or dates use
an index, since quads are indexed in a manner that collates in the natural order of the data type.
</para>
</sect2>
<sect2 id="virtuosofaq5"><title>What data types are supported?</title>
<para>Virtuoso supports all RDF data types, including language-tagged and XML schema typed strings
as native data types. Thus there is no overhead converting between RDF data types and types
supported by the underlying DBMS.
</para>
</sect2>
<sect2 id="virtuosofaq6"><title>What inferencing is supported?</title>
<para>Subclass, subproperty, identity by inverse-functional properties, and owl:sameAs are
processed at run time if an inference context option is specified in the query.
</para>
<para>There is a general-purpose transitivity feature that can be used for a
wide variety of graph algorithms. For example:
</para>
<programlisting><![CDATA[
SELECT ?friend
WHERE
{
<alice> foaf:knows ?friend option (transitive)
}
]]></programlisting>
<para>would return all the people directly or indirectly known by <alice>.
</para>
</sect2>
<sect2 id="virtuosofaq7"><title>Is the inferencing dynamic, or is an extra
step required before inferencing can be used?</title>
<para>The mentioned types of inferencing are enabled by a switch in the query and are done at
run-time, with no step for materialization of entailed triples needed. The pattern:
</para>
<programlisting><![CDATA[
{?s a <type>}
]]></programlisting>
<para>would iterate over all the RDFS subclasses of <type> and look for subjects with this type.
</para>
<para>The pattern:
</para>
<programlisting><![CDATA[
{<thing> a ?class}
]]></programlisting>
<para>will, if the match of ?class has superclasses, also return the superclasses even though the
superclass membership is not physically stored for each superclass.
</para>
<para>Of course, one can always materialize entailed triples by running SPARQL/SPARUL statements
to explicitly add any implied information.
</para>
<para>If two subjects have the same inverse functional property with the same value, they will be
considered the same. For example, if two people have the same email address, they will be
considered the same.
</para>
<para>If two subjects are declared to be owl:sameAs, either directly or through a chain of x owl:sameAs
y, y owl:sameAs z, and so on, they will be considered the same.
</para>
<para>These features can be individually enabled and disabled. They all have some run time cost, hence
they are optional. The advantage is that no preprocessing of the data itself is needed before querying,
and the data does not get bigger. This is important, especially if the database is very large and
queries touch only small parts of it. In such cases, materializing implied triples can be very costly.
See discussion at <ulink url="http://www.openlinksw.com/weblog/oerling/?id=1498">E Pluribus Unum</ulink>
</para>
</sect2>
<sect2 id="virtuosofaq8"><title>Do you support full-text search?</title>
<para>Virtuoso has an optional full-text index on RDF literals. Searching for text matches using
the SPARQL regex feature is very inefficient in the best of cases. This is why Virtuoso offers a special
<emphasis>bif:contains</emphasis> predicate similar to the SQL <emphasis>contains</emphasis> predicate
of many relational databases. This supports a full-text query language with proximity, and/or/and-not,
wildcards, etc.
</para>
<para>While the full-text index is a general-purpose SQL feature in Virtuoso, there is extra RDF-specific
intelligence built into it. One can, for example, specify which properties are indexed, and within which
graphs this applies.
</para>
</sect2>
<sect2 id="virtuosofaq9"><title>What programming interfaces are supported? Do you
support standard SPARQL protocol?</title>
<para>Virtuoso supports the standard SPARQL protocol.
</para>
<para>Virtuoso offers drivers for the Jena, Sesame, and Redland frameworks. These allow using
Virtuoso's store and SPARQL implementation as the back end of Jena, Sesame, or Redland applications.
Virtuoso will then do the query optimization and execution. Jena and Sesame drivers come standard;
contact us about Redland.
</para>
<para>Virtuoso SPARQL can be used through any SQL call level interface (CLI) supported by Virtuoso
(i.e., ODBC, JDBC, OLE-DB, ADO.NET, XMLA). All have suitable extensions for RDF specific data types
such as IRIs and typed literals. In this way, one can write, for example, PHP web pages with SPARQL
queries embedded, just using the SQL tools. Prefixing a SQL query with the keyword "sparql" will
invoke SPARQL instead of SQL, through any SQL client API.
</para>
</sect2>
<sect2 id="virtuosofaq10"><title>How can data be partitioned across multiple servers?</title>
<para>
Virtuoso Cluster partitions each index of all tables containing RDF data separately. The partitioning is by
hash. The result is that the data is evenly distributed over the selected number of servers. Immediately
consecutive triples are generally in the same partition, since the low bits of IDs do not enter in into
the partition hash. This means that key compression works well.
</para>
<para>
Since RDF tables are in the end just SQL tables, SQL can be used for specifying a non-standard
partitioning scheme. For example, one could dedicate one set of servers for one index, and
another set for another index. Special cases might justify doing this.
</para>
<para>
With very large deployments, using a degree of application-specific data structures may be advisable.
See "Does Virtuoso support property tables".
</para>
</sect2>
<sect2 id="virtuosofaq11"><title>How many triples can a single server handle?</title>
<para>
With free-form data and text indexing enabled, 500M triples per 16G RAM can be a ballpark guideline.
If the triples are very short and repetitive, like the LUBM test data, then 16G per one billion
triples is a possibility. Much depends on the expected query load. If queries are simple lookups,
then less memory per billion triples is needed. If queries will be complex (analytics, join sequences,
and aggregations all over the data set), then relatively more RAM is necessary for good performance.
</para>
<para>
The count of quads has little impact on performance as long as the working set fits in memory. If
the working set is in memory, there may be 15-20% difference between a million and a billion triples.
If the database must frequently go to disk, this degrades performance since one can easily do 2000
random accesses in memory in the time it takes to do one random access from disk. But working-set
characteristics depend entirely on the application.
</para>
<para>
Whether the quads in a store all belong to one graph or any number of graphs makes no difference.
There are Virtuoso instances in regular online use with hundreds of millions of triples, such as
DBpedia and the <ulink url="http://neurocommons.org/page/Main_Page">Neurocommons</ulink> databases.
</para>
</sect2>
<sect2 id="virtuosofaq12"><title>What is the performance impact of going from the
billion to the trillion triples?</title>
<para>
Performance dynamics change when going from a single server to a cluster. If each partition is around a
billion triples in size, then the single triple lookup takes the same time, but there is cluster
interconnect latency added to the mix.
</para>
<para>
On the other hand, queries that touch multiple partitions or multiple triples in a partition will do
this in parallel and usually with a single message per partition. Thus throughput is higher.
</para>
<para>
In general terms, operations on a single triple at a time from a single thread are penalized and
operations on hundreds or more triples at a time win. Multiuser throughput is generally better
due to more cores and more memory, and latency is absorbed by having large numbers of concurrent requests.
</para>
<para>
See <ulink url="http://www.openlinksw.com/weblog/oerling/?id=1487">a sample of SPARQL scalability</ulink>.
</para>
</sect2>
<sect2 id="virtuosofaq13"><title>Do you support additional metadata for triples,
such as time-stamps, security tags etc?</title>
<para>
Since quads (triple plus graph) are stored in a regular SQL table with special data types, changing the
table layout to add a column is possible. This column would not however be visible to SPARQL without
some extra tuning. For coarse grain provenance and security information, we recommend doing this at
the graph level, where triples that belong together are tagged with the same provenance or security
are in the same graph. The graph can then have the relevant metadata as its properties.
</para>
<para>
If tagging at the single triple level is needed, this will most often not be needed for all triples.
Hence altering the table for all triples may not be the best choice. Making a special table that
has the graph, subject, predicate and object of the tagged triple as a key and the tag data as a
dependent part may be more efficient. Also, this table could be more easily accessed from SPARQL.
</para>
<para>
Using the RDF reification vocabulary is not recommended as a first choice but is possible without
any alterations.
</para>
<para>
Alterations of this nature are possible but we recommend contacting us for specifics. We can
provide consultancy on the best way to do this for each application. Altering the storage layout
without some extra support from us is not recommended.
</para>
</sect2>
<sect2 id="virtuosofaq14"><title>Should we use RDF for our large metadata store?
What are the alternatives?</title>
<para>
If the application has high heterogeneity of schema and frequent need for adaptation, then RDF is
recommended. The alternative is making a relational database.
</para>
<para>
Making a custom non-RDF object-attribute-value representation on Virtuoso or some other RDBMS is
possible but not recommended.
</para>
<para>
The reason for this is that this would miss many of the optimizations made specifically for RDF,
use of the SPARQL language, inference, compatibility with diverse browsers and front end tools,
etc. Not to mention interoperability and joinability with the body of linked data. Even if the
application is strictly private, using entity names and ontologies from the open world can still
have advantages.
</para>
<para>
If some customization to the quad (triple plus graph layout) is needed, we can provide consultancy
on how to do this while staying within the general RDF framework and retaining all the interoperability
benefits.
</para>
</sect2>
<sect2 id="virtuosofaq15"><title>How multithreaded is Virtuoso?</title>
<para>
All server and client components are multithreaded, using pthreads on Unix/Linux, Windows native on
Windows. Multithread/multicore scalability is good; see
<ulink url="http://www.openlinksw.com/weblog/oerling/?id=1409">BSBM</ulink>
</para>
<para>
In the case of Virtuoso Cluster, in order to have the maximum number of threads on a single query,
we recommend that each server on the cluster be running one Virtuoso process per 1.2 cores.
</para>
</sect2>
<sect2 id="virtuosofaq16"><title>Can multiple servers run off a single shared disk
database?</title>
<para>This might be possible with some customization but this is not our preferred way. Instead, we can
store selected indices in duplicate or more copies inside a clustered database. In this way, all
servers can have their own disk. Each key of each index will belong to one partition but each
partition will have more than one physical copy, each on a different server. The cluster query
logic will perform the load balancing. On the update side, the cluster will automatically do a
distributed transaction with two phase commit to keep the duplicates in sync.
</para>
</sect2>
<sect2 id="virtuosofaq17"><title>Can Virtuoso run on a SAN?</title>
<para>
Yes. Unlike Oracle RAC, for example, Virtuoso Cluster does not require a SAN. Each server has its
own database files and is solely responsible for these. In this way, having shared disk among all
servers is not required. Running on a SAN may still be desirable for administration reasons. If
using a SAN, the connection to the SAN should be high performance, such as Infiniband.
</para>
</sect2>
<sect2 id="virtuosofaq18"><title>How does Virtuoso join across partitions?</title>
<para>
Partitioning is entirely transparent to the application. Virtuoso has a highly optimized
message-flow between cluster nodes that combines operations into large batches and evaluates
conditions close to the data. See a sample of RDF scaling.
</para>
</sect2>
<sect2 id="virtuosofaq19"><title>Does Virtuoso support federated triple stores? If
there are multiple SPARQL end points, can Virtuoso be used to do queries joining between these?</title>
<para>
This is a planned extension. The logic for optimizing message flow between multiple end-points on
a wide-area network is similar to the logic for message-optimization on a cluster. This will
allow submitting a query with a list of end-points. The query will then consider triples from
each of the end points, as if the content of all the end points were in a single store.
</para>
<para>
End-point meta information, such as voiD descriptions of the graphs in the end-points, may be
used to avoid sending queries to end points that are known not to have a certain type of data.
</para>
</sect2>
<sect2 id="virtuosofaq20"><title>How many servers can a cluster contain?</title>
<para>
There is no fixed limit. If you have a large cluster installed, you can try Virtuoso there.
Having an even point-to-point latency is desirable.
</para>
</sect2>
<sect2 id="virtuosofaq21"><title>How do I reconfigure a cluster, adding and
removing machines, etc?</title>
<para>
We are working on a system whereby servers can be added and removed from a cluster during
operation and no repartitioning of the data is needed.
</para>
<para>
In the first release, the number of server processes that make up the cluster is set when
creating the database. These processes with their database files can then be moved between
machines but this requires stopping the cluster and updating configuration files.
</para>
</sect2>
<sect2 id="virtuosofaq22"><title>How will Virtuoso handle regional clusters?</title>
<para>
Performance of a cluster depends on the latency and bandwidth of the interconnect. At least dual
1Gbit ethernet is recommended for each node. Thus a cluster should be on a single local or system
area network.
</para>
<para>
If regional copies are needed, we would replicate between clusters by asynchronous log shipping.
This requires some custom engineering.
</para>
<para>
When a transaction is committed at one site, it is logged and sent to the subscribing sites if
they are online. If there is no connection, the subscribing sites will get the data from the log.
This scheme now works between single Virtuoso servers, and needs some custom development to be
adapted to clusters.
</para>
<para>
If replicating all the data of one site to another site is not possible, then application logic
should be involved. Also, if consolidated queries should be made against large,
geographically-separated clusters, then it is best to query them separately and merge the
results in the application. All depends on the application level rules on where data resides.
</para>
</sect2>
<sect2 id="virtuosofaq23"><title>Is there a mechanism for terminating long running queries?</title>
<para>
Virtuoso SPARQL and SQL offer an "anytime" option that will return partial results after a configurable
timeout.
</para>
<para>
In this way, queries will return in a predictable time and indicate whether the results are complete
or not, as well as give a summary of resource utilization.
</para>
<para>
This is especially useful for publishing a SPARQL endpoint where a single long running query could
impact the performance of the whole system. This timeout significantly reduces the risk of denial
of service.
</para>
<para>
This is also more user-friendly than simply timing-out a query after a set period and returning
an error. With the anytime option, the user gets a feel for what data may exist, including whether
any data exists at all. This feature works with arbitrarily complex queries, including aggregation,
GROUP BY, ORDER BY, transitivity, etc.
</para>
<para>
Since the Virtuoso SPARQL endpoint supports open authentication (OAuth), the authentication can be
used for setting timeouts, so as to give different service to different users.
</para>
<para>
It is also possible to set a timeout that will simply abort a query or an update transaction if it
fails to terminate in a set time.
</para>
<para>
Disconnecting the client from the server will also terminate any processing on behalf of that client,
regardless of timeout settings.
</para>
<para>
The SQL client call-level interfaces (ODBC, JDBC, OLE-DB, ADO.NET, XMLA) each support a cancel call
that can terminate a long running query from the application, without needing to disconnect.
</para>
</sect2>
<sect2 id="virtuosofaq24"><title>Can the user be asynchronously notified when a
long running query terminates?</title>
<para>
There is no off-the-shelf API for this but making an adaptation of the SPARQL endpoint that
could proceed after the client disconnected and, for example, could send results by email is
trivial. Since SOAP and REST Web services can be programmed directly in Virtuoso's stored
procedure language, implementing and exposing this type of application logic is easy.
</para>
</sect2>
<sect2 id="virtuosofaq25"><title>How many concurrent queries can Virtuoso handle?</title>
<para>
There is no set limit. As with any DBMS, response times get longer if there is severe congestion.
</para>
<para>
For example, having 2 or 3 concurrent queries per core is a good performance point which will keep
all parts of the system busy. Having more than this is possible but will not increase overall throughput.
</para>
<para>
With a cluster, each server has both HTTP and SQL listeners, so clients can be evenly spread across
all nodes. In a heavy traffic Web application, it is best to have a load balancer in front of the
HTTP endpoints to divide the connections among the servers and to keep some cap on the number of
concurrently running requests, enforcing a maximum request-rate per client IP address, etc.
</para>
</sect2>
<sect2 id="virtuosofaq26"><title>What is the relative performance of SPARQL queries
vs native relational queries?</title>
<para>
This is application dependent. In Virtuoso, SPARQL and SQL share the same query execution engine,
query optimizer, and cost model. If data is highly regular (i.e., a good fit for relational
representation), and if queries typically access most of the row, then SQL will be more efficient.
If queries are unpredictable, data is ragged, schema changes frequent, or inference is needed,
then RDF will do relatively better.
</para>
<para>
The recent Berlin SPARQL Benchmark shows some figures comparing Virtuoso SQL and SPARQL and SPARQL
in front of relational representation. However, the test workload is heavily biased in favor of
relational. See also BSBM: MySQL vs Virtuoso.
</para>
<para>
With the TPC-H workload, relationally stored data, and SPARQL mapped to SQL, we find that with about
half the queries there is no significant cost to SPARQL. With some queries there is additional
overhead because the mapping does not produce a SQL query identical to that specified in the benchmark.
</para>
</sect2>
<sect2 id="virtuosofaq27"><title>Does Virtuoso Support Property Tables?</title>
<para>
For large applications, we would recommend RDF whenever there is significant variability of schema, but
would still use an application-specific, relational style representation for those parts of the data
that are regular in format. This is possible without loss of flexibility for the variable-schema part.
However, this will introduce relational-style restrictions on the regular data; for example, a person
could only have a single date-of-birth by design. In many cases, such restrictions are quite acceptable.
Querying will still take place in SPARQL, and the representation will be transparent.
</para>
<para>
A relational table where the primary key is the RDF subject and where columns represent single-valued
properties is usually called a property table. These can be defined in a manner similar to defining RDF
mappings of relational tables.
</para>
</sect2>
<sect2 id="virtuosofaq28"><title>What performance metrics does Virtuoso offer?</title>
<para>There is an extensive array of performance metrics. This includes:
</para>
<itemizedlist mark="bullet">
<listitem>Cluster status summary with thread counts, CPU utilization, interconnect traffic, clean and
dirty cache pages, virtual memory swapping warning, etc. This is either a cluster total or a total with
breakdown per cluster node.</listitem>
<listitem>Disk access, lock contention, general concurrency, and access count per index </listitem>
<listitem>Statistics on memory usage for disk caching index-by-index, cache replacement statistics, disk
random and sequential read times</listitem>
<listitem>Count of random, sequential index access, disk access, lock contention, cluster interconnect
traffic per query/client </listitem>
<listitem>Detailed query-execution plans are available through the
<link linkend=""><function>explain</function></link> function</listitem>
</itemizedlist>
</sect2>
<sect2 id="virtuosofaq29"><title>What support do you provide for concurrent/multithreaded
operation? Is your interface thread-safe?</title>
<para>
All client interfaces and server-side processes are multithreaded. As usual, each thread of an application
should use a different connection to the database.
</para>
</sect2>
<sect2 id="virtuosofaq30"><title>What level of ACID properties is supported?</title>
<para>
Virtuoso supports all 4 isolation levels from dirty read to serializable, for both relational and RDF data.
</para>
<para>
The recommended default isolation is read-committed, which offers a clean historical read of data that has
uncommitted updates. This mode is similar to the Oracle default isolation and guarantees that no uncommitted
data is seen, and that no read will block waiting for a lock held by another client.
</para>
<para>
There is transaction logging and roll forward recovery, with two phase commit used in Virtuoso Cluster
if an update transaction modifies more than one server.
</para>
<para>
For RDF workloads which typically are not transactional and have large bulk loads, we recommend running
in a "row autocommit" mode without transaction logging. This virtually eliminates log contention but
still guarantees consistent results of multithreaded bulk loads.
</para>
<para>
Setting this up requires some consultancy and custom development but is well worthwhile for large projects.
</para>
</sect2>
<sect2 id="virtuosofaq31"><title>Do you provide the ability to atomically add a set of
triples, where either all are added or none are added?</title>
<para>
Yes. Doing this with millions of triples per transaction may run out of rollback space. Also,
there is risk of deadlock if multiple such inserts run at the same time. For good concurrency,
the inserts should be of moderate size. As usual, deadlocks are resolved by aborting one of the
conflicting transactions.
</para>
</sect2>
<sect2 id="virtuosofaq32"><title>Do you provide the ability to add a set of triples,
respecting the isolation property (so concurrent accessors either see none of the triple values,
or all of them)?</title>
<para>Yes. The reading client should specify serializable isolation and the inserting client should
perform the insert as a transaction, no row autocommit mode.
</para>
</sect2>
<sect2 id="virtuosofaq33"><title>What is the time to start a database, create/open a graph?</title>
<para>
Starting a Virtuoso server process takes a few seconds. Making a new graph takes no time beyond the
time to insert the triples into it. Once the server process(es) are running, all the data is online.
</para>
<para>
With high-traffic applications, reaching cruising speed may sometimes take a long time, specially if
the load is random-access intensive. Filling gigabytes of RAM with cached disk pages takes a long
time if done a page at a time. To alleviate this, Virtuoso pre-reads 2MB-sized extents instead of
single pages if there is repeated access to the same extent within a short time. Thus cache warm-up
times are shortened.
</para>
</sect2>
<sect2 id="virtuosofaq33"><title>What sort of security features are built into Virtuoso?</title>
<para>
For SQL, we have the standard role-based security and an Oracle-style row-level security (policy) feature.
</para>
<para>
For SPARQL, users may have read or update roles at the level of the quad store.
</para>
<para>
With RDF, a graph may be owned by a user. The user may specify read and write privileges on the graph.
These are then enforced for SPARUL (the SPARQL update language) and SPARQL.
</para>
<para>
When an RDF graph is based on relationally stored data in Virtuoso or another RDBMS through Virtuoso's
SQL federation feature (i.e., if the graph is an Linked Data View of underlying SQL data), then all relational
security controls apply.
</para>
<para>
Further, due to the dual-nature of Virtuoso, sophisticated ontology-based security models are feasible.
Such models are not currently used by default, but they are achievable with our consultancy.
</para>
</sect2>
</sect1>
<sect1 id="virtuosotipsandtricks">
<title>Tips and Tricks</title>
<sect2 id="virtuosotipsandtricksgeotr">
<title>How Can I convert triples with geo properties to geometries to use spartial query?</title>
<para>Assuming a Named Graph with the following triples:</para>
<programlisting><![CDATA[
...
<http://linkedgeodata.org/triplify/node454640663> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://linkedgeodata.org/ontology/hostel> .
<http://linkedgeodata.org/triplify/node454640663> <http://www.georss.org/georss/point> "53.2752338 -9.0443748" .
<http://linkedgeodata.org/triplify/node454640663> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-9.0443748"^^<http://www.w3.org/2001/XMLSchema#decimal> .
<http://linkedgeodata.org/triplify/node454640663> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "53.2752338"^^<http://www.w3.org/2001/XMLSchema#decimal> .
<http://linkedgeodata.org/triplify/node280886720> <http://www.w3.org/2000/01/rdf-schema#label> "Abbey House" .
<http://linkedgeodata.org/triplify/node280886720> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://linkedgeodata.org/ontology/bed_and_breakfast> .
<http://linkedgeodata.org/triplify/node280886720> <http://www.georss.org/georss/point> "53.2874983 -9.0702631" .
<http://linkedgeodata.org/triplify/node280886720> <http://www.w3.org/2003/01/geo/wgs84_pos#long> "-9.0702631"^^<http://www.w3.org/2001/XMLSchema#decimal> .
<http://linkedgeodata.org/triplify/node280886720> <http://www.w3.org/2003/01/geo/wgs84_pos#lat> "53.2874983"^^<http://www.w3.org/2001/XMLSchema#decimal> .
...
]]></programlisting>
<para>In order to convert these triples ( with geo properties ) to geometries to use spartial query,
you need to run the <link linkend="fn_fn_rdf_geo_add"><function>DB.DBA.RDF_GEO_FILL ()</function></link>
function to populate the special RDF_GEO table with the point information as detailed at
<link linkend="rdfsparqlgeospatcrg">Creating Geometries From RDF Data</link> documentation section.</para>
<para>Then the geo-spatail information will be available and can be queried.</para>
<para>Note: RDF_GEO and associated indexes are created when the database is first created and
thus just needs to be populated with the geometry data in the RDF triples, which is what
the <link linkend="fn_fn_rdf_geo_add"><function>DB.DBA.RDF_GEO_FILL ()</function></link> function does</para>.
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfsparqlgeospatprog">Programmatic Manipulation of Geometries in RDF</link></listitem>
<listitem><link linkend="rdfsparqlgeospatexmp">GEO Spatial Examples</link></listitem>
<listitem>GEO Spatial Tutorials:
<itemizedlist mark="bullet">
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(26)">ROUND</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(27)">DESCRIBE</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(28)">CONSTRUCT</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(29)">ASK</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(30)">UNION</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(31)">COUNT</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(32)">FILTER</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(33)">Find Distance Variant I</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(34)">Find Distance Variant II</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(35)">Querying Time and Space Variant I</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_2/SPARQL_Tutorials_Part_2.html#(36)">Querying Time and Space Variant II</ulink></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</tip>
</sect2>
<sect2 id="virtuosotipsandtricksspchar">
<title>How Can I execute SPARQL queries containing '$' character using ISQL?</title>
<para>Assuming a SPARQL query should filter on the length of labels:</para>
<programlisting><![CDATA[
SELECT ?label
FROM <http://mygraph.com>
WHERE
{
?s ?p ?label
FILTER(regex(str(?label), "^.{1,256}$") )
}
]]></programlisting>
<para>ISQL uses '<emphasis>$</emphasis>' character as a prefix for macro names of its preprocessor.
When '<emphasis>$</emphasis>' character is used in SPARQL query to be executed in ISQL, the character
should be replaced with '<emphasis>$$</emphasis>' notation or an escape char + numeric code:</para>
<programlisting><![CDATA[
SQL> SPARQL
SELECT ?label
FROM <http://mygraph.com>
WHERE
{
?s ?p ?label
FILTER(REGEX(str(?label), "^.{1,256}$$") )
}
]]></programlisting>
<para>Note also that the FILTER written in this way, finds <emphasis>?label-s</emphasis> with length
less than 256.</para>
<para>To achieve fast results, <emphasis>REGEX</emphasis> should be replaced with the
<emphasis>bif:length</emphasis> function:</para>
<programlisting><![CDATA[
SQL> SPARQL
SELECT ?label
FROM <http://mygraph.com>
WHERE
{
?s ?p ?label
FILTER (bif:length(str(?label))<= 256)
}
]]></programlisting>
<para>In this way the SPARQL query execution can work much faster if the interoperability is
not required and <emphasis>?label-s</emphasis> are numerous.</para>
</sect2>
<sect2 id="virtuosotipsandtricksfinddeadlockstables">
<title>How can I find on which table deadlocks occur?</title>
<para>One possible way to find on which table deadlocks occur is to execute the following statement:</para>
<programlisting><![CDATA[
SELECT TOP 10 *
FROM SYS_L_STAT
ORDER BY deadlocks DESC
]]></programlisting>
</sect2>
<sect2 id="virtuosotipsandtricksoutotmemoryerror">
<title>How Can I configure parameters to avoid out of memory error?</title>
<para>In order to avoid out of memory error, you should make sure the values for the paramaters
<emphasis>NumberOfBuffers</emphasis> and <emphasis>MaxCheckpointRemap</emphasis> are not set with the same values.</para>
<para>For example, the following configuration will cause an error out of memory:</para>
<programlisting><![CDATA[
# virtuoso.ini
...
[Parameters]
NumberOfBuffers = 246837
MaxDirtyBuffers = 18517
MaxCheckpointRemap = 246837
...
]]></programlisting>
<para>Changing the value of the parameter <emphasis>MaxCheckpointRemap</emphasis> with let's
say 1/4 of the DB size will resolve the issue.</para>
</sect2>
<sect2 id="virtuosotipsandtricksrdftriggersoptions">
<title>What are "Generate RDB2RDF triggers" and "Enable Data Syncs with Physical Quad Store" Linked Data Views options?</title>
<para>These Linked Data Views options basically persist the triples in the transient View Graph in the Native Quad Store. The Data Sync is how you keep the transient views in sync with the persisted triples.</para>
<para>Without this capability you cannot exploit faceted browsing without severe performance overhead when using Linked Data based conceptual views over ODBC or JDBC accessible data sources.</para>
<para>Note: Using these options when the RFViews have already been created is not currently possible via the Conductor UI. Instead you should be able to add them manually from isql:</para>
<orderedlist>
<listitem>Drop the Linked Data View graph and Quad Map.</listitem>
<listitem>Create it again with the RDB2RDF Triggers options enabled.</listitem>
</orderedlist>
<tip><title>See Also:</title>
<para><link linkend="rdb2rdftriggers">RDB2RDF Triggers</link></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtricksmanagedaterangequery">
<title>How to Manage Date Range SPARQL queries?</title>
<para>The following examples demonstrate how to manage date range in a SPARQL query:</para>
<para><emphasis>Example with date range</emphasis></para>
<programlisting><![CDATA[
SELECT ?s ?date
FROM <http://dbpedia.org>
WHERE
{
?s ?p ?date . FILTER ( ?date >= "19450101"^^xsd:date && ?date <= "19451231"^^xsd:date )
}
LIMIT 100
]]></programlisting>
<para><emphasis>Example with bif:contains</emphasis></para>
<para>Suppose there is the following query using bif:contains for date:</para>
<para>If ?date is of type xsd:date or xsd:dateTime and of valid syntax then
bif:contains(?date, '"1945*"' ) will not found it, because it will be parsed at load/create and
stored as SQL DATE value.
</para>
<para>So if data are all accurate and typed properly then the filter is:</para>
<programlisting><![CDATA[
(?date >= xsd:date("1945-01-01") && ?date < xsd:date("1946-01-01"))
]]></programlisting>
<para>i.e. the query should be:</para>
<programlisting><![CDATA[
SELECT DISTINCT ?s ?date
FROM <http://dbpedia.org>
WHERE
{
?s ?p ?date . FILTER( ?date >= xsd:date("1945-01-01") && ?date < xsd:date("1946-01-01") && (str(?p) != str(rdfs:label)) )
}
LIMIT 10
]]></programlisting>
<para>If data falls, then the free-text will be OK for tiny examples but not for "big" cases because
<emphasis>bif:contains(?date, '"1945*"')</emphasis> would require that less than 200 words in the
table begins with 1945. Still, some data can be of accurate type and syntax so range comparison
should be used for them and results aggregated via UNION.</para>
<para>If dates mention timezones then the application can chose the beginning and the end of the
year in some timezones other than the default.</para>
</sect2>
<sect2 id="virtuosotipsandtricksquadstorageinternally">
<title>How can I see which quad storages exist and in which quad storage a graph resides?</title>
<para>Let's take for example a <ulink url="http://virtuoso.openlinksw.com/whitepapers/relational%20rdf%20views%20mapping.html">created Linked Data View from relational data in Virtuoso</ulink>. The RDF output therefor should have two graphs which reside in a quad storage named for ex.:
</para>
<programlisting><![CDATA[
http://example.com/rdfv_demo/quad_storage/default
]]></programlisting>
<para>Also the RDF is accessible over the SPARQL endpoint with the following query:
</para>
<programlisting><![CDATA[
define input:storage <http://example.com/rdfv_demo/quad_storage/default>
SELECT *
WHERE
{
?s ?p ?o
}
]]></programlisting>
<para>Now one could ask is there a way to define internally (once) that the quad storage should be
included in queries to the SPARQL endpoint? So that the user does not have to define the
<emphasis>input:storage</emphasis> explicitly in each query, like this:</para>
<programlisting><![CDATA[
http://example.com/sparql?query=select * where { ?s ?p ?o }&default-graph-uri=NULL&named-graph-uri=NULL
]]></programlisting>
<para>All metadata about all RDF storages are kept in "system" graph
<http://www.openlinksw.com/schemas/virtrdf#> ( namespace prefix <emphasis>virtrdf:</emphasis> ).
Subjects of type <emphasis>virtrdf:QuadStorage</emphasis> are RDF storages. There are three of them by default:
</para>
<programlisting><![CDATA[
SQL> SPARQL SELECT * FROM virtrdf: WHERE { ?s a virtrdf:QuadStorage };
s
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/schemas/virtrdf#DefaultQuadStorage
http://www.openlinksw.com/schemas/virtrdf#DefaultServiceStorage
http://www.openlinksw.com/schemas/virtrdf#SyncToQuads
3 Rows. -- 3 msec.
]]></programlisting>
<itemizedlist mark="bullet">
<listitem><emphasis>virtrdf:DefaultQuadStorage</emphasis> is what's in use if no input:storage specified.</listitem>
<listitem><emphasis>virtrdf:DefaultServiceStorage</emphasis> will be used for SPARQL federation.</listitem>
<listitem><emphasis>virtrdf:SyncToQuads</emphasis> is to keep the list of Linked Data Views that are translated into RDB2RDF triggers.</listitem>
</itemizedlist>
<para>There are two ways of using the Linked Data View from above in SPARQL endpoint without
<emphasis>define input:storage</emphasis>:</para>
<orderedlist>
<listitem>Create Linked Data View right in <emphasis>virtrdf:DefaultQuadStorage</emphasis> or add the
view in other storage and then copy it from there to <emphasis>virtrdf:DefaultQuadStorage</emphasis>.
<itemizedlist mark="bullet">
<listitem>In any of these two variants, use:
<programlisting><![CDATA[
SPARQL ALTER QUAD STORAGE virtrdf:DefaultQuadStorage . . .
]]></programlisting>
</listitem>
</itemizedlist>
</listitem>
<listitem>Use <emphasis>SYS_SPARQL_HOST</emphasis> table as described
<link linkend="rdfdefaultgraph">here</link> and set <emphasis>SH_DEFINES</emphasis> so it
contains your favorite <emphasis>define input:storage</emphasis>.</listitem>
</orderedlist>
</sect2>
<sect2 id="virtuosotipsandtricksdroprecrdefstrg">
<title>Can I drop and re-create the DefaultQuadStorage?</title>
<para>Currently system metadata consist of three "levels":</para>
<orderedlist>
<listitem><emphasis>QuadMapFormats</emphasis> are used to describe transformations of individual
SQL values (or types of SQL values),</listitem>
<listitem><emphasis>QuadMaps</emphasis> refers to <emphasis>QuadMapFormats</emphasis> (via
<emphasis>QuadMapValues</emphasis>) and describe some "minimal" independent RDB2RDF
transformations,</listitem>
<listitem><emphasis>QuadStorages</emphasis> organizes <emphasis>QuadMaps</emphasis>.</listitem>
</orderedlist>
<para><emphasis>QuadStorages</emphasis> contains only "symlinks" to maps, if you drop a storage
you don't drop all mappings inside. If you drop the <emphasis>DefaultQuadStorage</emphasis> or
some other built-in thing, it can be safely recovered by
<link linkend="fn_rdf_audit_metadata"><function>DB.DBA.RDF_AUDIT_METADATA</function></link>,
with first parameter set to 1. This will keep your own data intact. However we recommend to write
a script that declares all your formats, Linked Data Views and storages, to be able to reproduce the
configuration after any failures.</para>
</sect2>
<sect2 id="virtuosotipsandtricksgraphsecurity">
<title>How to display only some information from RDF graph?</title>
<para>Virtuoso supports graph-level security, as described <link linkend="rdfgraphsecurity">here</link>
but not subject-level or predicate-level. When exposing data that needs protected access, triples
should be confined to private name graphs which are protected by ACLs using WebID.</para>
<para>Note, how you can use <ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSPARQLSecurityWebID">WebID to protect Virtuoso SPARQL endpoints</ulink>.</para>
<tip><title>See Also:</title>
<para><link linkend="rdfgraphsecurity">RDF Graphs Security</link></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtrickssparqlcondport">
<title>Is it possible to have the SPARQL endpoint on a different port than the Conductor?</title>
<para>Virtuoso Web Server has the capability to create extra listeners using the <link linkend="admui.internetdomains">Conductor interface</link>.</para>
<orderedlist>
<listitem>At install time you have your HTTP Server port in your virtuoso.ini set to 8890, which
you want to keep in your local network as this contains ALL the endpoints that you have
registered in Virtuoso. So as long as you do not open this port in your firewall, you can
only get at it from the local machine.</listitem>
<listitem>Next you should create a new vhost entry using the EXTERNAL name of your machine and
use port 80 (or a higher port if you do not want to run as root) for ex.:
<programlisting><![CDATA[
Interface: 0.0.0.0
Port: 8080
Http Host: my.example.com
]]></programlisting>
</listitem>
<listitem>Next you add a "New directory to this line", click on "Type" radio button and choose
"Sparql access point" from the drop-down list and press Next button. Set "Path" to /sparql
and press the "Save Changes" button to store.</listitem>
<listitem>At this point you have created: http://my.example.com:8080/sparql which functions
exactly the same as your internal http://example.com/sparql. You can now open your firewall
and allow outside machines to connect to port 8080 so people can use your SPARQL endpoint
without access to any other endpoint on your Virtuoso installation.</listitem>
<listitem>You should probably also change your virtuoso.ini so:
<programlisting><![CDATA[
[URIQA]
DefaultHost = my.example.com:8080
]]></programlisting>
</listitem>
<listitem>If you use port 80, you do not have to add :80 at the end of this setting, although
it should not make any difference.</listitem>
<listitem>You can now add other directories / endpoints to the new <emphasis>my.example.com</emphasis>
interface you just created e.g. a nice / directory that points to a index.html which describes
your site etc.</listitem>
</orderedlist>
<tip><title>See Also:</title>
<para><link linkend="admui.internetdomains">Internet Domains</link></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtricksenableadonetvs2010">
<title>How to enable the Virtuoso Entity Framework 3.5 ADO.Net Provider in Visual Studio 2010?</title>
<para>The Virtuoso Entity Framework 3.5 ADO.Net Provider is current only list as a Visible control
in the Visual Studio 2008 IDE as the current installers only create the necessary registry
entries for Visual Studio 2008. To make it visible in the Visual Studio 2010's IDE the
following registry settings need to be manually updated and manual addtions to some of
the VS 2010 XML configuration files:</para>
<orderedlist>
<listitem>Export following registry keys to .reg files and using a text editor, such as Wordpad, edit the Visual Studio version numbers from 8.0 or 9.0 to 10.0:
<programlisting><![CDATA[
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\DataProviders\{EE00F82B-C5A4-4073-8FF1-33F815C9801D}
- and -
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\DataSources\{90FBCAF2-8F42-47CD-BF1A-88FF41173060}
]]></programlisting>
</listitem>
<listitem>Once edited, save and double click them to create the new registry entries under:
<programlisting><![CDATA[
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\10.0....
]]></programlisting>
</listitem>
<listitem>In addition, locate the file C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config,
locate the node, then locate the <emphasis><add name="VirtuosoClient3? Data Provider" ...</emphasis>
node within it:
<programlisting><![CDATA[
<add name="VirtuosoClient3 Data Provider" invariant="OpenLink.Data.Virtuoso"
description=".NET Framework Data Provider for Virtuoso" type="OpenLink.Data.Virtuoso.VirtuosoClientFactory, virtado3, Version=6.2.3128.2, Culture=neutral, PublicKeyToken=391bf132017ae989" />
]]></programlisting>
</listitem>
</orderedlist>
<para>and copy is to the equivalent C:\WINDOWS\Microsoft.NET\Frameworks\v4.0.30128\CONFIG\machine.config location.</para>
<para>Visual Studio 2010 will then have the necessary information to locate and load the Virtuoso ADO.Net provider in its IDE.</para>
<para>The registry should typically contain the following entries for Visual Studio 2010 as a result:</para>
<programlisting><![CDATA[
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}]
@=".NET Framework Data Provider for Virtuoso"
"AssociatedSource"="{4D90D7C5-69A6-43EE-83ED-59A0E442D260}"
"CodeBase"="C:\\Windows\\assembly\\GAC_MSIL\\virtado3\\6.2.3128.1__391bf132017ae989\\virtado3.dll"
"Description"="Provider_Description, OpenLink.Data.Virtuoso.DDEX.Net3.DDEXResources, virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
"DisplayName"="Provider_DisplayName, OpenLink.Data.Virtuoso.DDEX.Net3.DDEXResources, virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
"InvariantName"="OpenLink.Data.Virtuoso"
"PlatformVersion"="2.0"
"ShortDisplayName"="Provider_ShortDisplayName, OpenLink.Data.Virtuoso.DDEX.Net3.DDEXResources, virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
"Technology"="{77AB9A9D-78B9-4ba7-91AC-873F5338F1D2}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IDSRefBuilder]
@="Microsoft.VisualStudio.Data.Framework.DSRefBuilder"
"Assembly"="Microsoft.VisualStudio.Data.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataAsyncCommand]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataCommand]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataConnectionProperties]
@="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoDataConnectionProperties"
"Assembly"="virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataConnectionSupport]
@="Microsoft.VisualStudio.Data.Framework.AdoDotNet.AdoDotNetConnectionSupport"
"Assembly"="Microsoft.VisualStudio.Data.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataConnectionUIControl]
@="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoDataConnectionUIControl"
"Assembly"="virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataConnectionUIProperties]
@="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoDataConnectionProperties"
"Assembly"="virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataMappedObjectConverter]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataObjectIdentifierResolver]
@="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoDataObjectIdentifierResolver"
"Assembly"="virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataObjectSupport]
@="Microsoft.VisualStudio.Data.Framework.DataObjectSupport"
"Assembly"="Microsoft.VisualStudio.Data.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
"XmlResource"="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoObjectSupport"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataSourceInformation]
@="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoDataSourceInformation"
"Assembly"="virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataTransaction]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}\SupportedObjects\IVsDataViewSupport]
@="Microsoft.VisualStudio.Data.Framework.DataViewSupport"
"Assembly"="Microsoft.VisualStudio.Data.Framework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
"XmlResource"="OpenLink.Data.Virtuoso.DDEX.Net3.VirtuosoViewSupport"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataSources\{4D90D7C5-69A6-43EE-83ED-59A0E442D260}]
@="OpenLink Virtuoso Data Source"
"DefaultProvider"="{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataSources\{4D90D7C5-69A6-43EE-83ED-59A0E442D260}\SupportingProviders]
[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\10.0\DataSources\{4D90D7C5-69A6-43EE-83ED-59A0E442D260}\SupportingProviders\{0886A2BB-03D0-4E00-8A3D-F235A5DC0F6D}]
"Description"="DataSource_Description, OpenLink.Data.Virtuoso.DDEX.Net3.DDEXResources, virtado3, Version=6.2.3128.1, Culture=neutral, PublicKeyToken=391bf132017ae989"
]]></programlisting>
<para>The next Virtuoso releases, 6.3+ will support this new Visual Studio 2010 release out of the box.</para>
</sect2>
<sect2 id="virtuosotipsandtrickscontrolunicode3">
<title>How Can I Control the normalization of UNICODE3 accented chars in free-text index?</title>
<para>
The normalization of UNICODE3 accented chars in free-text index can be controlled by setting up the
configuration parameter <emphasis>XAnyNormalization</emphasis> in the
virtuoso.ini config file, section [I18N]. This parameter controls whether accented
UNICODE characters should be converted to their non-accented base
variants at the very beginning of free-text indexing or parsing a
free-text query string. The parameter's value is an integer that is bitmask with
only 2 bits in use atm:
</para>
<orderedlist>
<listitem>0: the default behavior, do not normalize anything, so "Jose" and
"José" are two distinct words.
</listitem>
<listitem>2: Any combined char is converted to its (smallest known) base. So
"é" will lose its accent and become plain old ASCII "e".</listitem>
<listitem>3: This is equl to 1|2 and when set then performs both conversions.
As a result, pair of base char and combinig char loses its second char and chars with accents will lose
accents.</listitem>
</orderedlist>
<para>If the parameter is required at all, the needed value is probably 3. So
the fragment of virtuoso.ini is:</para>
<programlisting><![CDATA[
[I18N]
XAnyNormalization=3
]]></programlisting>
<para>In some seldom case the value of 1 can be appropriate. The parameter
should be set once before creating the database. If changed on the
existing database, all free-text indexes that may contain non-ASCII data
should be re-created. On a typical system, the parameter affects all
text columns, XML columns, RDF literals and queries.</para>
<para>Strictly speaking, it affects not all of them but only items that use
default "x-any" language or language derived from x-any such as "en" and
"en-US" but if you haven't tried writing new C plugins for custom
languages you should not look so deep.</para>
<para>As an example, with <emphasis>XAnyNormalization=3</emphasis> once can get the following:</para>
<programlisting><![CDATA[
SQL>SPARQL
INSERT IN <http://InternationalNSMs/>
{ <s> <sp> "Índio João Macapá Júnior Tôrres Luís Araújo José" ;
<ru> "Он добавил картошки, посолил и поставил аквариум на огонь" . }
INSERT INTO <http://InternationalNSMs/>, 2 (or less) triples -- done
SQL> DB.DBA.RDF_OBJ_FT_RULE_ADD (null, null, 'InternationalNSMs.wb');
Done. -- 0 msec.
SQL>vt_inc_index_db_dba_rdf_obj();
Done. -- 26 msec.
SQL>SPARQL
SELECT *
FROM <http://InternationalNSMs/>
WHERE
{
?s ?p ?o
}
ORDER BY ASC (str(?o))
s sp Índio João Macapá Júnior Tôrres Luís Araújo José
s ru Он добавил картошки, посолил и поставил аквариум на огонь
2 Rows. -- 2 msec.
SQL> SPARQL
SELECT *
FROM <http://InternationalNSMs/>
WHERE
{
?s ?p ?o . ?o bif:contains "'Índio João Macapá Júnior Tôrres Luís Araújo José'" .
}
s sp Índio João Macapá Júnior Tôrres Luís Araújo José
1 Rows. -- 2 msec.
SQL>SPARQL
SELECT *
FROM <http://InternationalNSMs/>
WHERE
{
?s ?p ?o . ?o bif:contains "'Indio Joao Macapa Junior Torres Luis Araujo Jose'" . }
s sp Índio João Macapá Júnior Tôrres Luís Araújo José
1 Rows. -- 1 msec.
SQL> SPARQL
SELECT *
FROM <http://InternationalNSMs/>
WHERE
{
?s ?p ?o . ?o bif:contains "'поставил аквариум на огонь'" . }
s ru Он добавил картошки, посолил и поставил аквариум на огонь
]]></programlisting>
<para>There was also request for function that normalizes characters in
strings as free-text engine will do with XAnyNormalization=3 , the function will be provided as a separate patch and depends on this
specific patch.
</para>
<tip><title>See Also:</title>
<para><link linkend="VIRTINI">Virtuoso Configuration File</link></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtricksdefinegraphwithspongeroption">
<title>How Can I define graph with virt:rdf_sponger option set to "on"?</title>
<para>Suppose we have the following scenario:</para>
<orderedlist>
<listitem>Create Virtuoso user using Conductor for ex. with name "john" and pwd 1.</listitem>
<listitem>Create for the user a RDF Sink folder for ex. with name "MySinkFolder" from type
"RDF Upload Folder" or use the <emphasis>rdf_sink</emphasis> folder created automatically
for your user.</listitem>
<listitem>In the properties page of the RDF sink folder add in the WebDAV section this
property <emphasis>virt:rdf_graph</emphasis> with value:
<programlisting><![CDATA[
http://host:port/DAV/home/<user-name>/<rdf-sink-folder>/
-- So in our example it should be:
http://example.com/DAV/home/john/MySinkFolder/
]]></programlisting>
</listitem>
<listitem>Add another property virt:rdf_sponger with value "on".
<figure id="sink1" float="1">
<title></title>
<graphic fileref="ui/sink1.png"/>
</figure>
</listitem>
<listitem>Upload RDF files to the RDF Sink folder "MySinkFolder", for ex. upload file with name
"data.rdf":
<figure id="sink2" float="1">
<title></title>
<graphic fileref="ui/sink2.png"/>
</figure>
</listitem>
<listitem>As result the RDF data should be stored in graph depending on your folder name etc.:
<programlisting><![CDATA[
http:///local.virt/DAV/home/<user-name>/<rdf-sink-folder>/<resource>
-- So in our example it will be:
http:///local.virt/DAV/home/john/MySinkFolder/data.rdf
]]></programlisting>
<orderedlist>
<listitem>Go to http://host:port/sparql ; </listitem>
<listitem>Execute simple query to view the graph triples:
<programlisting><![CDATA[
SELECT *
FROM <http://local.virt/DAV/home/john/MySinkFolder/data.rdf>
WHERE
{
?s ?p ?o
}
]]></programlisting>
<figure id="sink3" float="1">
<title></title>
<graphic fileref="ui/sink3.png"/>
</figure>
<figure id="sink4" float="1">
<title></title>
<graphic fileref="ui/sink4.png"/>
</figure>
</listitem>
</orderedlist>
</listitem>
<listitem>In order to define any graph you want with the options from above, you should execute:
<programlisting><![CDATA[
SQL> DAV_PROP_SET ('/DAV/home/<user-name>/<rdf-sink-folder>/', 'virt:rdf_graph', iri, <user-name>, <password>);
-- So in our example it should be:
SQL> DAV_PROP_SET ('/DAV/home/john/MySinkFolder/', 'virt:rdf_graph', 'http://mydata.com', 'john', '1');
]]></programlisting>
<itemizedlist mark="bullet">
<listitem>Note: calling this function uses the given IRI as the graph IRI when sponging
stuff put in <your-rdf-sink-folder>.</listitem>
</itemizedlist>
</listitem>
<listitem>Finally you should execute the following command to get the RDF data from the new graph:
<programlisting><![CDATA[
SQL> SELECT DAV_PROP_GET ('/DAV/home/<user-name>/<your-rdf-sink-folder>/', 'virt:rdf_graph',<user-name>, <password>);
-- So in our example it should be:
SQL> SELECT DAV_PROP_GET ('/DAV/home/john/MySinkFolder/', 'virt:rdf_graph','john', '1');
Query result:
DAV_PROP_GET
http://example.com/DAV/home/john/MySinkFolder/
No. of rows in result: 1
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="virtuosotipsandtricksconvprstr">
<title>How do I use SPARUL to change a selection of property values from URI References to Literals?</title>
<para>Assume a given graph where triples are comprised of property values that are mixed across URI References and Typed Literals as exemplified by the results of the query below:</para>
<programlisting><![CDATA[
SELECT DISTINCT ?sa ?oa
FROM <http://ucb.com/nbeabase>
WHERE
{
?sa a <http://ucb.com/nbeabase/resource/Batch> .
?sa <http://ucb.com/nbeabase/resource/chemAbsNo> ?oa . FILTER regex(?oa, '-','i')
}
]]></programlisting>
<para>You can use the following SPARUL pattern to harmonize the property values across relevant triples in a specific graph, as shown below:</para>
<programlisting><![CDATA[
SQL> SPARQL
INSERT INTO GRAPH <http://ucb.com/nbeabase>
{
?sa <http://ucb.com/nbeabase/resource/sampleId> `str (?oa)`
}
WHERE
{
?sa <http://ucb.com/nbeabase/resource/chemAbsNo> ?oa . FILTER regex(?oa, '-','i')
}
]]></programlisting>
</sect2>
<sect2 id="virtuosotipsandtricksbulkloadcl">
<title>How is a Checkpoint performed against a Virtuoso Clustered Server?</title>
<para>The cluster <link linkend="fn_cl_exec">cl_exec()</link> function is
used to perform a checkpoint across all node of a Virtuoso cluster as follows:</para>
<programlisting><![CDATA[
SQL>cl_exec ('checkpoint');
]]></programlisting>
<para>This typically needs to be run after loading RDF datasets into a Virtuoso cluster to prevent lose of data when the cluster is restarted.</para>
</sect2>
<sect2 id="virtuosotipsandtrickconstrprst">
<title>How can I use CONSTRUCT with PreparedStatements?</title>
<para>Assume a given query which uses pragma <emphasis>output:format '_JAVA_'</emphasis> with CONSTRUCT:</para>
<programlisting><![CDATA[
SPARQL DEFINE output:format '_JAVA_'
CONSTRUCT { ?s ?p ?o }
WHERE
{
?s ?p ?o .
FILTER (?s = iri(?::0))
}
LIMIT 1
]]></programlisting>
<para>In order to work correctly, the query should be modified to:</para>
<programlisting><![CDATA[
SPARQL DEFINE output:format '_JAVA_'
CONSTRUCT { `iri(?::0)` ?p ?o }
WHERE
{
`iri(?::0)` ?p ?o
}
LIMIT 1
]]></programlisting>
<para>Equivalent variant of the query is also:</para>
<programlisting><![CDATA[
SPARQL DEFINE output:format '_JAVA_'
CONSTRUCT { ?s ?p ?o }
WHERE
{
?s ?p ?o .
FILTER (?s = iri(?::0))
}
LIMIT 1
]]></programlisting>
</sect2>
<sect2 id="virtuosotipsandtrickssparulupdatestrl">
<title>How can perform SPARQL Updates without transactional log size getting exceed?</title>
<para>Since SPARUL updates are generally not meant to be transactional, it is best to run these in:</para>
<programlisting><![CDATA[
SQL> log_enable (2);
]]></programlisting>
<para>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>Alternatively, the "<emphasis>TransactionAfterImageLimit</emphasis>" parameter can be set
in the virtuoso.ini config file to a higher value than its 50MB default:</para>
<programlisting><![CDATA[
#virtuoso.ini
...
[Parameters]
...
TransactionAfterImageLimit = N bytes default 50000000
...
]]></programlisting>
<tip><title>See Also:</title>
<para><link linkend="rdfperfsparul">Using SPARUL</link></para>
<para><link linkend="ini_Parameters">Virtuoso INI Parameters</link></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtrickscrawlercustompl">
<title>How can I write custom crawler using PL?</title>
<para>The following code is an example of loading data via crawler with special function to generate link for downloading:</para>
<programlisting><![CDATA[
create procedure EUROPEANA_STORE (
in _host varchar,
in _url varchar,
in _root varchar,
inout _content varchar,
in _s_etag varchar,
in _c_type varchar,
in store_flag int := 1,
in udata any := null,
in lev int := 0)
{
declare url varchar;
declare xt, xp any;
declare old_mode int;
xt := xtree_doc (_content, 2);
xp := xpath_eval ('//table//tr/td/a[@href]/text()', xt, 0);
commit work;
old_mode := log_enable (3,1);
foreach (any u in xp) do
{
u := cast (u as varchar);
url := sprintf ('http://semanticweb.cs.vu.nl/europeana/api/export_graph?graph=%U&mimetype=default&format=turtle', u);
dbg_printf ('%s', u);
{
declare continue handler for sqlstate '*' {
dbg_printf ('ERROR: %s', __SQL_MESSAGE);
};
SPARQL LOAD ?:url into GRAPH ?:u;
}
}
log_enable (old_mode, 1);
return WS.WS.LOCAL_STORE (_host, _url, _root, _content, _s_etag, _c_type, store_flag, 0);
}
]]></programlisting>
<tip><title>See Also:</title>
<para><link linkend="contentcrawlerrdf">Set Up the Content Crawler to Gather RDF</link></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtrickscrawlercustomde">
<title>How Can I Get an exact mapping for a date?</title>
<para>Assume a given attempts to get an exact mapping for the literal "1950" using
<emphasis>bif:contains</emphasis>:</para>
<programlisting><![CDATA[
SPARQL
SELECT DISTINCT ?s ?o
FROM <http://dbpedia.org>
WHERE
{
?s ?p ?o .
FILTER( bif:contains (?o, '"1950"')
&& isLiteral(?o)
&& ( str(?p) ! = rdfs:label || str(?p) != foaf:name
&& ( ?o='1950')
)
}
]]></programlisting>
<para>As an integer 1950 or date 1950-01-01 are not texts, they are not in free-text index
and thus invisible for CONTAINS free-text predicate.</para>
<para>A possible way to make them visible that way is to introduce an additional RDF predicate
that will contain objects of the triples in question, converted to strings via str() function.</para>
<para>Thus better results will be approached: if searches about dates are frequent then a new
predicate can have date/datetime values extracted from texts, eliminating the need for bif:contains.</para>
<para>Therefor, the query from above should be changed to:</para>
<programlisting><![CDATA[
SPARQL
SELECT DISTINCT ?s ?o
FROM <http://dbpedia.org>
WHERE
{
?s ?p ?o .
FILTER ( isLiteral(?o)
&& ( str(?p) != str(rdfs:label) || str(?p) != foaf:name )
&& str(?o) in ("1950", "1950-01-01"))
}
]]></programlisting>
</sect2>
<sect2 id="virtuosotipsandtricksgetcertattr">
<title>How Can I Get certificate attributes using SPARQL?</title>
<para>The SPARQL query should use the <emphasis>cert:hex</emphasis> and
<emphasis>cert:decimal</emphasis> in order to get to the values, so for ex:</para>
<programlisting><![CDATA[
PREFIX cert: <http://www.w3.org/ns/auth/cert#>
PREFIX rsa: <http://www.w3.org/ns/auth/rsa#>
SELECT ?webid
FROM <http://webid.myxwiki.org/xwiki/bin/view/XWiki/homepw4>
WHERE
{
[] cert:identity ?webid ;
rsa:modulus ?m ;
rsa:public_exponent ?e .
?m cert:hex "b520f38479f5803a7ab33233155eeef8ad4e1f575b603f7780f3f60ceab1\n34618fbe117539109c015c5f959b497e67c1a3b2c96e5f098bb0bf2a6597\n779d26f55fe8d320de7af0562fd2cd067dbc9d775b22fc06e63422717d00\na6801dedafd7b54a93c3f4e59538475673972e524f4ec2a3667d0e1ac856\nd532e32bf30cef8c1adc41718920568fbe9f793daeeaeeaa7e8367b7228a\n895a6cf94545a6f6286693277a1bc7750425ce6c35d570e89453117b88ce\n24206afd216a705ad08b7c59\n"^^xsd:string .
?e cert:decimal "65537"^^xsd:string
}
]]></programlisting>
</sect2>
<sect2 id="virtuosotipsandtricksmultithreadjdbc">
<title>How can I make Multi Thread Virtuoso connection using JDBC?</title>
<para>See details <link linkend="JDBCDriverhibernatesetupandtestingexmp4">here</link>.</para>
</sect2>
<sect2 id="virtuosotipsandtricksgetcertattr">
<title>How Do I Perform Bulk Loading of RDF Source Files into one or more Graph IRIs?</title>
<para>See details <ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtBulkRDFLoader">here</ulink>.</para>
</sect2>
<sect2 id="virtuosotipsandtricksrdfschowlinfrl">
<title>How to exploit RDF Schema and OWL Inference Rules with minimal effort?</title>
<para>When you install Virtuoso, it's reasoner and highly scalable inference capabilities may not
be obvious. Typical cases involve using <emphasis>rdfs:subClassOf</emphasis> predicates in queries
and wondering why reasoning hasn't occurred in line with the semantics defined in RDF Schema.</para>
<para>The experience applies when using more sophisticated predicates from OWL such as
<emphasis>owl:equivalentProperty</emphasis>, <emphasis>owl:equivalentClass</emphasis>,
<emphasis>owl:sameAs</emphasis>, <emphasis>owl:SymmetricalProperty</emphasis>,
<emphasis>owl:inverseOf</emphasis> etc ...</para>
<para>Virtuoso implemented inference rules processing in a loosely coupled manner that allow
users to conditionally apply inference context (via rules) to SPARQL queries. Typically, you
have to create these rules following steps outlined <link linkend="rdfsparqlrule">here</link>.</para>
<para>This tips and tricks note provides a shortcut for setting up and exploring RDF Schema and
OWL reasoning once you've installed the <ulink url="http://s3.amazonaws.com/opldownload/uda/vad-packages/6.1/virtuoso/fct_dav.vad">Virtuoso Faceted Browser VAD package</ulink>.</para>
<tip><title>See Also:</title>
<para><link linkend="rdfsparqlrule">Inference Rules and Reasoning</link></para>
<para><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtFacetBrowserInstallConfig">Virtuoso Faceted Browser Installation and configuration</ulink></para>
<para><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtuosoFacetsWebService">Virtuoso Faceted Web Service</ulink></para>
</tip>
</sect2>
<sect2 id="virtuosotipsandtricksdumparbqntr">
<title>How can I dump arbitrary query result as N-Triples?</title>
<para>Assume the following arbitrary query:</para>
<programlisting><![CDATA[
SPARQL define output:format "NT"
CONSTRUCT { ?s a ?t }
FROM virtrdf:
WHERE { ?s a ?t };
]]></programlisting>
<para>For iteration over result-set of an arbitrary query, use
<link linkend="fn_exec_next"><function>exec_next()</function></link> in a loop that begins with
<link linkend="fn_exec"><function>exec()</function></link> with cursor output variable as
an argument and ends with <link linkend="fn_exec_close"><function>exec_close()</function></link>
after it is out of data.</para>
</sect2>
<sect2 id="virtuosotipsandtrickbindnmgrprst">
<title>How do I bind named graph parameter in prepared statement?</title>
<para>Assume the following SPARQL query:</para>
<programlisting><![CDATA[
CONSTRUCT
{
?s ?p ?o
}
FROM ?context
WHERE
{
?s ?p ?o
}
]]></programlisting>
<para>To bind the named graph context of the query from above, the best solution due
to performance implications, is to change the syntax of the query as:</para>
<programlisting><![CDATA[
CONSTRUCT
{
?s ?p ?o
}
WHERE
{
graph `iri(??)` { ?s ?p ?o }
}
]]></programlisting>
<para>Note: In case of using "FROM clause", it needs a constant in order to check at the
compile time whether the IRI refers to a graph or a graph group:</para>
<itemizedlist mark="bullet">
<listitem>Assume "FROM clause" is used as for ex:
<programlisting><![CDATA[
CONSTRUCT
{
?s ?p ?o
}
FROM `iri(??)`
WHERE
{
?s ?p ?o
}
]]></programlisting>
<itemizedlist mark="bullet">
<listitem>In this case can be made security checks at
the compile time (i.e., once) and not waste time at the run time.</listitem>
</itemizedlist>
</listitem>
<listitem>Assume "FROM clause" is used as for ex:
<programlisting><![CDATA[
CONSTRUCT
{
?s ?p ?o
}
FROM iri(??)
WHERE
{
?s ?p ?o
}
]]></programlisting>
<itemizedlist mark="bullet">
<listitem>In this case a compile-time check, a run-time check or 50/50 mix of them can
be performed, depending on the security policies.</listitem>
</itemizedlist>
</listitem>
<listitem>FROM without constant would mean that security rules, if they present in the storage,
are used at the run time, for every triple that matches every triple pattern in the default graph.
This issue can be reproduced if FROM is not specified at all: if security differs from default
then the effect is noticeably bad.</listitem>
</itemizedlist>
</sect2>
<sect2 id="virtuosotipsandtricksadonetinsb">
<title>How can I insert binary data to Virtuoso RDF storage in plain queries and with parameter binding via ADO.NET calls?</title>
<para>The following example shows different methods for insert binary data to Virtuoso RDF storage in plain queries and with parameter binding via ADO.NET calls:</para>
<programlisting><![CDATA[
# Test_Bin.cs
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Data;
using OpenLink.Data.Virtuoso;
#if ODBC_CLIENT
namespace OpenLink.Data.VirtuosoOdbcClient
#elif CLIENT
namespace OpenLink.Data.VirtuosoClient
#else
namespace OpenLink.Data.VirtuosoTest
#endif
{
class Test_Bin
{
[STAThread]
static void Main(string[] args)
{
IDataReader myread = null;
IDbConnection c;
c = new VirtuosoConnection("HOST=localhost:1111;UID=dba;PWD=dba;");
IDbCommand cmd = c.CreateCommand();
int ros;
try
{
c.Open();
cmd.CommandText = "sparql clear graph <ado.bin>";
cmd.ExecuteNonQuery();
//insert binary as base64Binary
cmd.CommandText = "sparql insert into graph <ado.bin> { <res1> <attr> \"GpM7\"^^<http://www.w3.org/2001/XMLSchema#base64Binary> }";
cmd.ExecuteNonQuery();
//insert binary as hexBinary
cmd.CommandText = "sparql insert into graph <ado.bin> { <res2> <attr> \"0FB7\"^^<http://www.w3.org/2001/XMLSchema#hexBinary> }";
cmd.ExecuteNonQuery();
//prepare for insert with parameter binding
cmd.CommandText = "sparql define output:format '_JAVA_' insert into graph <ado.bin> { `iri($?)` <attr> `bif:__rdf_long_from_batch_params($?,$?,$?)` }";
//bind parameters for insert binary as base64Binary
IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = "p1";
param.DbType = DbType.AnsiString;
param.Value = "res3";
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p2";
param.DbType = DbType.Int32;
param.Value = 4;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p3";
param.DbType = DbType.AnsiString;
param.Value = "GpM7";
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p4";
param.DbType = DbType.AnsiString;
param.Value = "http://www.w3.org/2001/XMLSchema#base64Binary";
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
//bind parameters for insert binary as hexBinary
param = cmd.CreateParameter();
param.ParameterName = "p1";
param.DbType = DbType.AnsiString;
param.Value = "res4";
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p2";
param.DbType = DbType.Int32;
param.Value = 4;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p3";
param.DbType = DbType.AnsiString;
param.Value = "0FB7";
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p4";
param.DbType = DbType.AnsiString;
param.Value = "http://www.w3.org/2001/XMLSchema#hexBinary";
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
//bind parameters for insert binary as byte[]
param = cmd.CreateParameter();
param.ParameterName = "p1";
param.DbType = DbType.AnsiString;
param.Value = "res5";
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p2";
param.DbType = DbType.Int32;
param.Value = 3;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p3";
param.DbType = DbType.Binary;
byte[] bin_val = {0x01, 0x02, 0x03, 0x04, 0x05};
param.Value = bin_val;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p4";
param.DbType = DbType.AnsiString;
param.Value = System.DBNull.Value;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
//execute select and check the results
cmd.CommandText = "sparql SELECT ?s ?o FROM <ado.bin> WHERE {?s ?p ?o}"; ;
myread = cmd.ExecuteReader();
int r = 0;
while (myread.Read())
{
Console.WriteLine("=== ROW === "+r);
for (int i = 0; i < myread.FieldCount; i++)
{
string s;
if (myread.IsDBNull(i))
Console.Write("N/A|\n");
else
{
object o = myread.GetValue(i);
Type t = myread.GetFieldType(i);
s = myread.GetString(i);
Console.Write(s + "[");
if (o is SqlExtendedString)
{
SqlExtendedString se = (SqlExtendedString)o;
Console.Write("IriType=" + se.IriType + ";StrType=" + se.StrType + ";Value=" + se.ToString());
Console.Write(";ObjectType=" + o.GetType() + "]|\n");
}
else if (o is SqlRdfBox)
{
SqlRdfBox se = (SqlRdfBox)o;
Console.Write("Lang=" + se.StrLang + ";Type=" + se.StrType + ";Value=" + se.Value);
Console.Write(";ObjectType=" + o.GetType() + "]|\n");
object v = se.Value;
if (v is System.Byte[])
{
byte[] vb = (byte[])v;
for (int z = 0; z < vb.Length; z++)
{
Console.WriteLine(""+z+"="+vb[z]);
}
}
}
else
Console.Write(o.GetType() + "]|\n");
}
}
r++;
}
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
finally
{
// if (myread != null)
// myread.Close();
if (c.State == ConnectionState.Open)
c.Close();
}
}
}
}
]]></programlisting>
<para>Output log for example is in the log.txt:</para>
<programlisting><![CDATA[
# log.txt
=== ROW === 0
res1[IriType=IRI;StrType=IRI;Value=res1;ObjectType=OpenLink.Data.Virtuoso.SqlExtendedString]|
GpM7[Lang=;Type=http://www.w3.org/2001/XMLSchema#base64Binary;Value=GpM7;ObjectType=OpenLink.Data.Virtuoso.SqlRdfBox]|
=== ROW === 1
res2[IriType=IRI;StrType=IRI;Value=res2;ObjectType=OpenLink.Data.Virtuoso.SqlExtendedString]|
0FB7[Lang=;Type=http://www.w3.org/2001/XMLSchema#hexBinary;Value=0FB7;ObjectType=OpenLink.Data.Virtuoso.SqlRdfBox]|
=== ROW === 2
res3[IriType=IRI;StrType=IRI;Value=res3;ObjectType=OpenLink.Data.Virtuoso.SqlExtendedString]|
GpM7[Lang=;Type=http://www.w3.org/2001/XMLSchema#base64Binary;Value=GpM7;ObjectType=OpenLink.Data.Virtuoso.SqlRdfBox]|
=== ROW === 3
res4[IriType=IRI;StrType=IRI;Value=res4;ObjectType=OpenLink.Data.Virtuoso.SqlExtendedString]|
0FB7[Lang=;Type=http://www.w3.org/2001/XMLSchema#hexBinary;Value=0FB7;ObjectType=OpenLink.Data.Virtuoso.SqlRdfBox]|
=== ROW === 4
res5[IriType=IRI;StrType=IRI;Value=res5;ObjectType=OpenLink.Data.Virtuoso.SqlExtendedString]|
0102030405[System.Byte[]]|
]]></programlisting>
</sect2>
<sect2 id="instrdfvs">
<title>How can I insert RDF data from Visual Studio to Virtuoso?</title>
<para>The following example shows how to insert RDF Data from Visual Studio to Virtuoso:</para>
<programlisting><![CDATA[
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Data;
using OpenLink.Data.Virtuoso;
#if ODBC_CLIENT
namespace OpenLink.Data.VirtuosoOdbcClient
#elif CLIENT
namespace OpenLink.Data.VirtuosoClient
#else
namespace OpenLink.Data.VirtuosoTest
#endif
{
class Test_Insert
{
[STAThread]
static void Main(string[] args)
{
IDataReader myread = null;
IDbConnection c;
c = new VirtuosoConnection("HOST=localhost:1111;UID=dba;PWD=dba;Charset=UTF-8");
IDbCommand cmd = c.CreateCommand();
int ros;
try
{
c.Open();
cmd.CommandText = "sparql clear graph <ado.net>";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P01> \"131\"^^<http://www.w3.org/2001/XMLSchema#short> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P02> \"1234\"^^<http://www.w3.org/2001/XMLSchema#integer> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P03> \"12345.12\"^^<http://www.w3.org/2001/XMLSchema#float> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P04> \"123456.12\"^^<http://www.w3.org/2001/XMLSchema#double> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P05> \"123456.12\"^^<http://www.w3.org/2001/XMLSchema#decimal> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P06> \"01020304\"^^<http://www.w3.org/2001/XMLSchema#hexBinary> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P07> \"01.20.1980T04:51:13\"^^<http://www.w3.org/2001/XMLSchema#dateTime> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P08> \"01.20.1980\"^^<http://www.w3.org/2001/XMLSchema#date> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P09> \"01:20:19\"^^<http://www.w3.org/2001/XMLSchema#time> }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql insert into graph <ado.net> { <a> <P10> \"test\" }";
cmd.ExecuteNonQuery();
cmd.CommandText = "sparql define output:format '_JAVA_' insert into graph <ado.net> { <b> `iri($?)` `bif:__rdf_long_from_batch_params($?,$?,$?)` }";
//add Object URI
add_triple(cmd, "S01", 1, "test1", null);
//add Object BNode
add_triple(cmd, "S02", 1, "_:test2", null);
//add Literal
add_triple(cmd, "S03", 3, "test3", null);
//add Literal with Datatype
add_triple(cmd, "S04", 4, "1234", "http://www.w3.org/2001/XMLSchema#integer");
//add Literal with Lang
add_triple(cmd, "S05", 5, "test5", "en");
add_triple(cmd, "S06", 3, (short)123, null);
add_triple(cmd, "S07", 3, 1234, null);
add_triple(cmd, "S08", 3, (float)12345.12, null);
add_triple(cmd, "S09", 3, 123456.12, null);
add_triple(cmd, "S10", 3, new DateTime(2001, 02, 23, 13, 44, 51, 234), null);
add_triple(cmd, "S11", 3, new DateTime(2001, 02, 24), null);
add_triple(cmd, "S12", 3, new TimeSpan(19, 41, 23), null);
add_triple(cmd, "S13", 4, "GpM7", "http://www.w3.org/2001/XMLSchema#base64Binary");
add_triple(cmd, "S14", 4, "0FB7", "http://www.w3.org/2001/XMLSchema#hexBinary");
byte[] bin_val = { 0x01, 0x02, 0x03, 0x04, 0x05 };
add_triple(cmd, "S15", 3, bin_val, null);
}
catch (Exception e)
{
Console.WriteLine("{0} Exception caught.", e);
}
finally
{
if (c.State == ConnectionState.Open)
c.Close();
}
}
static void add_triple(IDbCommand cmd, string sub, int ptype, object val, string val_add)
{
cmd.Parameters.Clear();
IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = "p1";
param.DbType = DbType.AnsiString;
param.Value = sub;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p2";
param.DbType = DbType.Int32;
param.Value = ptype;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p3";
if (val != null && val.GetType() == typeof (System.String))
param.DbType = DbType.AnsiString;
param.Value = val;
cmd.Parameters.Add(param);
param = cmd.CreateParameter();
param.ParameterName = "p4";
param.DbType = DbType.AnsiString;
param.Value = val_add;
cmd.Parameters.Add(param);
cmd.ExecuteNonQuery();
}
}
}
]]></programlisting>
<tip><title>See Also:</title>
<para><link linkend="rdfinsertmethods">RDF Insert Methods in Virtuoso</link></para>
</tip>
</sect2>
<sect2 id="descrmd">
<title>How does default describe mode work?</title>
<para>The default describe mode works only if subject has a type/class. To get any anonymous subject described CBD mode should be used:</para>
<programlisting><![CDATA[
$ curl -i -L -H "Accept: application/rdf+xml" http://lod.openlinksw.com/describe/?url=http%3A%2F%2Fwww.mpii.de%2Fyago%2Fresource%2FEddie%255FMurphy
HTTP/1.1 303 See Other
Date: Mon, 21 Mar 2011 14:24:36 GMT
Server: Virtuoso/06.02.3129 (Linux) x86_64-generic-linux-glibc25-64 VDB
Content-Type: text/html; charset=UTF-8
Accept-Ranges: bytes
TCN: choice
Vary: negotiate,accept,Accept-Encoding
Location: http://lod.openlinksw.com/sparql?query=%20DESCRIBE%20%3Chttp%3A%2F%2Fwww.mpii.de%2Fyago%2Fresource%2FEddie%255FMurphy%3E&format=application%
2Frdf%2Bxml
Content-Length: 0
HTTP/1.1 200 OK
Date: Mon, 21 Mar 2011 14:24:37 GMT
Server: Virtuoso/06.02.3129 (Linux) x86_64-generic-linux-glibc25-64 VDB
Accept-Ranges: bytes
Content-Type: application/rdf+xml; charset=UTF-8
Content-Length: 467967
<?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.mpii.de/yago/resource/MTV%5FMovie%5FAward%5Ffor%5FBest%5FComedic%5FPerformance"><n0pred:hasInternalWikipediaLinkTo xmlns:n0pred="http://www.mpii.de/yago/resource/" rdf:resource="http://www.mpii.de/yago/resource/Eddie%5FMurphy"/></rdf:Description>
<rdf:Description rdf:about="http://www.mpii.de/yago/resource/#fact_23536547421"><rdf:subject rdf:resource="http://www.mpii.de/yago/resource/Eddie%5FMurphy"/></rdf:Description>
<rdf:Description rdf:about="http://www.mpii.de/yago/resource/#fact_23536896725"><rdf:object rdf:resource="http://www.mpii.de/yago/resource/Eddie%5FMurphy"/></rdf:Description>
...
]]></programlisting>
</sect2>
<sect2 id="notresphttp">
<title>What should I do if the Virtuoso Server is not responding to HTTP requests?</title>
<para>Assume the Virtuoso server is not responding to HTTP requests although SQL connection is working. In order to determine what activity is being performed that might account for this:</para>
<orderedlist>
<listitem>Check the status:
<programlisting><![CDATA[
SQL> status('');
REPORT
VARCHAR
_______________________________________________________________________________
OpenLink Virtuoso VDB Server
Version 06.02.3129-pthreads for Linux as of Mar 16 2011
Registered to Uriburner (Personal Edition, unlimited connections)
Started on: 2011/03/17 10:49 GMT+60
Database Status:
File size 0, 37598208 pages, 7313125 free.
1000000 buffers, 993399 used, 76771 dirty 0 wired down, repl age 25548714 0 w. io 0 w/crsr.
Disk Usage: 2642884 reads avg 4 msec, 30% r 0% w last 1389 s, 1557572 writes,
15331 read ahead, batch = 79. Autocompact 308508 in 219226 out, 28% saved.
Gate: 71130 2nd in reads, 0 gate write waits, 0 in while read 0 busy scrap.
Log = virtuoso.trx, 14922248 bytes
VDB: 0 exec 0 fetch 0 transact 0 error
1757362 pages have been changed since last backup (in checkpoint state)
Current backup timestamp: 0x0000-0x00-0x00
Last backup date: unknown
Clients: 5 connects, max 2 concurrent
RPC: 116 calls, -1 pending, 1 max until now, 0 queued, 2 burst reads (1%), 0 second brk=9521074176
Checkpoint Remap 331113 pages, 0 mapped back. 1180 s atomic time.
DB master 37598208 total 7313125 free 331113 remap 40593 mapped back
temp 569856 total 569851 free
Lock Status: 52 deadlocks of which 0 2r1w, 86078 waits,
Currently 1 threads running 0 threads waiting 0 threads in vdb.
Pending:
25 Rows. -- 1274 msec.
SQL>
]]></programlisting>
</listitem>
<listitem>Connect with the PL debugger and see what is running currently using the info threads call:
<programlisting><![CDATA[
$ isql 1111 dba <password> -D
DEBUG> info threads
]]></programlisting>
</listitem>
<listitem>This should return the current code being executed by the Sever.</listitem>
<listitem>Run <link linkend="fn_txn_killall"><function>txn_killall()</function></link> to kill any pending transactions which may enable the server to start responding to HTTP requests again:
<programlisting><![CDATA[
SQL> txn_killall();
Done. -- 866 msec.
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="cxmlurlptrn">
<title>What CXML params are supported for the SPARQL URL pattern?</title>
<para>The following options are supported for CXML link behavior in the SPARQL URL Pattern:</para>
<orderedlist>
<listitem>Local faceted navigation links:
<programlisting><![CDATA[
# CXML_redir_for_subjs=&CXML_redir_for_hrefs=&:
http://lod.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=SELECT+DISTINCT+%3Fcafe+%3Flat+%3Flong+%3Fcafename+%3Fchurchname++%28+bif%3Around%28bif%3Ast_distance+%28%3Fchurchgeo%2C+%3Fcafegeo%29%29+%29++WHERE++{++++%3Fchurch+a+lgv%3Aplace_of_worship+.++++%3Fchurch+geo%3Ageometry+%3Fchurchgeo+.++++%3Fchurch+lgv%3Aname+%3Fchurchname+.++++%3Fcafe+a+lgv%3Acafe+.++++%3Fcafe+lgv%3Aname+%3Fcafename+.++++%3Fcafe+geo%3Ageometry+%3Fcafegeo+.++++%3Fcafe+geo%3Alat+%3Flat+.++++%3Fcafe+geo%3Along+%3Flong+.++++FILTER+%28+bif%3Ast_intersects+%28%3Fchurchgeo%2C+bif%3Ast_point+%282.3498%2C48.853%29%2C5%29++%26%26+bif%3Ast_intersects+%28%3Fcafegeo%2C+%3Fchurchgeo%2C+0.2%29+%29+}+LIMIT+50&debug=on&timeout=&format=text%2Fhtml&CXML_redir_for_subjs=&CXML_redir_for_hrefs=&save=display&fname=
]]></programlisting>
</listitem>
<listitem>External Resource Links:
<programlisting><![CDATA[
# CXML_redir_for_subjs=&CXML_redir_for_hrefs=121:
http://lod.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=SELECT+DISTINCT+%3Fcafe+%3Flat+%3Flong+%3Fcafename+%3Fchurchname++%28+bif%3Around%28bif%3Ast_distance+%28%3Fchurchgeo%2C+%3Fcafegeo%29%29+%29++WHERE++{++++%3Fchurch+a+lgv%3Aplace_of_worship+.++++%3Fchurch+geo%3Ageometry+%3Fchurchgeo+.++++%3Fchurch+lgv%3Aname+%3Fchurchname+.++++%3Fcafe+a+lgv%3Acafe+.++++%3Fcafe+lgv%3Aname+%3Fcafename+.++++%3Fcafe+geo%3Ageometry+%3Fcafegeo+.++++%3Fcafe+geo%3Alat+%3Flat+.++++%3Fcafe+geo%3Along+%3Flong+.++++FILTER+%28+bif%3Ast_intersects+%28%3Fchurchgeo%2C+bif%3Ast_point+%282.3498%2C48.853%29%2C5%29++%26%26+bif%3Ast_intersects+%28%3Fcafegeo%2C+%3Fchurchgeo%2C+0.2%29+%29+}+LIMIT+50&debug=on&timeout=&format=text%2Fhtml&CXML_redir_for_subjs=&CXML_redir_for_hrefs=121&save=display&fname=
]]></programlisting>
</listitem>
<listitem>External faceted navigation links:
<programlisting><![CDATA[
# CXML_redir_for_subjs=&CXML_redir_for_hrefs=LOCAL_PIVOT:
http://lod.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=SELECT+DISTINCT+%3Fcafe+%3Flat+%3Flong+%3Fcafename+%3Fchurchname++%28+bif%3Around%28bif%3Ast_distance+%28%3Fchurchgeo%2C+%3Fcafegeo%29%29+%29++WHERE++{++++%3Fchurch+a+lgv%3Aplace_of_worship+.++++%3Fchurch+geo%3Ageometry+%3Fchurchgeo+.++++%3Fchurch+lgv%3Aname+%3Fchurchname+.++++%3Fcafe+a+lgv%3Acafe+.++++%3Fcafe+lgv%3Aname+%3Fcafename+.++++%3Fcafe+geo%3Ageometry+%3Fcafegeo+.++++%3Fcafe+geo%3Alat+%3Flat+.++++%3Fcafe+geo%3Along+%3Flong+.++++FILTER+%28+bif%3Ast_intersects+%28%3Fchurchgeo%2C+bif%3Ast_point+%282.3498%2C48.853%29%2C5%29++%26%26+bif%3Ast_intersects+%28%3Fcafegeo%2C+%3Fchurchgeo%2C+0.2%29+%29+}+LIMIT+50&debug=on&timeout=&format=text%2Fhtml&CXML_redir_for_subjs=&CXML_redir_for_hrefs=LOCAL_PIVOT&save=display&fname=
]]></programlisting>
</listitem>
<listitem>External description resource(TTL):
<programlisting><![CDATA[
# CXML_redir_for_subjs=&CXML_redir_for_hrefs=LOCAL_TTL:
http://lod.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=SELECT+DISTINCT+%3Fcafe+%3Flat+%3Flong+%3Fcafename+%3Fchurchname++%28+bif%3Around%28bif%3Ast_distance+%28%3Fchurchgeo%2C+%3Fcafegeo%29%29+%29++WHERE++{++++%3Fchurch+a+lgv%3Aplace_of_worship+.++++%3Fchurch+geo%3Ageometry+%3Fchurchgeo+.++++%3Fchurch+lgv%3Aname+%3Fchurchname+.++++%3Fcafe+a+lgv%3Acafe+.++++%3Fcafe+lgv%3Aname+%3Fcafename+.++++%3Fcafe+geo%3Ageometry+%3Fcafegeo+.++++%3Fcafe+geo%3Alat+%3Flat+.++++%3Fcafe+geo%3Along+%3Flong+.++++FILTER+%28+bif%3Ast_intersects+%28%3Fchurchgeo%2C+bif%3Ast_point+%282.3498%2C48.853%29%2C5%29++%26%26+bif%3Ast_intersects+%28%3Fcafegeo%2C+%3Fchurchgeo%2C+0.2%29+%29+}+LIMIT+50&debug=on&timeout=&format=text%2Fhtml&CXML_redir_for_subjs=&CXML_redir_for_hrefs=LOCAL_TTL&save=display&fname=
]]></programlisting>
</listitem>
<listitem>External description resource(CXML):
<programlisting><![CDATA[
# CXML_redir_for_subjs=&CXML_redir_for_hrefs=LOCAL_CXML:
http://lod.openlinksw.com/sparql?default-graph-uri=&should-sponge=&query=SELECT+DISTINCT+%3Fcafe+%3Flat+%3Flong+%3Fcafename+%3Fchurchname++%28+bif%3Around%28bif%3Ast_distance+%28%3Fchurchgeo%2C+%3Fcafegeo%29%29+%29++WHERE++{++++%3Fchurch+a+lgv%3Aplace_of_worship+.++++%3Fchurch+geo%3Ageometry+%3Fchurchgeo+.++++%3Fchurch+lgv%3Aname+%3Fchurchname+.++++%3Fcafe+a+lgv%3Acafe+.++++%3Fcafe+lgv%3Aname+%3Fcafename+.++++%3Fcafe+geo%3Ageometry+%3Fcafegeo+.++++%3Fcafe+geo%3Alat+%3Flat+.++++%3Fcafe+geo%3Along+%3Flong+.++++FILTER+%28+bif%3Ast_intersects+%28%3Fchurchgeo%2C+bif%3Ast_point+%282.3498%2C48.853%29%2C5%29++%26%26+bif%3Ast_intersects+%28%3Fcafegeo%2C+%3Fchurchgeo%2C+0.2%29+%29+}+LIMIT+50&debug=on&timeout=&format=text%2Fhtml&CXML_redir_for_subjs=&CXML_redir_for_hrefs=LOCAL_CXML&save=display&fname=
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="replallgr">
<title>How can I replicate all graphs?</title>
<para>To replicate all graphs ( except the system graph http://www.openlinksw.com/schemas/virtrdf# ),
one should use http://www.openlinksw.com/schemas/virtrdf#rdf_repl_all as graph IRI:</para>
<programlisting><![CDATA[
SQL> DB.DBA.RDF_RDF_REPL_GRAPH_INS ('http://www.openlinksw.com/schemas/virtrdf#rdf_repl_all');
]]></programlisting>
</sect2>
<sect2 id="rndsalltr">
<title>What is best method to get a random sample of all triples for a subset of all the resources
of a SPARQL endpoint?</title>
<para>The best method to get a random sample of all triples for a subset of all the resources of
a SPARQL endpoint, is decimation in its original style:</para>
<programlisting><![CDATA[
SELECT ?s ?p ?o
FROM <some-graph>
WHERE
{
?s ?p ?o .
FILTER ( 1 > bif:rnd (10, ?s, ?p, ?o) )
}
]]></programlisting>
<para>By tweaking first argument of <emphasis>bif:rnd()</emphasis> and the left side of the
inequality you can tweak decimation ratio from 1/10 to the desired value. What's important is
to know that the SQL optimizer has a right to execute <emphasis>bif:rnd (10)</emphasis> only once
at the beginning of the query, so we had to pass additional three arguments that can be known only
when a table row is fetched so <emphasis>bif:rnd (10, ?s, ?p, ?o)</emphasis> is calculated for every
row and thus any given row is either returned or ignored independently from others.</para>
<para>However, <emphasis>bif:rnd (10, ?s, ?p, ?o)</emphasis> contains a subtle inefficiency. In RDF
store, graph nodes are stored as numeric IRI IDs and literal objects can be stored in a separate
table. The call of an SQL function needs arguments of traditional SQL datatypes, so the query
processor will extract the text of IRI for each node and the full value for each literal object.
That is significant waste of time. The workaround is:</para>
<programlisting><![CDATA[
SPARQL
SELECT ?s ?p ?o
FROM <some-graph>
WHERE
{
?s ?p ?o .
FILTER ( 1> <SHORT_OR_LONG::bif:rnd> (10, ?s, ?p, ?o))
}
]]></programlisting>
<para>This tells the SPARQL front-end to omit redundant conversions of values.</para>
</sect2>
<sect2 id="replallgr">
<title>How can I replicate all graphs?</title>
<para>To replicate all graphs ( except the system graph http://www.openlinksw.com/schemas/virtrdf# ),
one should use http://www.openlinksw.com/schemas/virtrdf#rdf_repl_all as graph IRI:</para>
<programlisting><![CDATA[
SQL> DB.DBA.RDF_RDF_REPL_GRAPH_INS ('http://www.openlinksw.com/schemas/virtrdf#rdf_repl_all');
]]></programlisting>
</sect2>
<sect2 id="sparqlmkmeshup">
<title>How can I use SPARQL to make Meshups?</title>
<para>The following example demonstrates how to use SPARQL in order to make Meshups:</para>
<programlisting><![CDATA[
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX rtb: <http://www.openlinksw.com/schemas/oat/rdftabs#>
CONSTRUCT
{
?museum geo:geometry ?museumgeo ;
rtb:useMarker 'star' ;
foaf:name ?musname;
rdfs:comment ?muscomment.
?edu geo:geometry ?edugeo ;
rtb:useMarker 'book' ;
foaf:name ?eduname;
rdfs:comment ?educomment.
?wh geo:geometry ?whgeo;
rtb:useMarker '03';
foaf:name ?whname;
rdfs:comment ?whcomment.
}
WHERE
{
{
?museum a dbo:Museum;
geo:geometry ?museumgeo;
foaf:name ?musname;
rdfs:comment ?muscomment.
filter (lang(?musname)='en' && lang(?muscomment)='en')
}
UNION
{
?edu a dbo:University;
geo:geometry ?edugeo;
foaf:name ?eduname;
rdfs:comment ?educomment.
filter (lang(?eduname)='en' && lang(?educomment)='en')
}
UNION
{
?wh a dbo:WorldHeritageSite;
geo:geometry ?whgeo;
rdfs:label ?whname;
rdfs:comment ?whcomment.
filter (lang(?whname)='en' && lang(?whcomment)='en')
}
}
]]></programlisting>
</sect2>
<sect2 id="clusternetmeter">
<title>How can I use the net_meter utility before starting the ingestion to a cluster?</title>
<para>The <link linkend="">net_meter</link> utility is a SQL procedure that runs a network
test procedure on every host of the cluster. The network test procedure sends a message
to every other host of the cluster and waits for the replies from each host. After the last
reply is received the action is repeated. This results in a symmetrical load of the network,
all points acting as both clients and servers to all other points.
</para>
<programlisting><![CDATA[
net_meter (
in n_threads int,
in n_batches int,
in bytes int,
in ops_per_batch int)
]]></programlisting>
<para>The parameters have the following meaning:</para>
<itemizedlist mark="bullet">
<listitem><emphasis>n_threads</emphasis>: The number of network test instances started on
each host. A value of 4 on a cluster of 4 hosts would result in a total of 16 network test
procedures spread over 4 processes.
</listitem>
<listitem><emphasis>n_batches</emphasis>: The number of message exchanges done by each network
test procedure. A message exchange consists of sending one request to every other host of the cluster
and of waiting for all to have replied.
</listitem>
<listitem><emphasis>bytes</emphasis>: The number of bytes sent to each host in each message
exchange. The reply from each host has the same number of bytes.
</listitem>
<listitem><emphasis>ops_per_batch</emphasis>: This causes each message batch to contain several
operations. In practice this is a multiplier on the number of bytes.
</listitem>
</itemizedlist>
<sect3 id="clusternetmeterex">
<title>Example</title>
<para>Assume anuser has run 2 sets of tests on a cluster:</para>
<para>The first one was 1 thread, 1000 batches, 1000 bytes per exchange, 1 operation per batch:</para>
<programlisting><![CDATA[
SQL> net_meter (1, 1000, 1000, 1);
round_trips MBps
REAL REAL
_______________________________________
1245.393315542000254 2.489418401123078
1 Rows. -- 39345 msec.
]]></programlisting>
<para>resulted in a measured throughput of 2.5 MBps</para>
<para>The second one was 1 thread, 5000 batches, 10000 bytes per exchange, 1 operation per batch:</para>
<programlisting><![CDATA[
SQL> net_meter (1, 5000, 10000, 1);
round_trips MBps
REAL REAL
___________________________________________
15915.291672080031181 305.017186586494738
1 Rows. -- 15394 msec.
]]></programlisting>
<para>resulted in a measured throughput of 305 MBps.</para>
<para>This indicates that the user's network is slow when sending multiple short messages.</para>
<para>When using the ingestion you should check the:</para>
<programlisting><![CDATA[
status('cluster');
]]></programlisting>
<para>command a few times and check the XX KB/s amount which should be around or above the 2500 mark.</para>
</sect3>
</sect2>
<sect2 id="loadcmrdf">
<title>How can I use the LOAD command to import RDF data?</title>
<para>SPARQL INSERT can be done using the LOAD command:</para>
<programlisting><![CDATA[
SPARQL INSERT INTO <..> { .... } [[FROM ...] { ... }]
SPARQL LOAD <x> [INTO <y>]
-- <ResourceURL> will be the Graph IRI of the loaded data:
SPARQL LOAD <ResourceURL>
]]></programlisting>
<sect3 id="loadcmrdfex">
<title>Examples</title>
<sect4 id="loadcmrdfex1">
<title>Load from Resource URL</title>
<para>In order to load data from resource URL for ex:
http://www.w3.org/People/Berners-Lee/card#i , execute from isql the following command:</para>
<programlisting><![CDATA[
SQL> SPARQL LOAD <http://www.w3.org/People/Berners-Lee/card#i>;
callret-0
VARCHAR
_______________________________________________________________________________
Load <http://www.w3.org/People/Berners-Lee/card#i> into graph <http://www.w3.org/People/Berners-Lee/card#i> -- done
1 Rows. -- 703 msec.
SQL>
]]></programlisting>
</sect4>
<sect4 id="loadcmrdfex2">
<title>Load from file</title>
<orderedlist>
<listitem>Create DAV collection which is visible to public, for ex: http://example.com/DAV/tmp</listitem>
<listitem>Upload to the DAV collection a file for ex. with name listall.rq and with the following content:
<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>
</listitem>
<listitem>Execute from ISQL the following command:
<programlisting><![CDATA[
SQL>SPARQL LOAD bif:concat ("http://", bif:registry_get("URIQADefaultHost"), "/DAV/tmp/listall.rq") into graph <http://myNewGraph.com>;
callret-0
VARCHAR
_______________________________________________________________________________
Load <http://example.com/DAV/tmp/listall.rq> into graph <http://myNewGraph.com> -- done
1 Rows. -- 321 msec.
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
<sect4 id="loadcmrdfex3">
<title>Directly LOAD triples using ISQL</title>
<programlisting><![CDATA[
SQL>SPARQL INSERT INTO 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> .
};
]]></programlisting>
</sect4>
</sect3>
</sect2>
<sect2 id="degrprc">
<title>How can I delete graphs using stored procedure?</title>
<para>The following script demonstrates the use of custom stored procedures for deleting graph(s).
It first creates a table <emphasis>GRAPHS_TO_DELETE</emphasis>, into which the names of the graphs
to be deleted should be inserted, as follows:</para>
<programlisting><![CDATA[
use MYUSR;
create procedure GRAPHS_TO_DELETE_SP (in gd_iris any)
{
declare gd_iri iri_id;
declare dp, row any;
result_names (gd_iri);
dp := dpipe (0, '__I2IDN');
foreach (varchar iri in GD_IRIS) do
{
dpipe_input (dp, iri);
}
while (0 <> (row := dpipe_next (dp, 0)))
{
result (row[0]);
}
}
;
drop view GRAPHS_TO_DELETE_VIEW;
create procedure view GRAPHS_TO_DELETE_VIEW as MYUSR.DBA.GRAPHS_TO_DELETE_SP (gd_iris) (gd_iri any);
create procedure DELETE_GRAPHS (in g_iris any)
{
declare g_iids any;
if (not isvector (g_iris) and g_iris is not null)
signal ('22023', '.....', 'The input argument must be an array of strings or null');
if (not length (g_iris))
return 0;
delete from DB.DBA.RDF_QUAD where G in (select * from GRAPHS_TO_DELETE_VIEW where gd_iris = g_iris) option (loop exists);
return row_count ();
}
;
]]></programlisting>
<para>Finally call the procedure DELETE_GRAPHS to perform the deletion of the specified graphs.
Note it does not return a result set and can be called as follows:</para>
<programlisting><![CDATA[
SQL> select MYUSR.DBA.DELETE_GRAPHS (vector ('g1', 'g2', 'g3'));
]]></programlisting>
<para>This will return the number of triples removed from the specified graphs.</para>
<para>Note: the procedure only applies to the cluster so to get IRI IDs via partitioned
pipe (DAQ). It is not usable on single.</para>
</sect2>
<sect2 id="sparulspongertut">
<title>How can I use SPARUL to add missing triples to a Named Graph?</title>
<sect3 id="sparulspongertutwhat">
<title>What?</title>
<para>Use of SPARUL to add missing triples to a Named Graph. For example, an ontology/vocabulary
extension.</para>
</sect3>
<sect3 id="sparulspongertutwhy">
<title>Why?</title>
<para>A lot of ontologies and vocabularies started life prior to emergence of the Linked Data
meme. As a result, many do not include rdfs:isDefinedBy relations (via triples) that associate
Classes and Properties in an ontology with the ontology itself, using de-referencable URIs.
The downside of this pattern is that Linked Data's follow-your-nose pattern isn't exploitable
when viewing these ontologies e.g., when using contemporary Linked Data aware browsers.</para>
</sect3>
<sect3 id="sparulspongertuthow">
<title>How?</title>
<para>If SPARUL privileges are assigned to SPARQL or other accounts associated with SPARQL
Endpoint. Or via WebID? protected SPARQL endpoint with SPARUL is granted to SPARQL or specific
accounts or WebIDs in a group.</para>
<programlisting><![CDATA[
INSERT INTO <LocalNamedGraphIRI>
{ ?s rdfs:DefinedBy <LocalOntologyEntityURI>.
?o rdfs:isDefinedBy <http://www.w3.org/ns/auth/acl>. }
FROM <ExtSourceNamedGraphIRI>
WHERE
{
?s a ?o
}
]]></programlisting>
<sect4 id="sparulspongertutex">
<title>Example</title>
<orderedlist>
<listitem>Load Quad Named Graph via Sponger based query:
<programlisting><![CDATA[
DEFINE get:soft "replace"
SELECT DISTINCT *
FROM <http://www.w3.org/ns/auth/acl#>
WHERE
{
?s ?p ?o
}
]]></programlisting>
</listitem>
<listitem>Added Triples via SPARUL to Ontology Named Graph:
<programlisting><![CDATA[
INSERT INTO <http://www.w3.org/ns/auth/acl#>
{ ?s rdfs:DefinedBy <http://www.w3.org/ns/auth/acl>.
?o rdfs:DefinedBy <http://www.w3.org/ns/auth/acl>. }
FROM <http://www.w3.org/ns/auth/acl#>
WHERE
{
?s a ?o
}
]]></programlisting>
</listitem>
<listitem>Via Conductor or Command-line iSQL courtesy of SPASQL execute the following statements:
<orderedlist>
<listitem>Remove an existing graph:
<programlisting><![CDATA[
SPARQL
CLEAR GRAPH <http://www.w3.org/ns/auth/acl/> ;
SPARQL
CLEAR GRAPH <http://www.w3.org/ns/auth/acl> ;
SPARQL
CLEAR GRAPH <http://www.w3.org/ns/auth/acl#> ;
]]></programlisting>
</listitem>
<listitem>Load a new graph:
<programlisting><![CDATA[
SPARQL
LOAD <http://www.w3.org/ns/auth/acl> ;
]]></programlisting>
</listitem>
<listitem>Add missing rdfs:isDefinedBy triples via SPARUL:
<programlisting><![CDATA[
SPARQL
INSERT INTO <http://www.w3.org/ns/auth/acl>
{ ?s rdfs:DefinedBy <http://www.w3.org/ns/auth/acl>.
?o rdfs:DefinedBy <http://www.w3.org/ns/auth/acl>. }
FROM <http://www.w3.org/ns/auth/acl>
WHERE
{
?s a ?o
} ;
]]></programlisting>
</listitem>
</orderedlist>
</listitem>
<listitem>Verification: Access the following url: <emphasis>http://<cname>/describe/?uri=http://www.w3.org/ns/auth/acl></emphasis>
</listitem>
</orderedlist>
<tip><title>See Also:</title>
<para><link linkend="rdfsparul">SPARUL -- an Update Language For RDF Graphs</link></para>
<para><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSponger">Virtuoso Sponger</ulink><link linkend="rdfsparul"></link></para>
</tip>
</sect4>
</sect3>
</sect2>
<sect2 id="ifsparqlbi">
<title>How can I use the SPARQL IF operator for SPARQL-BI endpoint?</title>
<para>Assume a SPARQL query is to be executed against the Virtuoso DBpedia SPARQL endpoint
(<ulink url="http://dbpedia.org/sparql">http://dbpedia.org/sparql</ulink>) to retrieve the
decimal longitude of the "NJ Devils' hometown" with cardinal direction, which determines
whether the decimal is positive (in the case of East) or negative (in the case of West).</para>
<para>Virtuoso supports SPARQL-BI, an extended SPARQL 1.0 implementation from before SPARQL 1.1
was ratified, thus the "IF" operator is not currently supported, but an equivalent
<link linkend="fn_either"><function>bif:either</function></link> built-in SQL function does
exist enabling an equivalent query to be executed:</para>
<programlisting><![CDATA[
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX dbp: <http://dbpedia.org/property/>
SELECT ?team ( (bif:either( ?ew = 'W', -1, 1)) * (?d + (((?m * 60) + ?s) / 3600.0)) as ?v)
{
?team a dbo:HockeyTeam . ?team rdfs:label 'New Jersey Devils'@en .
?team dbp:city ?cityname . ?city rdfs:label ?cityname .
?city dbp:longd ?d; dbp:longm ?m; dbp:longs ?s; dbp:longew ?ew .
}
]]></programlisting>
<figure id="spbi1" float="1">
<title>SPARQL IF operator for SPARQL-BI endpoint</title>
<graphic fileref="ui/spbi1.png"/>
</figure>
<tip><title>See Also:</title>
<para><link linkend="rdfsparqlimplementatioptragmas">Supported SPARQL-BI "define" pragmas</link></para>
<para><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VOSArticleBISPARQL2">SPARQL-BI</ulink><link linkend="rdfsparul"></link></para>
</tip>
</sect2>
<sect2 id="chpntset">
<title>How can I handle checkpoint condition?</title>
<para>In general, to control checkpoint in order to bypass client timeouts during long checkpoints when inserting triples into the Virtuoso server, one must disable automatic checkpoint by:</para>
<programlisting><![CDATA[
SQL> checkpoint_interval (0);
]]></programlisting>
<para>and also to make sure the AutoCheckpointLogSize is off. Then can be performed checkpoint whenever the client wants using the 'checkpoint' command.</para>
<para>However the need of cache check is not needed unless instance shows regular errors. By default the cache check is disabled.</para>
<para>Virtuoso offers a new option in the Virtuoso ini file to enable the check of page maps: <emphasis>PageMapCheck</emphasis>, 1/0 default 0: </para>
<programlisting><![CDATA[
-- Virtuoso.ini
...
[Parameters]
...
PageMapCheck = 0
...
]]></programlisting>
<para>Also customer can add <emphasis>CheckpointSyncMode = 0</emphasis> in order to disable sync during checkpoint to speed the operations.</para>
</sect2>
<sect2 id="inccntnegt">
<title>How can I incorporate Content Negotiation into RDF bulk loaders?</title>
<para>The examples from below demonstrate how to incorporate Content Negotiation into RDF bulk loaders:</para>
<itemizedlist mark="bullet">
<listitem>Using the <link linkend="fn_rdf_load_rdfxml"><function>DB.DBA.RDF_LOAD_RDFXML</function></link> function:
<programlisting><![CDATA[
DB.DBA.RDF_LOAD_RDFXML (http_get ('http://purl.org/ontology/mo/', null, 'GET', 'Accept: application/rdf+xml', null, null, 3), 'http://purl.org/ontology/mo/', 'http://purl.org/ontology/mo/') .
]]></programlisting>
</listitem>
<listitem>Using the <link linkend="fn_ttlp"><function>DB.DBA.TTLP</function></link> function: The call to http client should be modified to ask for appropriate content type as for ex:
<programlisting><![CDATA[
DB.DBA.TTLP (http_get ('http://purl.org/ontology/mo/', null, 'GET', 'Accept: text/n3', null, null, 3), 'http://purl.org/ontology/mo/', 'http://purl.org/ontology/mo/'), '...', '...');
]]></programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="linkeddata3simplesteps">
<title>Virtuoso Linked Data Deployment In 3 Simple Steps?</title>
<para>Injecting Linked Data into the Web has been a major pain point for those who seek personal, service, or organization-specific variants of DBpedia. Basically, the sequence goes something like this:</para>
<orderedlist>
<listitem>You encounter DBpedia or the LOD Cloud Pictorial.</listitem>
<listitem>You look around (typically following your nose from link to link).</listitem>
<listitem>You attempt to publish your own stuff.</listitem>
<listitem>You get stuck.</listitem>
</orderedlist>
<para>The problems typically take the following form:</para>
<orderedlist>
<listitem>Functionality confusion about the complementary Name and Address functionality of a single URI abstraction.</listitem>
<listitem>Terminology confusion due to conflation and over-loading of terms such as Resource, URL, Representation, Document, etc.</listitem>
<listitem>Inability to find robust tools with which to generate Linked Data from existing data sources such as relational databases, CSV files, XML, Web Services, etc.</listitem>
</orderedlist>
<para>To start addressing these problems, here is a simple guide for generating and publishing Linked Data using Virtuoso.</para>
<sect3 id="linkeddata3simplesteps1">
<title>Step 1 - RDF Data Generation</title>
<para>Existing RDF data can be added to the Virtuoso RDF Quad Store via a variety of built-in data loader utilities.</para>
<para>Many options allow you to easily and quickly generate RDF data from other data sources:</para>
<itemizedlist mark="bullet">
<listitem>Install the Sponger Bookmarklet for the URIBurner service. Bind this to your own SPARQL-compliant backend RDF database (in this scenario, your local Virtuoso instance), and then perform Network Resource Fetch of some HTTP-accessible resources.</listitem>
<listitem>Convert relational DBMS data to RDF using the Virtuoso Linked Data Views Wizard.</listitem>
<listitem>Starting with CSV files, you can:
<itemizedlist mark="bullet">
<listitem>Place them at an HTTP-accessible location, and use the Virtuoso Sponger to convert them to RDF or;</listitem>
<listitem>Use the CVS import feature to import their content into Virtuoso's relational
data engine; then use the built-in Linked Data Views Wizard as with other RDBMS data.</listitem>
</itemizedlist>
</listitem>
<listitem>Starting from XML files, you can:
<itemizedlist mark="bullet">
<listitem>Use Virtuoso's inbuilt XSLT-Processor for manual XML to RDF/XML transformation or;</listitem>
<listitem>Leverage the Sponger Cartridge for GRDDL, if there is a transformation service associated with your XML data source, or;</listitem>
<listitem>Let the Sponger analyze the XML data source and make a best-effort transformation to RDF.</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</sect3>
<sect3 id="linkeddata3simplesteps2">
<title>Step 2 - Linked Data Deployment</title>
<para>Install the Faceted Browser VAD package (fct_dav.vad) which delivers the following:</para>
<orderedlist>
<listitem>Faceted Browser Engine UI</listitem>
<listitem>Dynamic Hypermedia Resource Generator:
<itemizedlist mark="bullet">
<listitem>delivers descriptor resources for every entity (data object) in the Native or Virtual Quad Stores</listitem>
<listitem>supports a broad array of output formats, including HTML+RDFa, RDF/XML, N3/Turtle, NTriples, RDF-JSON, OData+Atom, and OData+JSON.</listitem>
</itemizedlist>
</listitem>
</orderedlist>
</sect3>
<sect3 id="linkeddata3simplesteps3">
<title>Step 3 - Linked Data Consumption & Exploitation</title>
<para>Three simple steps allow you, your enterprise, and your customers to consume and exploit your newly deployed Linked Data --</para>
<orderedlist>
<listitem>Load a page like this in your browser: http://<cname>[:<port>]/describe/?uri=<entity-uri>
<itemizedlist mark="bullet">
<listitem><cname>[:<port>] gets replaced by the host and port of your Virtuoso instance </listitem>
<listitem><entity-uri> gets replaced by the URI you want to see described -- for instance, the URI of one of the resources you let the Sponger handle.</listitem>
</itemizedlist>
</listitem>
<listitem>Follow the links presented in the descriptor page.</listitem>
<listitem>If you ever see a blank page with a hyperlink subject name in the About: section at the top of the page, simply add the parameter "&sp=1" to the URL in the browser's Address box, and hit [ENTER]. This will result in an "on the fly" resource retrieval, transformation, and descriptor page generation.</listitem>
<listitem>Use the navigator controls to page up and down the data associated with the "in scope" resource descriptor.</listitem>
</orderedlist>
</sect3>
</sect2>
<sect2 id="difcrdrdelgr">
<title>What are the differences between create, drop, clear and delete Graph?</title>
<para>In Virtuoso it does not matter whether <emphasis>CREATE GRAPH</emphasis> and
<emphasis>DROP GRAPH</emphasis> are called or not. Their purpose is to provide compatibility with
the original SPARUL that was designed for Jena. Some Jena triple stores require explicit creation
of each graph (like CREATE TABLE in SQL), they report errors if one tries to create a graph twice
and so on.</para>
<para>For Virtuoso, a new graph is not an important system event, it has single quad store shared
by all graphs. When a graph is made by <emphasis>CREATE GRAPH</emphasis>, its name is placed in
an auxiliary table that is used solely to signal appropriate errors on CREATE graph that is
CREATE-d already or on DROP of a missing graph; this table is not used in any way in SPARQL or
other subsystems. In a perfect world, smart development tools will query that table to give
hints to a programmer regarding available graphs, but the reality is not so perfect.</para>
<para>What's more important is a difference between
<emphasis>DELETE FROM g { ?s ?p ?o } FROM g WHERE { ?s ?p ?o }</emphasis> and
<emphasis>CLEAR GRAPH g</emphasis>, as both will delete all triples from the specified graph <g> with
equal speed, but <emphasis>CLEAR GRAPH</emphasis> will also delete free-text index data about
occurrences of literals in this specific graph. So <emphasis>CLEAR GRAPH</emphasis> will make
the database slightly more compact and the text search slightly faster. (Naturally,
<emphasis>DROP GRAPH</emphasis> makes <emphasis>CLEAR GRAPH</emphasis> inside, not just
<emphasis>DELETE FROM ...</emphasis> )</para>
<tip><title>See Also:</title>
<para><link linkend="rdfinsertmethods">RDF Insert Methods in Virtuoso</link></para>
</tip>
</sect2>
<sect2 id="srchprd">
<title>How can I perform search for predicate values?</title>
<para><emphasis>What?</emphasis></para>
<para>Creation of a stored procedure that enables users to find properties based on their string based token patterns.</para>
<para><emphasis>Why?</emphasis></para>
<para>When working with datasets from disparate datasources in a common named graph, there are times when you seek to scope sparql or spasql queries to specific property IRI/URI patterns without embarking upon inefficient regex heuristics.</para>
<para><emphasis>What?</emphasis></para>
<para>Make a stored procedure for querying against the main quad store table (rdf_quad). Surface the procedure as a magic predicate using "bif:" prefix. To find all the properties whose predicates start with "http://www.openlinksw.com/", a Virtuoso/PL procedure can be used as listed below:</para>
<programlisting><![CDATA[
SQL> create procedure PREDICATES_OF_IRI_PATH (
in path varchar,
in dump_iri_ids integer := 0)
{
declare PRED_IRI varchar;
declare PRED_IRI_ID IRI_ID;
declare path_head_len integer;
if (dump_iri_ids)
result_names (PRED_IRI_ID);
else
result_names (PRED_IRI);
for ( SELECT RP_NAME, RP_ID
FROM RDF_PREFIX
WHERE (RP_NAME >= path) AND (RP_NAME < path || chr(255)) ) do
{
declare fourbytes varchar;
fourbytes := '----';
fourbytes[0] := bit_shift (RP_ID, -24);
fourbytes[1] := bit_and (bit_shift (RP_ID, -16), 255);
fourbytes[2] := bit_and (bit_shift (RP_ID, -8), 255);
fourbytes[3] := bit_and (RP_ID, 255);
for ( SELECT RI_NAME, RI_ID from RDF_IRI
WHERE (RI_NAME >= fourbytes) AND (RI_NAME < fourbytes || chr(255)) ) do
{
if (exists (SELECT TOP 1 1 FROM RDF_QUAD WHERE P=RI_ID))
result (case when (dump_iri_ids) then RI_ID else RP_NAME || subseq (RI_NAME, 4) end);
}
}
for ( path_head_len := length (path)-1; path_head_len >= 0; path_head_len := path_head_len - 1)
{
for ( SELECT RP_NAME, RP_ID from RDF_PREFIX
WHERE RP_NAME = subseq (path, 0, path_head_len) ) do
{
declare fourbytes varchar;
fourbytes := '----';
fourbytes[0] := bit_shift (RP_ID, -24);
fourbytes[1] := bit_and (bit_shift (RP_ID, -16), 255);
fourbytes[2] := bit_and (bit_shift (RP_ID, -8), 255);
fourbytes[3] := bit_and (RP_ID, 255);
for ( SELECT RI_NAME, RI_ID from RDF_IRI
WHERE (RI_NAME >= fourbytes || subseq (path, path_head_len))
AND (RI_NAME < fourbytes || subseq (path, path_head_len) || chr(255)) ) do
{
if (exists (SELECT TOP 1 1 FROM RDF_QUAD WHERE P=RI_ID))
result (case when (dump_iri_ids) then RI_ID else RP_NAME || subseq (RI_NAME, 4) end);
}
}
}
}
;
Done. -- 16 msec.
]]></programlisting>
<para><emphasis>Example Usage</emphasis></para>
<orderedlist>
<listitem>Execute:
<programlisting><![CDATA[
set echo on;
]]></programlisting>
</listitem>
<listitem>Collect all predicates that start with:
<programlisting><![CDATA[
-- http://www.openlinksw.com/
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/', 1);
VARCHAR
_______________________________________________________________________________
#i351
#i159
#i10
#i8
...
-- http://www.openlinksw.com/schemas/virtrdf
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/schemas/virtrdf', 1);
PRED_IRI_ID
VARCHAR
_______________________________________________________________________________
#i159
#i10
#i8
#i6
#i160
#i269
#i278
#i275
-- http://www.openlinksw.com/schemas/virtrdf#
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/schemas/virtrdf#',1);
PRED_IRI_ID
VARCHAR
_______________________________________________________________________________
#i159
#i10
#i8
#i6
#i160
#i269
#i278
...
-- http://www.openlinksw.com/schemas/virtrdf#i
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/schemas/virtrdf#i',1);
PRED_IRI_ID
VARCHAR
_______________________________________________________________________________
#i159
#i10
#i8
-- other
SQL>PREDICATES_OF_IRI_PATH ('no://such :)', 1);
0 Rows. -- 0 msec.
]]></programlisting>
</listitem>
<listitem>Show all predicates that start with:
<programlisting><![CDATA[
-- http://www.openlinksw.com/
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/');
PRED_IRI
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/schemas/DAV#ownerUser
http://www.openlinksw.com/schemas/virtrdf#inheritFrom
http://www.openlinksw.com/schemas/virtrdf#isSpecialPredicate
http://www.openlinksw.com/schemas/virtrdf#item
http://www.openlinksw.com/schemas/virtrdf#loadAs
http://www.openlinksw.com/schemas/virtrdf#noInherit
http://www.openlinksw.com/schemas/virtrdf#qmGraphMap
http://www.openlinksw.com/schemas/virtrdf#qmMatchingFlags
http://www.openlinksw.com/schemas/virtrdf#qmObjectMap
http://www.openlinksw.com/schemas/virtrdf#qmPredicateMap
http://www.openlinksw.com/schemas/virtrdf#qmSubjectMap
...
-- http://www.openlinksw.com/schemas/virtrdf
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/schemas/virtrdf');
PRED_IRI
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/schemas/virtrdf#inheritFrom
http://www.openlinksw.com/schemas/virtrdf#isSpecialPredicate
http://www.openlinksw.com/schemas/virtrdf#item
http://www.openlinksw.com/schemas/virtrdf#loadAs
http://www.openlinksw.com/schemas/virtrdf#noInherit
http://www.openlinksw.com/schemas/virtrdf#qmGraphMap
http://www.openlinksw.com/schemas/virtrdf#qmMatchingFlags
http://www.openlinksw.com/schemas/virtrdf#qmObjectMap
http://www.openlinksw.com/schemas/virtrdf#qmPredicateMap
http://www.openlinksw.com/schemas/virtrdf#qmSubjectMap
http://www.openlinksw.com/schemas/virtrdf#qmTableName
...
-- http://www.openlinksw.com/schemas/virtrdf#
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/schemas/virtrdf#');
PRED_IRI
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/schemas/virtrdf#inheritFrom
http://www.openlinksw.com/schemas/virtrdf#isSpecialPredicate
http://www.openlinksw.com/schemas/virtrdf#item
http://www.openlinksw.com/schemas/virtrdf#loadAs
http://www.openlinksw.com/schemas/virtrdf#noInherit
http://www.openlinksw.com/schemas/virtrdf#qmGraphMap
http://www.openlinksw.com/schemas/virtrdf#qmMatchingFlags
http://www.openlinksw.com/schemas/virtrdf#qmObjectMap
http://www.openlinksw.com/schemas/virtrdf#qmPredicateMap
http://www.openlinksw.com/schemas/virtrdf#qmSubjectMap
http://www.openlinksw.com/schemas/virtrdf#qmTableName
http://www.openlinksw.com/schemas/virtrdf#qmf01blankOfShortTmpl
http://www.openlinksw.com/schemas/virtrdf#qmf01uriOfShortTmpl
http://www.openlinksw.com/schemas/virtrdf#qmfBoolOfShortTmpl
http://www.openlinksw.com/schemas/virtrdf#qmfBoolTmpl
...
-- http://www.openlinksw.com/schemas/virtrdf#i
SQL>PREDICATES_OF_IRI_PATH ('http://www.openlinksw.com/schemas/virtrdf#i');
PRED_IRI
VARCHAR
_______________________________________________________________________________
http://www.openlinksw.com/schemas/virtrdf#inheritFrom
http://www.openlinksw.com/schemas/virtrdf#isSpecialPredicate
http://www.openlinksw.com/schemas/virtrdf#item
3 Rows. -- 15 msec.
-- other
SQL>PREDICATES_OF_IRI_PATH ('no://such :)');
PRED_IRI
VARCHAR
_______________________________________________________________________________
0 Rows. -- 15 msec.
]]></programlisting>
</listitem>
</orderedlist>
<para>If you want to use the procedure's output inside SPARQL queries, it can be wrapped by a procedure view and it in turn can be used in an Linked Data View but it is redundant for most applications.</para>
<para>For typical "almost static" data, it is more practical to write a procedure that will store all found predicates in some dedicated "dictionary" graph and then use the graph as usual.</para>
</sect2>
<sect2 id="constrinserst">
<title>How can I use INSERT via CONSTRUCT Statements?</title>
<para>You can write an ordinary CONSTRUCT statement, ensure that it generates the triples intended to be added, and then replace the leading CONSTRUCT keyword with the INSERT INTO phrase.</para>
<para><emphasis>Example:</emphasis></para>
<orderedlist>
<listitem>Assume new triples need to be added for the equivalentClass:
<programlisting><![CDATA[
CONSTRUCT
{
?s <http://www.w3.org/2002/07/owl#equivalentClass> `iri (bif:replace(?o,'http://schema.rdfs.org/', 'http://schema.org/'))`
}
FROM <http://www.openlinksw.com/schemas/rdfs>
WHERE
{
?s <http://www.w3.org/2002/07/owl#equivalentClass> ?o
};
]]></programlisting>
</listitem>
<listitem>Execute the CONSTRUCT query from the htp://cname/sparql SPARQL endpoint.</listitem>
<listitem>View the generated triples to ensure they are correct.</listitem>
<listitem>Replace CONSTRUCT with INSERT INTO:
<programlisting><![CDATA[
SPARQL INSERT INTO <http://www.openlinksw.com/schemas/rdfs>
{
?s <http://www.w3.org/2002/07/owl#equivalentClass> `iri (bif:replace(?o,'http://schema.rdfs.org/', 'http://schema.org/'))`
}
FROM <http://www.openlinksw.com/schemas/rdfs>
WHERE
{
?s <http://www.w3.org/2002/07/owl#equivalentClass> ?o
} ;
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="cleargraphrelemtgr">
<title>How to clear graphs which are related to empty graphs?</title>
<para>The following example demonstrates how to remove graphs which are related to empty graphs:</para>
<programlisting><![CDATA[
PREFIX nrl:<http://www.semanticdesktop.org/ontologies/2007/08/15/nrl#>
SELECT ( bif:exec(bif:sprintf("SPARQL CLEAR GRAPH<%s>", str(?mg))))
WHERE
{
?mg nrl:coreGraphMetadataFor ?g .
FILTER(?g in ( <urn:nepomuk:local:8a9e692a> )) .
FILTER ( !bif:exists((SELECT (1) WHERE { GRAPH ?g { ?s ?p ?o . } . })) ) .
}
]]></programlisting>
</sect2>
<sect2 id="subqrbl">
<title>How can I use sub-queries to enable literal values based joins?</title>
<sect3 id="subqrblwhat">
<title>What?</title>
<para>Use of subqueries to enable literal values based joins.</para>
</sect3>
<sect3 id="subqrblwhy">
<title>Why?</title>
<para>Sophisticated access to literal values via subqueries provides powerful mechanism for enhancing sparql graph patterns via dynamic literal value generation.</para>
</sect3>
<sect3 id="subqrblhow">
<title>How?</title>
<para>Use select list variables from subqueries to produce literal object values in sparql graph patterns.</para>
<sect4 id="subqrblhowex">
<title>Example</title>
<para>Assume in the following query, where should be used a sub-query to replace ?app:</para>
<programlisting><![CDATA[
SELECT DISTINCT ?r
WHERE
{
graph ?g
{
?r nie:url ?url .
} .
?g nao:maintainedBy ?app .
?app nao:identifier "nepomukindexer" .
}
]]></programlisting>
<para>If it is not sure that ?app is the only, for e.g., the triple ?app nao:identifier "nepomukindexer" can appear in more than one graph, then the query should be changed to:</para>
<programlisting><![CDATA[
SELECT DISTINCT ?r
WHERE
{
graph ?g
{
?r nie:url ?url .
} .
?g nao:maintainedBy ?app .
FILTER (?app = (SELECT ?a WHERE { ?a nao:identifier "nepomukindexer" }))
}
]]></programlisting>
<para>or even shorter:</para>
<programlisting><![CDATA[
SELECT DISTINCT ?r
WHERE
{
graph ?g
{
?r nie:url ?url .
} .
?g nao:maintainedBy `(SELECT ?a WHERE { ?a nao:identifier "nepomukindexer" })` .
}
]]></programlisting>
</sect4>
</sect3>
</sect2>
<sect2 id="sparqlpreforder">
<title>How can I execute query with labels preference order?</title>
<para>The way to prefer one label to the other can be done as follows:</para>
<itemizedlist mark="bullet">
<listitem>Have a procedure which returns preference order:
<programlisting><![CDATA[
create procedure lbl_order (in p any)
{
declare r int;
r := vector (
'http://www.w3.org/2000/01/rdf-schema#label',
'http://xmlns.com/foaf/0.1/name',
'http://purl.org/dc/elements/1.1/title',
'http://purl.org/dc/terms/title',
'http://xmlns.com/foaf/0.1/nick',
'http://usefulinc.com/ns/doap#name',
'http://rdf.data-vocabulary.org/name',
'http://www.w3.org/2002/12/cal/ical#summary',
'http://aims.fao.org/aos/geopolitical.owl#nameListEN',
'http://s.opencalais.com/1/pred/name',
'http://www.crunchbase.com/source_description',
'http://dbpedia.org/property/name',
'http://www.geonames.org/ontology#name',
'http://purl.org/ontology/bibo/shortTitle',
'http://www.w3.org/1999/02/22-rdf-syntax-ns#value',
'http://xmlns.com/foaf/0.1/accountName',
'http://www.w3.org/2004/02/skos/core#prefLabel',
'http://rdf.freebase.com/ns/type.object.name',
'http://s.opencalais.com/1/pred/name',
'http://www.w3.org/2008/05/skos#prefLabel',
'http://www.w3.org/2002/12/cal/icaltzd#summary',
'http://rdf.data-vocabulary.org/name',
'http://rdf.freebase.com/ns/common.topic.alias',
'http://opengraphprotocol.org/schema/title',
'http://rdf.alchemyapi.com/rdf/v1/s/aapi-schema.rdf#Name',
'http://poolparty.punkt.at/demozone/ont#title'
);
if (isiri_id (p))
p := id_to_iri (p);
r := position (p, r);
if (r = 0)
return 100;
return r;
}
;
]]></programlisting>
</listitem>
<listitem>Execute the following query:
<programlisting><![CDATA[
SPARQL
DEFINE input:inference "facets"
SELECT ?o
WHERE
{
<http://uriburner.com/about/id/entity/http/www.linkedin.com/in/kidehen#CV_mfrTl4s6Jy> virtrdf:label ?o ;
?p ?o .
}
ORDER BY (sql:lbl_order (?p));
]]></programlisting>
</listitem>
<listitem>Or execute the following query using sql:
<programlisting><![CDATA[
SELECT __ro2sq (O), lbl_order (P)
FROM RDF_QUAD table option (with ''facets'')
WHERE G = __i2id (?)
AND S = __i2id (?)
AND P = __i2id (''http://www.openlinksw.com/schemas/virtrdf#label'', 0)
ORDER BY 2
]]></programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="getobjdtype">
<title>How can I get object datatype?</title>
<para>To get object datatype should be used the internal Virtuoso/PL function
<link linkend="fn_rdf_datatype_of_obj"><function>DB.DBA.RDF_DATATYPE_OF_OBJ</function></link>, visible in SPARQL as sql:RDF_DATATYPE_OF_OBJ.
</para>
<para>Suppose the following scenario:</para>
<programlisting><![CDATA[
# Explicit typecast (insert)
SQL> sparql insert into <test_datatype> { <a> <string> "string 1"^^xsd:string . };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <test_datatype>, 1 (or less) triples -- done
1 Rows. -- 94 msec.
#Not explicit typecast (insert)
SQL> sparql insert into <test_datatype> { <a> <string> "string 2". };
callret-0
VARCHAR
_______________________________________________________________________________
Insert into <test_datatype>, 1 (or less) triples -- done
1 Rows. -- 16 msec.
SQL> SPARQL
SELECT ?o (iri(sql:RDF_DATATYPE_OF_OBJ(?o, 'untyped!')))
FROM <test_datatype> { <a> <string> ?o} ;
o callret-1
VARCHAR VARCHAR
_______________________________________________________________________________
string 1 http://www.w3.org/2001/XMLSchema#string
string 2 untyped!
2 Rows. -- 16 msec.
SQL>
]]></programlisting>
</sect2>
<sect2 id="howbackuprestoreind">
<title>How Can I Backup and Restore individual table(s) and individual index(s)?</title>
<para>See more details <link linkend="procindexrecov">here</link>.</para>
</sect2>
<sect2 id="bifcontainsoptions">
<title>What bif:contains free-text options can I use?</title>
<para>Virtuoso supports the following free-text options for bif:contains:</para>
<orderedlist>
<listitem><emphasis>OFFBAND</emphasis>: See description for this free-text option in
<link linkend="offbanddata">this section</link>.
<itemizedlist mark="bullet">
<listitem>Note: it is useful only if data comers via an Linked Data View and the source
relational table uses this trick;</listitem>
</itemizedlist>
</listitem>
<listitem><emphasis>SCORE</emphasis>: This free-text option is calculated as described in
<link linkend="hitscores">this section</link>:
<programlisting><![CDATA[
SQL>SPARQL
SELECT ?s1 as ?c1, ?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
}
}
};
c1 sc rank
_________________________________________________________________________
http://www.mixx.com/stories/45003360/justi... 3 5.881291583872891e-14
http://www.mixx.com/stories/45099313/bing_... 2.7 5.881291583872891e-14
http://dbpedia.org/resource/CBS_Interactive 1.5 5.881291583872891e-14
http://dbpedia.org/resource/CBS_Interactive 1.5 5.881291583872891e-14
4 Rows. -- 1 msec.
]]></programlisting>
</listitem>
<listitem><emphasis>SCORE_LIMIT</emphasis>: This free-text option works as it is in plain
SQL free-text. <link linkend="queryingftcols">See more details</link> :
<programlisting><![CDATA[
SQL> SPARQL
SELECT ?s ?sc
WHERE
{
?s ?p ?o .
?o bif:contains "tree" OPTION (score ?sc , score_limit 20)
};
s sc
VARCHAR INTEGER
________________________________________________________________________________
http://www.openlinksw.com/virtrdf-data-formats#default 24
http://www.openlinksw.com/virtrdf-data-formats#default 24
http://www.openlinksw.com/virtrdf-data-formats#sql-longvarbinary 21
http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-dt 20
http://www.openlinksw.com/virtrdf-data-formats#sql-nvarchar-dt 20
http://www.openlinksw.com/virtrdf-data-formats#sql-varchar-lang 20
http://www.openlinksw.com/virtrdf-data-formats#sql-nvarchar-lang 20
7 Rows. -- 2 msec.
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="sparqlendpointprotection">
<title>What SPARQL Endpoint Protection Methods can I use?</title>
<para>Virtuoso supports the following SPARQL Endpoint protection methods:</para>
<orderedlist>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSPARQLSecurityWebID">Secure SPARQL Endpoint Guide using WebID Protocol</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtOAuthSPARQL">Secure SPARQL Endpoint Guide via OAuth</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtSPARQLProtectSQLDigestAuthentication">Secure SPARQL Endpoint Guide via SQL Accounts -- usage path digest authentication</ulink></listitem>
</orderedlist>
</sect2>
<sect2 id="sparqlassignrole">
<title>How do I assign SPARQL role to SQL user?</title>
<para>This section a sample scenario how to assign SPARQL ( for ex. SPARQL_SELECT ) role to
Virtuoso SQL user:</para>
<orderedlist>
<listitem>Go to <ulink url="http://cname/conductor">http://cname/conductor</ulink>.</listitem>
<listitem>Enter dba credentials.</listitem>
<listitem>Go to System Admin -> User Accounts:
<figure id="role1" float="1">
<title>Assign SPARQL Role to SQL User</title>
<graphic fileref="ui/ag1.png"/>
</figure>
</listitem>
<listitem>Click "Edit" for a given user from the very last right column:
<figure id="role2" float="1">
<title>Assign SPARQL Role to SQL User</title>
<graphic fileref="ui/ag2.png"/>
</figure>
</listitem>
<listitem>From "Accounts Roles" drop-down list select a SPARQL Role, for ex.
<emphasis>SPARQL_SELECT</emphasis> and click the ">>" button:
<figure id="role1" float="1">
<title>Assign SPARQL Role to SQL User</title>
<graphic fileref="ui/ag3.png"/>
</figure>
</listitem>
<listitem>Click "Save". </listitem>
</orderedlist>
</sect2>
<sect2 id="gecodedata">
<title>How Do I Gecode Data?</title>
<para><emphasis>What?</emphasis></para>
<para>Automatic geocoding of data in quad store.</para>
<para><emphasis>Why?</emphasis></para>
<para>Enable exploitation of SPARQL-GEO for geospatial oriented queries.</para>
<para><emphasis>How?</emphasis></para>
<para>To gecode data one should call the <link linkend="fn_rdf_geo_fill"><function>rdf_geo_fill</function></link> API from Conductor or iSQL:</para>
<programlisting><![CDATA[
SQL> rdf_geo_fill ();
Done. -- 282 msec.
]]></programlisting>
<sect3 id="gecodedata">
<title>SPARQL-GEO sample queries</title>
<itemizedlist mark="bullet">
<listitem><ulink url="http://lod.openlinksw.com/b3s/search.vsp?q=20&sc=http%3A%2F%2Fdbpedia.org%2Fresource%2FOxford&sc2=5&sc3=http%3A%2F%2Fdbpedia.org%2Fproperty%2Festablished&sc4=en&fa=Execute">All Educational Institutions within 10km of Oxford, UK</ulink>:
<programlisting><![CDATA[
SELECT DISTINCT ?thing AS ?uri ?thingLabel AS ?name ?date AS ?established ?lat ?long WHERE
{
<http://dbpedia.org/resource/Oxford> geo:geometry ?sourcegeo .
?resource geo:geometry ?matchgeo .
?resource geo:lat ?lat .
?resource geo:long ?long .
FILTER ( bif:st_intersects ( ?matchgeo, ?sourcegeo, 5 ) ) .
?thing ?somelink ?resource .
?thing <http://dbpedia.org/property/established> ?date .
?thing rdfs:label ?thingLabel .
FILTER ( lang ( ?thingLabel ) = "en" )
}
]]></programlisting>
</listitem>
<listitem><ulink url="http://lod.openlinksw.com/b3s/search.vsp?q=18&sc=http%3A%2F%2Fdbpedia.org%2Fresource%2FLondon&sc2=20&sc3=en&fa=Execute">Things within close proximity of London</ulink>:
<programlisting><![CDATA[
SELECT DISTINCT ?resource ?label ?location WHERE
{
<http://dbpedia.org/resource/London> geo:geometry ?sourcegeo .
?resource geo:geometry ?location ; rdfs:label ?label .
FILTER ( bif:st_intersects ( ?location, ?sourcegeo, 20 ) ) .
FILTER ( lang ( ?label ) = "en" )
}
]]></programlisting>
</listitem>
</itemizedlist>
</sect3>
<tip><title>See Also:</title>
<itemizedlist mark="bullet">
<listitem><link linkend="fn_rdf_geo_fill"><function>rdf_geo_fill</function></link></listitem>
<listitem><link linkend="rdfsparqlgeospatcrg">Creating Geometries From RDF Data</link></listitem>
<listitem><link linkend="rdfsparqlgeospatprog">Programmatic Manipulation of Geometries in RDF</link></listitem>
<listitem><link linkend="rdfsparqlgeospatusg">Using Geometries With Existing Databases</link></listitem>
<listitem><ulink url="http://lod.openlinksw.com/b3s/">OpenLink Billion Triple Demo queries</ulink></listitem>
</itemizedlist>
</tip>
</sect2>
<sect2 id="delsptriple">
<title>How Can I Delete a Specific Triple Across Graphs?</title>
<para>Suppose the following situation:</para>
<itemizedlist mark="bullet">
<listitem>There is a specific triple somewhere in a massive dataset in a Virtuoso DBMS.</listitem>
<listitem>There are too many possible named graphs associated with the pattern so
<emphasis>SPARQL DELETE</emphasis> (which requires <emphasis>FROM</emphasis> i.e., Named
Graph scoping) isn't adequate</listitem>
</itemizedlist>
<para>What is the solution?</para>
<para>Using SQL you can execute the following:</para>
<programlisting><![CDATA[
SQL> SPARQL
DELETE FROM rdf_quad
WHERE s = iri_to_id ('http://linkeddata.uriburner.com/about/id/entity/http/twitter.com/kidehen')
AND o = iri_to_id ('http://purl.org/ontology/bibo/Document')
AND p = iri_to_id ('http://www.w3.org/1999/02/22-rdf-syntax-ns#type');
]]></programlisting>
</sect2>
<sect2 id="sparqlnotexists">
<title>How Do I Use NOT EXISTS in SPARQL Query?</title>
<para>Virtuoso supports "NOT EXISTS" SPARQL 1.1 feature. For example:</para>
<programlisting><![CDATA[
SQL> SPARQL
SELECT COUNT(*)
WHERE
{
?s ?p "Novosibirsk" FILTER NOT EXISTS { ?s ?p "Новосибирск" }
}
callret-0
INTEGER
313
No. of rows in result: 1
]]></programlisting>
<para>This query is equivalent to the following query:</para>
<programlisting><![CDATA[
SQL> SPARQL
SELECT COUNT(*)
WHERE
{
{ ?s ?p "Novosibirsk" } MINUS { ?s ?p "Новосибирск" } }
callret-0
INTEGER
313
No. of rows in result: 1
]]></programlisting>
</sect2>
<sect2 id="sparqlminus">
<title>How Do I Use MINUS in SPARQL Query?</title>
<para>Virtuoso supports "MINUS" SPARQL 1.1 feature. For example:</para>
<programlisting><![CDATA[
SQL> SPARQL
SELECT COUNT(*)
WHERE
{
{ ?s ?p "Novosibirsk" } MINUS { ?s ?p "Новосибирск" } }
callret-0
INTEGER
313
No. of rows in result: 1
]]></programlisting>
<para>This query is equivalent to the following query:</para>
<programlisting><![CDATA[
SQL> SPARQL
SELECT COUNT(*)
WHERE
{
?s ?p "Novosibirsk" FILTER NOT EXISTS { ?s ?p "Новосибирск" }
}
callret-0
INTEGER
313
No. of rows in result: 1
]]></programlisting>
</sect2>
<sect2 id="subclassofinferenceoptions">
<title>How Do I Use Transitive SPARQL Query Options and Exploit Inference Rules?</title>
<para>This section contains subClassOf oriented subsumption examples and examples for
Transitive Options e.g., Scope the reasoning to layers in the hierarchy.</para>
<sect3 id="subclassofinferenceoptionstranexmp">
<title>Transitive query options examples usage</title>
<itemizedlist mark="bullet">
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_5/SPARQL_Tutorials_Part_5.html#%2849%29">Transitivity with sameAs and graph</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_5/SPARQL_Tutorials_Part_5.html#%2850%29">Transitive Closure via Graph Path Expressions: TBox</ulink></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/presentations/SPARQL_Tutorials/SPARQL_Tutorials_Part_5/SPARQL_Tutorials_Part_5.html#%2851%29">Transitive Closure via Graph Path Expressions: ABox</ulink></listitem>
<listitem><link linkend="rdfsparqlimplementatiotransexamples7">Inference Rule using transitive properties from SKOS vocabulary</link></listitem>
</itemizedlist>
</sect3>
<sect3 id="subclassofinferenceoptionsinferexmp">
<title>subClassOf examples usage</title>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfiridereferencingfacetprlh">Processing Large Hierarchies in SPARQL</link></listitem>
<listitem><link linkend="rdfsparqlimplementatiotransexamples5">Example for TBox Subsumption</link></listitem>
<listitem><link linkend="rdfsparqlimplementatiotransexamples6">Example for Receptors</link></listitem>
<listitem><ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtTipsAndTricksGuideRDFSchemaOWLInferenceRules">Inference Rule using transitive properties from SKOS vocabulary</ulink></listitem>
</itemizedlist>
</sect3>
</sect2>
<sect2 id="samplegroupconcatdigest">
<title>What is the difference between the functions SAMPLE, GROUP_CONCAT and GROUP_DIGEST?</title>
<para>This section demonstrates the differences between the functions
<link linkend="fn_SAMPLE"><function>SAMPLE</function></link>,
<link linkend="fn_GROUP_CONCAT"><function>GROUP_CONCAT</function></link> and
<link linkend="fn_GROUP_DIGEST"><function>GROUP_DIGEST</function></link>.
</para>
<para>Assume the following query that should get all ?assets as a list with delimiters:</para>
<programlisting><![CDATA[
SPARQL SELECT ?view ?path (sql:GROUP_CONCAT (?asset, ' ')) as ?asset_list
FROM <http://mygraph.com>
WHERE
{
?view <viewPath> ?path ;
<viewContent> ?asset ;
<viewType> 'phyview'.
}
;
]]></programlisting>
<para>This method is not universal, because conversion to strings will eliminate the difference
between strings and IRIs and there should be some delimiter that never appears in values of
?asset. In addition, the query may fail with "row too long" error if values of ?asset are
lengthy and/or numerous enough. It is also possible the query not work completely free from
duplicates if more than one list is desired. E.g.:</para>
<programlisting><![CDATA[
SPARQL
SELECT ?view (sql:GROUP_CONCAT (?path, ' ')) as ?path_list
(sql:GROUP_CONCAT (?asset, ' ')) as ?asset_list
FROM <http://mygraph.com>
WHERE
{
?view <viewPath> ?path ;
<viewContent> ?asset ;
<viewType> 'phyview' .
}
]]></programlisting>
<para>will not contain duplicates in lists only if either ?path or ?asset is unique for every
found ?view; but if it's so unique then there's no need in the corresponding
sql:GROUP_CONCAT().</para>
<para>If there are many values per property but it's enough to return any single value and ignore
the rest then use sql:<link linkend="fn_SAMPLE"><function>SAMPLE ()</function></link>
function instead of sql:<link linkend="fn_GROUP_CONCAT"><function>GROUP_CONCAT ()</function></link>.
</para>
<para>If there are many values per property and it's better to show more than one value but "row
too long" error happens, then the sql:<link linkend="fn_GROUP_DIGEST"><function>GROUP_DIGEST ()</function></link>
function can be used:</para>
<programlisting><![CDATA[
SPARQL
SELECT ?view (sql:GROUP_DIGEST (?path, ' ', 1000, 1)) as ?path_list
(sql:GROUP_DIGEST (?asset, ' ', 1000, 1)) as ?asset_list
FROM <http://mygraph.com>
WHERE
{
?view <viewPath> ?path ;
<viewContent> ?asset ;
<viewType> 'phyview' .
}
]]></programlisting>
</sect2>
<sect2 id="constructaggfunc">
<title>How Do I use CONSTRUCT with objects which are value of aggregate function?</title>
<para>The following section demonstrates usage example of CONSTRUCT Query with object which is
a value of the aggregate function COUNT:</para>
<orderedlist>
<listitem>Assume following SPARQL SELECT Query:
<programlisting><![CDATA[
SELECT DISTINCT ?category COUNT(?category) AS ?count
WHERE
{
?s<http://purl.org/dc/terms/subject> ?category
FILTER(?s =<http://dbpedia.org/resource/Higgs_boson> || ?s =<http://dbpedia.org/resource/Gluon>)
}
]]></programlisting>
</listitem>
<listitem>To present it as CONSTRUCT Query, one should put "SELECT DISTINCT" into the
CONSTRUCT's WHERE clause as a subquery. So for example it could be:
<programlisting><![CDATA[
CONSTRUCT
{
?category a<http://www.w3.org/2004/02/skos/core#Concept> .
?category<http://www.turnguard.com/virtuoso/aggregates#count> ?count
}
WHERE
{
{
SELECT DISTINCT ?category COUNT(?category) AS ?count
WHERE
{
?s <http://purl.org/dc/terms/subject> ?category
FILTER(?s =<http://dbpedia.org/resource/Higgs_boson> || ?s =<http://dbpedia.org/resource/Gluon>)
}
}
}
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="sparqlcleanerrantdata">
<title>How Do I Clean Up Errant Data using SPARQL Update Language?</title>
<sect3 id="sparqlcleanerrantdatawhat">
<title>What?</title>
<para>Cleaning up errant data using SPARQL Update Language.</para>
</sect3>
<sect3 id="sparqlcleanerrantdatawhy">
<title>Why?</title>
<para>All data endeavors involve varying degrees of prospective and retrospective error
correction.</para>
</sect3>
<sect3 id="sparqlcleanerrantdatahow">
<title>How?</title>
<para>Given a triple in a Virtuoso Quad store that contains an errant URI e.g. one that
accidentally contains spaces, here is a SPARQL example that showcases how to delete said
triple using a built-in function:</para>
<programlisting><![CDATA[
DELETE FROM <your_graph>
{
`iri("http://isbsg.clearbluewater.com.au/wsf/datasets/378/Capers Jones_107_12122011081257")`
a <http://isbsg.org/ontology/data/Dataset>
};
]]></programlisting>
</sect3>
</sect2>
<sect2 id="sparqladdmissingtriples">
<title>How to Use SPARQL to add missing isDefinedBy relations to an Ontology?</title>
<sect3 id="sparqladdmissingtripleswhat">
<title>What?</title>
<para>Using SPARQL to add missing isDefinedBy relations to an Ontology.</para>
</sect3>
<sect3 id="sparqladdmissingtripleswhy">
<title>Why?</title>
<para>isDefinedBy relations make Ontologies (TBox) more navigable using follow-your-nose
pattern. This also makes ABox instance data more discoverable.</para>
</sect3>
<sect3 id="sparqladdmissingtripleshow">
<title>How?</title>
<para>Use SPARQL to generate relations that associate Classes and Properties the Ontology
that describes them.</para>
<sect4 id="sparqladdmissingtriplesvcard">
<title>Example Using the Ontology for vCards</title>
<para>In this example we will use:</para>
<itemizedlist mark="bullet">
<listitem>Ontology Document URL: http://www.w3.org/2006/vcard/ns ;</listitem>
<listitem>Ontology URI: http://www.w3.org/2006/vcard/ns# ;</listitem>
<listitem>A local Named Graph IRI to host SPARQL Update (SPARUL) the new relations.</listitem>
</itemizedlist>
<programlisting><![CDATA[
## Uncomment line below if using Virtuoso and executing SPARQL via iSQL
## or via an ODBC, JDBC, ADO.NET connection
## SPARQL
## Uncomment line (a SPARQL pragma) below if using Virtuoso and there
## isn't a local Named Graph holding triples retrieved from the Ontology URL
## DEFINE get:soft "add"
INSERT INTO <urn:data:qos:vcard>
{ ?s rdfs:isDefinedBy <http://www.w3.org/2006/vcard/ns#> }
FROM <http://www.w3.org/2006/vcard/ns>
WHERE
{
?s a ?o
}
]]></programlisting>
</sect4>
<sect4 id="sparqladdmissingtripleshowrmedia">
<title>Example Using the Recorded Media Ontology</title>
<para>In this example we will use:</para>
<itemizedlist mark="bullet">
<listitem>Ontology Document URL: http://www.w3.org/ns/ma-ont ;</listitem>
<listitem>Ontology URI: http://www.w3.org/ns/ma-ont# ;</listitem>
<listitem>A local Named Graph IRI to host SPARQL Update (SPARUL) the new relations.</listitem>
</itemizedlist>
<programlisting><![CDATA[
SPARQL
INSERT INTO <urn:data:qos:ma-ont>
{ ?s rdfs:isDefinedBy <http://www.w3.org/ns/ma-ont#> }
FROM <http://www.w3.org/ns/ma-ont>
WHERE
{
?s a ?o
}
]]></programlisting>
</sect4>
</sect3>
</sect2>
<sect2 id="loadsqldjdbc">
<title>How Can I execute load of sql dump from jdbc?</title>
<para>LOAD" is not a Virtuoso SQL command, it's an ISQL one. The ISQL checks the command to
be executed, whether it's of special "isql"-ish syntax or not, it executes commands it
understand and send the rest to the server, unchanged.</para>
<para>There's no way to mimic ISQL's behavior right on the server, without ISQL. However
some files can be loaded via the
<link linkend="fn_vad_load_sql_file"><function>DB.DBA.VAD_LOAD_SQL_FILE</function></link>
function.
</para>
</sect2>
<sect2 id="usemodifyasinsert">
<title>How Can I Use MODIFY to update triples?</title>
<para>The following queries are equivalent:</para>
<programlisting><![CDATA[
MODIFY <http://test.com/>
DELETE {?s ?p ?o}
INSERT {?s_new ?p ?o}
FROM <http://test.com/>
WHERE
{
{
SELECT iri(bif:replace(str(?s),"http://test.com/link","http://test.com/extra/link" ) )
AS ?s_new ?s ?p ?o
WHERE
{
?s ?p ?o FILTER (regex (str(?s), "http://test.com/link"))
}
}
}
]]></programlisting>
<programlisting><![CDATA[
MODIFY <http://test.com/>
DELETE {?s ?p ?o}
INSERT {`iri(?s_new)` ?p ?o}
FROM <http://test.com/>
WHERE
{
{
SELECT bif:replace(str(?s),"http://test.com/link","http://test.com/extra/link" )
AS ?s_new ?s ?p ?o
WHERE
{
?s ?p ?o FILTER (regex (str(?s), "http://test.com/link"))
}
}
}
]]></programlisting>
<programlisting><![CDATA[
MODIFY <http://test.com/>
DELETE {?s ?p ?o}
INSERT
{ `iri(bif:replace(str(?s),"http://test.com/link","http://test.com/extra/link" ))` ?p ?o }
FROM <http://test.com/>
WHERE
{
{
?s ?p ?o FILTER (regex (str(?s), "http://test.com/link"))
}
}
}
]]></programlisting>
</sect2>
<sect2 id="exectinsdelsparqilwebid">
<title>How Can I execute INSERT/DELETE (SPARUL) statements against a WebID? protected SPARQL endpoint?</title>
<para>View our <link linkend="rdfsparulexamples22">sample scenario</link>.</para>
</sect2>
<sect2 id="loggingandrecording">
<title>How can I make HTTP Logging and Recording in Virtuoso?</title>
<sect3 id="loggingandrecordinglg">
<title>HTTP Logging</title>
<para>Virtuoso can keep http log with all the requests that are made to the HTTP endpoint. Here
are the steps:</para>
<orderedlist>
<listitem>Edit your virtuoso.ini and add the following setting:
<programlisting><![CDATA[
[HTTPServer]
HTTPLogFile = logs/http15022012.log
]]></programlisting>
</listitem>
<listitem>Restart Virtuoso.</listitem>
<listitem>Virtuoso will now maintain a http log in the logs
subdirectory, with one line per request as in:
<programlisting><![CDATA[
180.76.5.87 - - [15/Feb/2012:21:50:44 +0100] "GET /data/Wilton_power_stations.json HTTP/1.0" 200 8014 ""
"Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)"
180.76.5.87 - - [15/Feb/2012:21:50:45 +0100] "POST /sparql HTTP/1.0" 200 3012 "" ""
]]></programlisting>
</listitem>
<listitem>The first request after midnight will open a new logfile, to make sure the logfile does not keep growing.
Old logfiles can be gzipped or removed by hand to conserve disk space.</listitem>
</orderedlist>
<para>The HTTP log files that Virtuoso produces can be processed by programs like
<ulink url="http://www.webalizer.org/">Webalizer</ulink> or
<ulink url="http://awstats.sourceforge.net/">AWstats</ulink> to accurately measure
site usage.
</para>
</sect3>
<sect3 id="loggingandrecordingrc">
<title>HTTP Recording</title>
<para>Virtuoso can also record the complete HTTP request for both GET and POST requests,
including all incoming headers, POST parameters etc. This is a very useful tool for debugging,
but it will cost performance and disk space, so it should not be left on for long periods of
time. Each request will be written to a separate file.
</para>
<para><emphasis>Note</emphasis>: Some filesystem types like ext2 and earlier versions of ext3
on Linux cannot handle huge amounts of files in a single directory without slowing down the whole
system.</para>
</sect3>
<sect4 id="loggingandrecordingrcexget">
<title>Example of a GET request</title>
<programlisting><![CDATA[
GET /sparql?query=DESCRIBE%20%3CnodeID%3A%2F%2Fb15481%3E&output=text%2Fcxml HTTP/1.1
Host: example.com
Connection: Keep-alive
Accept: */*
From: googlebot(at)googlebot.com
User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Accept-Encoding: gzip,deflate
]]></programlisting>
</sect4>
<sect4 id="loggingandrecordingrcexpost">
<title>Example of a POST request</title>
<programlisting><![CDATA[
POST /ods_services/Http/usersGetInfo HTTP/1.1
User-Agent: Opera/9.80 (Macintosh; Intel Mac OS X 10.5.8; U; en) Presto/2.9.168 Version/11.51
Host: example.com
Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif,
image/x-xbitmap, */*;q=0.1
Accept-Language: en,en-US;q=0.9,ja;q=0.8,fr;q=0.7,de;q=0.6,es;q=0.5,it;q=0.4,pt;q=0.3,pt-
PT;q=0.2,nl;q=0.1,sv;q=0.1,nb;q=0.1,da;q=0.1,fi;q=0.1,ru;q=0.1,pl;q=0.1,zh-CN;q=0.1,zh-TW;q=0.1,ko;q=0.1
Accept-Encoding: gzip, deflate
Referer: https://example.com/ods/
Cookie: interface=js; oatSecurityCookie=0123456878794576; sid=b3fae40reb78bc4babab3cb2a70fb111
Connection: Keep-Alive
Content-Length: 77
Content-Type: application/x-www-form-urlencoded
Authorization: Basic bnQacPPuhhxs
Content-Transfer-Encoding: binary
]]></programlisting>
</sect4>
<sect4 id="loggingandrecordingrcexenbr">
<title>Example Enabling recording</title>
<orderedlist>
<listitem>Go to the directory where the database is started from:
<programlisting><![CDATA[
mkdir sys_http_recording
chmod 777 sys_http_recording
]]></programlisting>
</listitem>
<listitem>Edit virtuoso.ini and set:
<programlisting><![CDATA[
[HTTPServer]
EnableRequestTrap = 1
]]></programlisting>
</listitem>
<listitem>Next connect with isql to your database and run the following commands:
<programlisting><![CDATA[
registry_set ('__save_http_history_on_disk', '1');
registry_set ('__save_http_history', '/');
]]></programlisting>
</listitem>
<listitem>Finally restart Virtuoso.</listitem>
<listitem>As result at this point every HTTP GET and POST request will be logged with
all the parameters, headers and settings.
</listitem>
</orderedlist>
</sect4>
<sect4 id="loggingandrecordingrcexdsbr">
<title>Example Disabling recording</title>
<orderedlist>
<listitem>To temporary disable the recordings, edit virtuoso.ini and set:
<programlisting><![CDATA[
[HTTPServer]
EnableRequestTrap = 0
]]></programlisting>
</listitem>
<listitem>Next you should remove the two registry items:
<programlisting><![CDATA[
registry_remove ('__save_http_history_on_disk');
registry_remove ('__save_http_history');
]]></programlisting>
</listitem>
<listitem>Finally restart Virtuoso.</listitem>
</orderedlist>
</sect4>
</sect2>
<sect2 id="rdfinsertcrawlingmethods">
<title>Quad Store Data Loading via Virtuoso's In-built Content Crawler?</title>
<para>This section covers the use of Virtuoso's in-built content crawler as a mechanism for
scheduled of one-off data loading operations for its native quad store.</para>
<para><emphasis>Why is this important?</emphasis></para>
<para>Transforming external data sources into Linked Data "on the fly" (e.g., via the 'Sponger')
is sufficient for many use cases, but there are times when the volume or sheer nature of a
data source makes batch-loading necessary. For example, Freebase offers RDF representations
of its data, but it doesn't publish RDF dumps; even if it did, such dumps would usually be
outdated by the time they were loaded. Thus, a scheduled crawl of that resource collection
offers a viable alternative.</para>
<para><emphasis>How to Set Up the Content Crawler for Linked Data generation and import</emphasis></para>
<para>The Virtuoso Conductor can be used to set up various Content Crawler Jobs:</para>
<itemizedlist mark="bullet">
<listitem><link linkend="rdfinsertmethodvirtuosocrawler">Setting up a Content Crawler Job to Import Linked Data into the Virtuoso Quad Store</link></listitem>
<listitem><link linkend="contentcrawlerrdfsm">Setting up a Content Crawler Job to Retrieve Sitemaps</link> (when the source includes RDFa) </listitem>
<listitem><link linkend="contentcrawlerrdfssm">Setting up a Content Crawler Job to Retrieve Semantic Sitemaps</link> (a variation of the standard sitemap)</listitem>
<listitem><link linkend="contentcrawlerrdfsd">Setting up a Content Crawler Job to Retrieve Content from Specific Directories</link></listitem>
<listitem><link linkend="contentcrawleratom">Setting up a Content Crawler Job to Retrieve Content from ATOM feed</link></listitem>
<listitem><link linkend="contentcrawlersparqlendp">Setting up a Content Crawler Job to Retrieve Content from SPARQL endpoint</link></listitem>
</itemizedlist>
</sect2>
<sect2 id="setshortenlongurisparam">
<title>What is the ShortenLongURIs Virtuoso configuration parameter?</title>
<para>The ShortenLongURIs parameter is a Virtuoso configuration setting to shorten extremely long
URIs in datasets when loading with the RDF Bulk Loader.</para>
<para>Some RDF datasets have long URIs that exceed the Virtuoso internal maximum size of 1900 bytes
and thus need to be shortened to avoid errors like:</para>
<programlisting><![CDATA[
"SR133: Can not set NULL to not nullable column 'DB.DBA.RDF_QUAD.S' (or .O, or .P)"
]]></programlisting>
<para>which has been seen loading some of the DBpedia 3.7 datasets, for example.</para>
<para>The Virtuoso ShortenLongURIs parameter needs to be set in the
<link linkend="ini_SPARQL">[SPARQL]</link> section of the Virtuoso configuration file
(virtuoso.ini by default) and restart the Virtuoso Server.
</para>
<programlisting><![CDATA[
[SPARQL]
.
.
.
ShortenLongURIs = 1
.
.
.
]]></programlisting>
<para><emphasis>Note</emphasis>: This parameter is only in the Virtuoso 06.03.3131+ commercial builds,
at the time of writing it is not included in the open source 6.1.4 archives but will be in the
next 6.1.5 release. A patch to enable this feature is however available from the
<ulink url="http://sourceforge.net/tracker/?func=detail&aid=3496331&group_id=161622&tid=820576">Virtuso patches page on source forge</ulink>, which can be applied to a 6.1.4 archive from source forge and the Virtuoso
server binary rebuilt.</para>
</sect2>
<sect2 id="soaprequestoversparqlendpoint">
<title>How Can I send SOAP requests to Virtuoso SPARQL Endpoint?</title>
<para>This section presents sample scenario how to execute SPARQL query in SOAP request over
Virtuoso SPARQL Endpoint.</para>
<orderedlist>
<listitem>Assume the following sample SOAP request containing simple SPARQL query:
<programlisting><![CDATA[
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<query-request xmlns="http://www.w3.org/2005/09/sparql-protocol-types/#">
<query xmlns="">SELECT DISTINCT ?z FROM virtrdf: {?x ?y ?z .} LIMIT 10</query>
</query-request>
</soapenv:Body>
</soapenv:Envelope>
]]></programlisting>
</listitem>
<listitem>Save locally the content from above for ex. to file with name "soap.xml".</listitem>
<listitem>To pass the SOAP request to a Virtuoso SPARQL Endpoint, execute the following curl command:
<programlisting><![CDATA[
$ curl -d@soap.xml -H "Content-Type:text/xml" -H "SOAPAction: ''" http://example.com/sparql
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<query-result xmlns="http://www.w3.org/2005/09/sparql-protocol-types/#">
<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="z"/>
</head>
<results distinct="false" ordered="true">
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadMapFormat</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadStorage</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapFormat</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadMap</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadMapValue</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapColumn</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadMapColumn</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#array-of-QuadMapATable</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadMapATable</uri>
</binding>
</result>
<result>
<binding name="z">
<uri>http://www.openlinksw.com/schemas/virtrdf#QuadMapFText</uri>
</binding>
</result>
</results>
</sparql>
</query-result>
</soapenv:Body>
</soapenv:Envelope>
]]></programlisting>
</listitem>
</orderedlist>
</sect2>
<sect2 id="howtodeleteblanknodes">
<title>How Can I Delete Triples containing blank nodes?</title>
<para>Please see details and sample scenario <link linkend="rdfsparulexamples24">here</link>.</para>
</sect2>
<sect2 id="howtogetfullexplainplanforsparqlquery">
<title>How Can I Get a full explain plan for a simple SPARQL query?</title>
<para>Please see details and sample scenario <link linkend="rdfperfcosttransanalyze">here</link>.</para>
</sect2>
<sect2 id="expressionsusage">
<title>How Can I Use Expressions inside CONSTRUCT, INSERT and DELETE {...} Templates?</title>
<para>Please examples <link linkend="rdfsparulexamples25">here</link>.</para>
</sect2>
<sect2 id="sparqldatediffindexfriendly">
<title>How to optimize bif:dateadd in SPARQL query using selective index-friendly filter?</title>
<sect3 id="sparqldatediffindexfriendlywhat">
<title>What?</title>
<para>Index-friendly filter for Date range ( bif:dateadd ) optimization within SPARQL query.</para>
</sect3>
<sect3 id="sparqldatediffindexfriendlywhy">
<title>Why?</title>
<para>Achieve fast results and better performance.</para>
</sect3>
<sect3 id="sparqldatediffindexfriendlyhow">
<title>How?</title>
<para>Assume the following SPARQL query:</para>
<programlisting><![CDATA[
SELECT ?wiki,
?dbp,
bif:datediff('second', xsd:DateTime(?extracted), now()) AS ?secondsAgo
FROM <http://nl.dbpedia.org>
WHERE
{
?wiki foaf:primaryTopic ?dbp .
?dbp dcterms:modified ?extracted .
FILTER ( bif:datediff('minute', now(), xsd:DateTime(?extracted)) <= 10 )
}
ORDER BY DESC(?extracted)
LIMIT 30
]]></programlisting>
<para>Let's take a look at the calculation of:</para>
<programlisting><![CDATA[
FILTER ( bif:datediff('minute', now(), xsd:DateTime(?extracted)) <= 10 ) .
]]></programlisting>
<para>For each "is modified" triple we:</para>
<orderedlist>
<listitem>Convert ?extracted to xsd:dateTime;</listitem>
<listitem>Calculate datediff;</listitem>
<listitem>Make a comparison and know whether we hit or miss 10 minutes interval</listitem>
</orderedlist>
<para>Written so, this will lead to a potentially long loop, because even if the optimizer will realize
that the filter is selective, it can't discover why is it so selective.</para>
<para>Now let's change the filter to: </para>
<programlisting><![CDATA[
FILTER ( ?extracted > bif:dateadd('minute', -10, now())) .
]]></programlisting>
<para><code>now()</code> can be calculated once at the very beginning of the query execution because it
does not depend on any rows in a given table. Then <code>bif:dateadd</code> has all arguments known and
thus the whole <code>bif:dateadd('minute', -10, now())</code> can be calculated only once and produce
some value. Therefor <code>FILTER ( ?extracted > some_known_value )</code> can be represented as a
single search step: look at index and get triples with known P, known G, O greater than the given one
and any S. That's pretty fast and predictable step, good for both optimizer and the runtime.</para>
<para>We can rephrase the query to filter index-friendly:</para>
<programlisting><![CDATA[
SELECT ?wiki,
?dbp,
bif:datediff('second', xsd:DateTime(?extracted) ,
now()) AS ?secondsAgo
FROM <http://nl.dbpedia.org>
WHERE
{
?wiki foaf:primaryTopic ?dbp .
?dbp dcterms:modified ?extracted .
FILTER ( ?extracted > bif:dateadd('minute', -10, now()))
}
ORDER BY DESC (?extracted)
LIMIT 30
]]></programlisting>
<para>In this case the presence or the absence of the order by does not matter too much, because the query
is way more straightforward: selective index-friendly filter first, and the selection could be ordered
naturally via hot index used by the filter.</para>
<para>Note also that if you know the datatype of an object literal, there's no need to write a cast like
xsd:dateTime --- it can make an expression index-unfriendly even if it will always return the argument
unchanged on your specific data.</para>
<orderedlist>
<listitem><ulink url="http://bit.ly/13xefMl">View the SPARQL Query Definition via SPARQL Protocol URL</ulink></listitem>
<listitem><ulink url="http://bit.ly/18rI9VA">View the SPARQL Query Results via SPARQL Protocol URL</ulink></listitem>
</orderedlist>
</sect3>
</sect2>
<sect2 id="determinedatausagetip">
<title>How can I Determine the data usage across a Virtuoso instance?</title>
<sect3 id="determinedatausagetipwhat">
<title>What?</title>
<para>How to determine the data usage across a Virtuoso instance.</para>
</sect3>
<sect3 id="determinedatausagetipwhy">
<title>Why?</title>
<para>There are times when a variety of DBMS activities (e.g., automated content crawling) can lead to
increase in database size, without the instance operator being fully aware of such activities and
their consequences.</para>
</sect3>
<sect3 id="determinedatausagetiphow">
<title>How?</title>
<para>Run the following statement:</para>
<programlisting><![CDATA[
SELECT TOP 20 * FROM sys_index_space_stats ORDER BY iss_pages DESC;
Query result:
ISS_KEY_TABLE ISS_KEY_NAME ISS_KEY_ID ISS_NROWS ISS_ROW_BYTES ISS_BLOB_PAGES ISS_ROW_PAGES ISS_PAGES
WS.WS.SYS_DAV_RES WS.WS.SYS_DAV_RE.. 492 630627 437635794 501049 57521 558570
DB.DBA.RDF_QUAD DB.DBA.RDF_QUAD 487 25134153 321502272 0 49779 49779
DB.DBA.RDF_QUAD RDF_QUAD_POGS 489 14749814 307163163 0 47191 47191
WS.WS.SYS_DAV_RES.... DB.DBA.RDF_OBJ 501 1139934 160445830 10748 21478 32226
WS.WS.SYS_DAV_RES WS.WS.SYS_DAV_RE.. 729 432 307124 28840 97 28937
DB.DBA.RDF_IRI DB.DBA.RDF_IRI 485 4378779 138542078 0 22479 22479
DB.DBA.RDF_IRI DB_DBA_RDF_IRI_UN.. 486 4259557 139496730 0 20187 20187
......
]]></programlisting>
</sect3>
</sect2>
<sect2 id="discoversparqlfedcapabtip">
<title>How to discover the capabilities of a SPARQL endpoint to enhancing SPARQL-FED usage from Virtuoso instances?</title>
<sect3 id="discoversparqlfedcapabtipwhat">
<title>What?</title>
<para>How to discover the capabilities of a SPARQL endpoint en route to enhancing SPARQL-FED usage from Virtuoso instances.</para>
</sect3>
<sect3 id="discoversparqlfedcapabtipwhy">
<title>Why?</title>
<para>There are features supported in Virtuoso SPARQL that aren't supported by other SPARQL engines.
There are also a lot of Virtuoso instances behind bubbles in the LOD cloud. Net effect, a Virtuoso
instance operator is faced with varied behavior when attempting to use SPARQL-FED functionality.</para>
</sect3>
<sect3 id="discoversparqlfedcapabtiphow">
<title>How?</title>
<para>Run this command to load metadata (or lack thereof) from an external SPARQL endpoint:</para>
<programlisting><![CDATA[
SPARQL LOAD SERVICE <{sparql-endpoint-iri> DATA
]]></programlisting>
<sect4 id="discoversparqlfedcapabtiphowex">
<title>Example</title>
<orderedlist>
<listitem>Run:
<programlisting><![CDATA[
Query result:
ANY
Load service <http://lod.openlinksw.com/sparql> data -- done.
Trying to query <http://lod.openlinksw.com/sparql> as SPARQL web service endpoint, POST mode...
]]></programlisting>
</listitem>
<listitem>Check the retrieved data:
<programlisting><![CDATA[
SPARQL
SELECT *
FROM virtrdf:
WHERE
{
<http://lod.openlinksw.com/sparql> ?p ?o
}
LIMIT 10
Query result:
p o
ANY ANY
http://www.openlinksw.com/schemas/virtrdf#isEndpointOfService http://lod.openlinksw.com/sparql-sd
http://www.openlinksw.com/schemas/virtrdf#dialect 000037ff
]]></programlisting>
</listitem>
</orderedlist>
</sect4>
</sect3>
</sect2>
<sect2 id="howtospliturlencodedlist">
<title>How to split a urlencoded ";-" separated list of urls in a SPARQL query?</title>
<orderedlist>
<listitem>Assume the following string: "http://example.org/test1;http://example.org/test2".</listitem>
<listitem>In order to split the given string into two values i.e. http://example.org/test1 and
http://example.org/test2 , one should use
<link linkend="fn_split_and_decode"><function>split_and_decode()</function></link> which returns an
array. Thus the <link linkend="fn_aref"><function>aref()</function></link> also needs to be used for
loading the elements.</listitem>
<listitem>Example:
<programlisting><![CDATA[
SELECT bif:aref (bif:split_and_decode('http%3A%2F%2Fexample.org%2Ftest1%3Bhttp%3A%2F%2Fexample.org%2Ftest2',0), 0)
{ ?S ?P ?O }
LIMIT 1
]]></programlisting>
<itemizedlist mark="bullet">
<listitem><ulink url="http://bit.ly/19eOiDE">View the SPARQL Query Definition via SPARQL Protocol URL</ulink>;</listitem>
<listitem><ulink url="http://bit.ly/18AgJS6">View the SPARQL Query Results via SPARQL Protocol URL</ulink></listitem>
</itemizedlist>
</listitem>
</orderedlist>
</sect2>
<sect2 id="howtoloadlargedatanocheckpointabort">
<title>How to Update Large SPARQL Data avoiding due to database checkpoint abortion?</title>
<para>Assume while performing large SPARQL update, for example of triples around 80 millions in total,
one gets the following error which aborts the update:
</para>
<programlisting><![CDATA[
"Transaction aborted due to a database checkpoint or database-wide
atomic operation. Please retry transaction" .
]]></programlisting>
<para>The error means that the SPARQL update has possibly encountered a database checkpoint during the
load. Thus one should check the CheckpointInterval in the INI file and possible increase its value:
</para>
<programlisting><![CDATA[
;
; Server parameters
;
[Parameters]
...
CheckpointInterval = 60
...
]]></programlisting>
<para>Note: The <ulink url="http://virtuoso.openlinksw.com/dataspace/dav/wiki/Main/VirtBulkRDFLoader">RDF Bulk loader</ulink>
can be used for loading large datasets, and it will handle the checkpoint matter automatically.
</para>
</sect2>
<sect2 id="howtomanagesslprotocolsandciphers">
<title>How to Manage SSL Protocols and Ciphers used with Virtuoso?</title>
<sect3 id="howtomanagesslprotocolsandcipherswhat">
<title>What?</title>
<para>As of Virtuoso 7.2, SSL protocol and cipher support is now configurable for connections from all HTTP, ODBC,
JDBC, ADO.NET, and OLE-DB clients.</para>
</sect3>
<sect3 id="howtomanagesslprotocolsandcipherswhy">
<title>Why?</title>
<para>Default binding to OpenSSL can expose Virtuoso instances to version- and cipher-specific SSL vulnerabilities
(e.g., recent <ulink url="http://security.stackexchange.com/questions/70719/ssl3-poodle-vulnerability">Poodle exploit</ulink>).
Being able to scope Virtuoso's use of SSL to one or more specific versions provides instance administrators better protection
against a moving target.</para>
</sect3>
<sect3 id="howtomanagesslprotocolsandciphershow">
<title>How?</title>
<sect4 id="howtomanagesslprotocolsandciphershowbasicc">
<title>Basic SSL Protocol Configuration</title>
<para>Basic configuration is through the <code>SSL_Protocols</code> values in the <code>[Parameters]</code> and
<code>[HTTP]</code> sections of the Virtuoso INI file. These are comma+space-separated (", ") value lists. Including a
protocol name explicitly enables it; preceding the protocol name with an exclamation point ("<code>!</code>")
explicitly disables it.</para>
<sect5 id="howtomanagesslprotocolsandciphershowbasiccss">
<title>Basic SSL Protocol Configuration</title>
<table colsep="1" frame="all" rowsep="0" shortentry="0" tocentry="1" tabstyle="decimalstyle" orient="land" pgwide="0">
<title>Supported SSL Protocols and INI keyword values List</title>
<tgroup align="char" charoff="50" char="." cols="3">
<colspec align="left" colnum="1" colsep="0" colwidth="20pc"/>
<thead>
<row>
<entry>SSL/TLS Version</entry>
<entry>Value for INI file</entry>
<entry>Notes</entry>
</row>
</thead>
<tbody>
<row>
<entry>SSLv2</entry>
<entry>-</entry>
<entry>Permanently disabled.</entry>
</row>
<row>
<entry>SSLv3</entry>
<entry><code>SSLv3</code></entry>
<entry>Disabled by default. To our knowledge, only required by IE6/Windows XP clients.</entry>
</row>
<row>
<entry>TLSv1</entry>
<entry><code>TLSv1</code></entry>
<entry>Enabled by default.</entry>
</row>
<row>
<entry>TLSv1.1</entry>
<entry><code>TLSv1.1</code></entry>
<entry>Enabled by default, supported if available in local <code>openssl</code> library.</entry>
</row>
<row>
<entry>TLSv1.2</entry>
<entry><code>TLSv1.2</code></entry>
<entry>Enabled by default, supported if available in local <code>openssl</code> library. </entry>
</row>
</tbody>
</tgroup>
</table>
</sect5>
</sect4>
<sect4 id="howtomanagesslprotocolsandciphershowbasica">
<title>Advanced SSL Cipher List Configuration</title>
<para>The <code>SSL_Cipher_List</code> values in the <code>[Parameters]</code> and <code>[HTTP]</code> stanzas of the
Virtuoso INI file may also be adjusted, to disable particular ciphers when there are security reports about some new
attack that breaks them. These are colon-separated ("<code>:</code>") value lists.</para>
<para>Including a protocol name or groupname explicitly enables it; preceding the protocol name with an exclamation point
("<code>!</code>") explicitly disables it. You can review the ciphers supported by your local <code>OpenSSL</code> library
with the command:</para>
<programlisting><![CDATA[
openssl ciphers -v ALL
]]></programlisting>
<para>For instance, we recommend explicitly forbidding anonymous cipher suites (i.e., ones that do not use certificates,
and are therefore susceptible to man-in-the-middle attacks) using <code>!aNULL</code>.</para>
<para>We also recommend including <code>@STRENGTH</code> at the end of the list, so that <code>OpenSSL</code> will
prioritize the enabled ciphers by key length, regardless of the list order.</para>
</sect4>
<sect4 id="howtomanagesslprotocolsandciphershowbasicr">
<title>Recommended Settings</title>
<para>The sample settings below provide a reasonable tradeoff of security versus flexibility. As shown, we have enabled
<code>SSLv3</code> on the HTTPS ports for IE6 users, but left this disabled on the SQL data port.</para>
<programlisting><![CDATA[
[Parameters]
SSL_Protocols = TLSv1, TLSv1.1, TLSv1.2
SSL_Cipher_List = HIGH:!aNULL:!eNULL:!RC4:!DES:!MD5:!PSK:!SRP:!KRB5:!SSLv2:!EXP:!MEDIUM:!LOW:!DES-CBC-SHA:@STRENGTH
[HTTP]
SSL_Protocols = SSLv3, TLSv1, TLSv1.1, TLSv1.2
SSL_Cipher_List = HIGH:!aNULL:!eNULL:!RC4:!DES:!MD5:!PSK:!SRP:!KRB5:!SSLv2:!EXP:!MEDIUM:!LOW:!DES-CBC-SHA:@STRENGTH
]]></programlisting>
</sect4>
</sect3>
</sect2>
</sect1>
</chapter>
|