[ Team LiB ] |
15.2 RDF Gateway, a Commercial RDF DatabaseRDF Gateway is a database and integrated web server, utilizing RDF, and built from the ground up rather than on top of either an existing web server (such as Apache) or database (such as SQL Server or MySQL). At this time, it works only within the Windows environment, specifically Windows NT 4.0, 2000, or XP. The installation is extremely easy; I was able to download, install, and run the application in less than five minutes.
RDF Gateway is an application server providing web page template support similar to ASP or JSP. This includes data storage, support for a scriptlike data query language, and web services. Aside from the use of RDF, all aspects of the tool are proprietary, though many are based on current open source efforts, including the RDF parser associated with Redland (discussed in Chapter 11). Once installed, an RDF Gateway icon is added to the system tray. Right-clicking on this opens a menu that can be used to start or stop the server or to open a properties window with information about the Gateway, such as port, database location, and so on. The properties page is informational only—unless there's a problem with the server, these settings shouldn't need to be changed. The Gateway can be managed through an online interface, where you can do things such as add or remove users from access to the repository, as shown in Figure 15-1. Figure 15-1. Adding a new user for RDF GatewayYou can also view the data tables used for the RDF Gateway repository or add COM objects, web services, packages, and so on. These externally created extensions to the Gateway can then be accessed through the scripting language supported by the product: RDFQL, an ECMAScript-based scripting language. RDFQL is used within RDF Server Pages (RSP) similarly to how Java is used in JSP and VBScript in ASP. As do these embedded scripting page approaches, RDFQL supports several built-in and global objects to facilitate application development. Among the objects supported with the released version of RDF Gateway are:
There are other objects such as strings, enumerators, and so on, but this listing gives you an idea of the built-in capability associated with RDFQL. Example 15-1 is a simple RSP that does nothing more than read an external RDF/XML page into a DataSource object and then use that object's formatting capability to print the RDF/XML out to the page. Example 15-1. Reading in and writing out remote RDF/XML document<% // Create an in-memory data source // connect to remote RDF/XML document using the Inet data service var monsters = new DataSource("inet?url=http://burningbird.net/articles/monsters1. rdf&parsetype=rdf"); //set the content type Response.ContentType = "text/xml"; //use the Format command on the datasource to generate an rdf+xml representation of the //contents of the datasource Response.Write(monsters.Format('application/rdf+xml')); %> As you can see from the example, scripting blocks are separated from the rest of the page with angle bracket/percent sign enclosures. RDF Gateway can be extended through the use of COM/COM+ objects, as well as through Gateway packages, which are distinct applications or libraries of functions, which can be used in any of the Gateway-managed pages. In addition, the underlying data repository for RDF Gateway can be accessed directly through JDBC from within Java applications and through ADO if you're programming Windows-based applications. RDFCLI, a Win32 library, also provides the fastest and most direct access to the RDF Gateway services. At first glance RDF Gateway appears similar to IIS/COM+ and other application/web servers of similar make, until you take a closer glance at the data queries. This is where the product's RDF roots shine through. I pulled an example of how data manipulation can work with RDF Gateway from the help files included with the application. Example 15-2 shows how to create and insert RDF statements into an in-memory data source and then how to print select predicate values out. Example 15-2. Creating and then querying RDF data within memory datastorefoaf = new DataSource( ); INSERT {[http://www.w3.org/1999/02/22-rdf-syntax-ns#type] [mailto:[email protected]] [http://xmlns.com/foaf/0.1/Person]} {[http://xmlns.com/foaf/0.1/firstName] [mailto:[email protected]] "Derrish"} {[http://xmlns.com/foaf/0.1/knows] [mailto:[email protected]] [mailto:[email protected]]} {[http://www.w3.org/1999/02/22-rdf-syntax-ns#type] [mailto:[email protected]] [http://xmlns.com/foaf/0.1/Person]} {[http://xmlns.com/foaf/0.1/firstName] [mailto:[email protected]] "Geoff"} {[http://xmlns.com/foaf/0.1/knows] [mailto:[email protected]] [mailto:[email protected]]} INTO #foaf; var ary = foaf.getObjects( ); for (var i = 0; i < ary.length; i++) { dumpPerson(ary[i]); } function dumpPerson(node) { var s = node["http://xmlns.com/foaf/0.1/firstName"]; var ary = node["http://xmlns.com/foaf/0.1/knows"]; if (ary != null) { s += " -> "; for (var i = 0; i < ary.length; i++) { if (i > 0) s += ", "; s += ary[i]["http://xmlns.com/foaf/0.1/firstName"]; } } Response.write(s); } After exposure to RDQL in Chapter 10, the insert statements based on an RDF triple in the first part of the code should be relatively familiar. Once the data's added to the store, the second part of the code example accesses the firstName property for both the FOAF resource, as well as all the resources that map to the knows predicate, resulting in an output of: Derrish -> Geoff Geoff -> Derrish RDF Gateway also provides the ability to query against multiple datastores, merging the results as appropriate. For instance, you can access data from three different data sources with a query such as the following: select ?p ?s ?o using #ds1, #ds2, #ds3 where {?p ?s ?o}; RDF Gateway also includes strong inferential support through two types of rules: statement and function. These allow incorporation of process logic within the semantics of the more traditional query. Again, using examples from the help file for the Gateway product, a statement rule would be like the following: INFER {[acme:size] ?product_id "big"} FROM {[itd:size] ?product_id "large"} OR {[itd:size] ?product_id "x-large"}; That's a lot of strange syntax, but what this statement is really saying is that there is a rule, {[acme:size] ?product_id "big"}, that is true if the body, {[itd:size] ?product_id "large"} OR {[itd:size] ?product_id "x-large"}, evaluates to true, and which can then be used within an RDFQL query as follows: SELECT ?acme_size FROM inventory WHERE {[acme:size] ?product_id ?acme_size}; The use of an inferential rule allows you to map one type of schema on to another and to then use these within the queries. How rules work becomes even more apparent when one looks at a function rule, such as the following: INFER GetLeadTime(?product_id, ?lead_time) FROM {[itd:assembly_time] ?product_id ?assembly_time} AND SWITCH ( case {[itd:component] ?product_id ?component_id}: GetLeadTime(?component_id, ?lead_time_comp) AND ?lead_time = ADD(?lead_time_comp, ?assembly_time) default: ?lead_time = ?assembly_time ) Using this function rule within a query, such as the following, returns the lead time for large products. However, within the rule itself, the actual lead time is accumulated from summing all lead times for the individual components that make up the part: SELECT ?lead_time USING inventory WHERE {[itd:size] ?product_id "large"} AND GetLeadTime(?product_id, ?lead_time); Learning to work with the inferential engine of RDF Gateway isn't trivial, but the potential of encapsulating complex logic into a form that can be used and reused within queries has considerable appeal. To enable this encapsulation, RDF Gateway provides support for a rulebase, a set of RDFQL rules that can be included within a query. Redefining the function statement into a rulebase would be as follows: rulebase app_rules { // ITD size to Acme size mapping rule INFER {[acme:size] ?product_id "big"} FROM {[itd:size] ?product_id 'large'} OR {[itd:size] ?product_id "x-large"}; // Lead time function rule INFER GetLeadTime(?product_id, ?lead_time) FROM {[itd:assembly_time] ?product_id ?assembly_time} AND SWITCH { case {[itd:component] ?product_id ?component_id}: getLeadTime(?component_id, ?lead_time) AND ?lead_time = ADD(?lead_time, ?assembly_time) default: ?lead_time = ?assembly_time }; }; The rulebase would then be used in a query in the following manner: SELECT ?product_id USING inventory RULEBASE NONE WHERE {[itd:size] ?product_id "big"}; It is this inferential engine support, in addition to the RDF/XML base, that makes RDF Gateway unique among application servers. |
[ Team LiB ] |