;; load up agraph (require :agraph) ;; use the agraph user package (in-package :db.agraph.user) ;; some prolog fu ;; heh. jim rulz (<-- (rulz jim)) ;; who rulz? jim rulz! (?- (rulz ?x)) ;; add some facts to the "database" - Lisp & Scheme are awesome ;; Java, C++, and Fortran all suck! (<-- (awesome lisp)) (<- (awesome scheme)) (<-- (suck java)) (<- (suck c++)) (<- (suck fortran)) ;; query our "database" for awesome languages (?- (awesome ?x)) ;; query our "database" for not so awesome languages (?- (suck ?x)) ;; add some real ARTIFICIAL INTELLIGENCE! If you're not in the awesome club, ;; then you suck! (<- (suck ?x) (not (awesome ?x))) ;; does intercal suck? (?- (suck intercal)) ;; of course ;; obviously, Prolog is a complete programming language thats just a taste to ;; get us started ;; Franz' implementation of prolog claims to compare well with other commercial ;; implementations of prolog YMMV. ;; lets play with the triple store! (open-triple-store "ABQLispScheme-Demo" :if-does-not-exist :create :if-exists :supersede) ;; show off the empty triple store (serialize-rdf/xml (get-triples) t) ;; register an XML namespace, shorthand is foo (register-namespace "foo" "http://foo.hpc.unm.edu/") ;; now we have a namespace pointing foo -> http://foo.hpc.unm.edu/ (serialize-rdf/xml (get-triples) t) ;; show how this is expanded into a URI for us !foo: !foo:is !foo:bar/baz/quux ;; resources, literals become UPIs (setf *foo-resource* (intern-resource "foo")) (setf *foo-literal* (intern-literal "foo")) ;; UPIs become values (upi->value *foo-resource*) (upi->value *foo-literal*) (setf *big* (make-string 1024 :initial-element #\a)) (setf *big-literal* (intern-literal *big*)) (length (upi->value *big-literal*)) ;; add some triples (add-triple (intern-resource "Lisp") !foo:is (intern-literal "good")) (add-triple (intern-resource "Scheme") !foo:is (intern-literal "good")) ;; now we've gt some stuff in the db (serialize-rdf/xml (get-triples) t) ;; more truth! (add-triple (intern-resource "Java") !foo:is (intern-literal "bad")) (add-triple (intern-resource "C++") !foo:is (intern-literal "bad")) (add-triple (intern-resource "Fortran") !foo:is (intern-literal "bad")) (add-triple (intern-resource "C" !foo:descendant (intern-resource "Algol"))) (add-triple (intern-resource "C++") !foo:descendant (intern-resource "C")) ;; query the database for what we've asserted about these languages ;; we're only interested in things with the !foo:is predicate (let ((*print-pretty* NIL)) (prolog (q ?lang !foo:is ?state) (lisp! (format t "~A is ~A~%" ?lang ?state))) ) ;; ok, thats ugly! (prolog (q ?lang !foo:is ?state) (lisp! (format t "~A is ~A~%" (upi->value ?lang) (upi->value ?state)))) ;; just the good ones (prolog (lisp ?state (intern-literal "good")) (q ?lang !foo:is ?state) (lisp! (format t "~A is ~A~%" (upi->value ?lang) (upi->value ?state)))) ;; you can just put random stuff in the database (add-triple (intern-resource "Jim") !foo:phone-number (intern-literal "505.277.8210")) (setf *jim* (intern-resource "Jim")) (add-triple *jim* !foo:job-title (intern-literal "High Performance Computing Systems Engineer III")) (add-triple *jim* !foo:beverage (intern-literal "coffee")) (add-triple *jim* !foo:office (intern-literal "G101D")) (setf *dan* (intern-resource "Dan")) (setf *cy* (intern-resource "Chun-Yu")) (add-triple *dan* !foo:phone-number (intern-literal "505.277.8249")) (add-triple *cy* !foo:phone-number (intern-literal "505.277.8339")) (add-triple *jim* !foo:works-with *dan*) (add-triple *jim* !foo:works-with *cy*) (add-triple *dan* !foo:works-with *jim*) ;; what are all of the triples with the subject "Jim"? (get-triples-list :s *jim*) ;; print them in a somewhat readable format (print-triples (get-triples-list :s *jim*)) ;; lets write our own print-triples (map-cursor NIL (lambda (triple) (format t "s: ~A p: ~A o: ~A~%" (upi->value (subject triple)) (upi->value (predicate triple)) (upi->value (object triple)))) (get-triples :s *jim*)) ;; what are the phone numbers of the folks that work with Jim? (select (?name ?number) ;; bind the variable ?jim to the resource "Jim" (lisp ?jim (intern-resource "Jim")) ;; look for the names of folks that work with Jim (q ?jim !foo:works-with ?name) ;; look for the phone numbers of those people (q ?name !foo:phone-number ?number)) ;; Note that this query is equivalent, but, generally much slower ;; our DB doesn't have much in it yet, so they won't be significantly different ;; ... yet ;; here we find everyone's phone number, then filter out those that ;; don't work with jim. Above we find everyone that works with jim, then ;; find their phone numbers. (select (?name ?number) ;; bind the variable ?jim to the resource "Jim" (lisp ?jim (intern-resource "Jim")) ;; look for the phone numbers of all people (q ?name !foo:phone-number ?number) ;; from those people with phone numbers, find those that work with Jim (q ?jim !foo:works-with ?name) ) (register-namespace "machine" "http://machines.hpc.unm.edu/") (add-triple (intern-resource "nox.hpc.unm.edu") !foo:is !machine:desktop) (add-triple (intern-resource "nox.hpc.unm.edu") !machine:ip (intern-literal "129.24.244.72")) (add-triple (intern-resource "nox.hpc.unm.edu") !machine:os (intern-literal "FreeBSD")) (add-triple (intern-resource "www.hpc.unm.edu") !foo:is !machine:server) (add-triple (intern-resource "www.hpc.unm.edu") !machine:ip (intern-literal "129.24.244.30")) (add-triple (intern-resource "www.hpc.unm.edu") !machine:os (intern-literal "Linux")) (add-triple (intern-resource "pequena.alliance.unm.edu") !foo:is !machine:cluster) (add-triple (intern-resource "pequena.alliance.unm.edu") !machine:ip (intern-literal "129.24.243.1")) (add-triple (intern-resource "pequena.alliance.unm.edu") !machine:os (intern-literal "Linux")) (loop for i from 1 to 128 do (let ((host (intern-resource (format NIL "dhcp~A.hpc.unm.edu" i))) (ip (intern-literal (format NIL "129.24.247.~A" i)))) (add-triple host !foo:is !machine:desktop) (add-triple host !machine:ip ip) (add-triple host !machine:os !machine:unknown))) (loop for i from 1 to 128 do (let ((host (intern-resource (format NIL "rcde~A.hpc.unm.edu" i))) (ip (intern-literal (format NIL "129.24.246.~A" i)))) (add-triple host !foo:is !machine:desktop) (add-triple host !machine:ip ip) (add-triple host !machine:os (intern-literal "Linux")))) ;; find the IP addresses of hosts running Linux (time (select ?ip (lisp ?linux (intern-literal "Linux")) (q ?host !machine:os ?linux) (q ?host !machine:ip ?ip))) ;; why was that so slow? (indexing-needed-p) (index-all-triples) (time (select ?ip (lisp ?linux (intern-literal "Linux")) (q ?host !machine:os ?linux) (q ?host !machine:ip ?ip))) ;; that was better (time (select ?ip (lisp ?linux (intern-literal "Linux")) (q ?host !machine:os ?linux) (q ?host !foo:is !machine:server) (q ?host !machine:ip ?ip))) ;; whats in our database? (serialize-rdf/xml (get-triples) t) ;; lets look at a subset of that, how about just Jim's stuff (serialize-rdf/xml (get-triples :s (intern-resource "Jim")) t) ;; triples aren't really triples... ;; triples are quints ;; triples also have a "graph" slot ;; you can use this for whatever, its not really a part of an RDF graph ;; The W3C proposal is to use the g or 'named-graph' slot for clustering triples (add-triple (intern-resource "Jim") !foo:member (intern-literal "ABQLispScheme") :g (intern-literal "organizations")) ;; print out the "organizations" triples (print-triples (get-triples :g (intern-literal "organizations"))) ;; they also have an ID slot so we can make triples that refer to other ;; triples ;; above we did: ;; (add-triple (intern-resource "Lisp") !foo:is (intern-literal "good")) (get-triple :s (intern-resource "Lisp") :p !foo:is :o (intern-literal "good")) (setf *id* (triple-id (get-triple :s (intern-resource "Lisp") :p !foo:is :o (intern-literal "good")))) (add-triple (intern-resource "Jim") !foo:believes (value->upi *id* :triple-id)) (setf *g* (intern-literal "users-graph")) ;; make an RDF Seq (list) of users for our DB (add-triple !foo:userlist !rdf:type !rdf:Bag :g *g*) (add-triple !foo:userlist !rdf:li (intern-literal "Jim") :g *g*) (add-triple !foo:userlist !rdf:li (intern-literal "Jane") :g *g*) (add-triple !foo:userlist !rdf:li (intern-literal "Bill") :g *g*) (add-triple !foo:userlist !rdf:li (intern-literal "Susie") :g *g*) (add-triple !foo:userlist !rdf:li (intern-literal "Sam") :g *g*) (add-triple !foo:userlist !rdf:li (intern-literal "Eve") :g *g*) (add-triple (value->upi (triple-id (get-triple :s !foo:userlist :p !rdf:li :o (intern-literal "Jim") :g *g*)) :triple-id) !foo:password (intern-literal "SuP3RSeEkr@t")) (defun check-password (user pass)> (select ?id (lisp ?user (intern-literal user)) (lisp ?id (value->upi (triple-id (get-triple :s !foo:userlist :p !rdf:li :o ?user :g *g*)) :triple-id)) (lisp ?pass (intern-literal pass)) (q ?id !foo:password ?pass))) (check-password "Jim" "foo") (check-password "Jim" "SuP3RSeEkr@t") (check-password "Foo" "SuP3RSeEkr@t")