-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathexample.lisp
152 lines (126 loc) · 4.24 KB
/
example.lisp
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
(ql:quickload :graph-db)
(in-package :graph-db)
(defvar *graph-name* :test-graph)
(defvar *graph-path* "/var/tmp/test-graph/")
(log:config :all :sane :d :nopretty :thread :daily "/var/tmp/graph.log")
;;; Types
(defun email-p (x)
(and (stringp x)
(find #\@ x)
x))
(deftype email () `(satisfies email-p))
;;; Schema
(def-vertex person ()
((first-name :type string)
(middle-name :type string)
(last-name :type string))
:test-graph)
(def-vertex customer (person)
((email :type email))
:test-graph)
(def-vertex product ()
((name :type string)
(upc :type string))
:test-graph)
(def-vertex merchant ()
((name :type string))
:test-graph)
(def-edge likes ()
()
:test-graph)
(def-edge sells ()
()
:test-graph)
(setq *graph* (make-graph *graph-name* *graph-path* :buffer-pool-size 10000))
;;; Indexes
;; This will index both customers and people
(def-view last-name :lessp (person :test-graph)
(:map
(lambda (person)
(when (slot-value person 'last-name)
(yield (slot-value person 'last-name) nil)))))
;; This will only index customers
(def-view email :lessp (customer :test-graph)
(:map
(lambda (customer)
(when (slot-value customer 'email)
(yield (slot-value customer 'email) nil)))))
;; Example of a map-reduce view
(def-view popularity :greaterp (likes :test-graph)
(:map
(lambda (like-edge)
(yield (string-id (to like-edge)) 1)))
(:reduce
(lambda (keys values)
(declare (ignore keys))
(apply '+ values))))
(defun lookup-people-by-last-name (last-name)
(let ((people (invoke-graph-view 'person 'last-name :key last-name)))
(if people
(mapcar (lambda (person)
(lookup-vertex (cdr (assoc :id person))))
people)
nil)))
(defun lookup-customer-by-email (email)
(let ((customers (invoke-graph-view 'customer 'email :key email)))
(if customers
(lookup-vertex (cdr (assoc :id (first customers))))
nil)))
;;; Add some data
(with-transaction ()
(let ((c1 (make-customer :first-name "Joe" :last-name "Blow" :email "[email protected]"))
(c2 (make-customer :first-name "Jill" :last-name "Blow" :email "[email protected]"))
(m1 (make-merchant :name "Snake Oil, Inc."))
(p1 (make-product :name "Oil of Longevity" :upc "1234567890"))
(p2 (make-product :name "Oil of Slipperiness" :upc "abcdefghijk")))
(make-sells :from m1 :to p1)
;; The above is equivalent to
;; (make-edge 'sells m1 p1 1 nil)
(make-sells :from m1 :to p2)
(make-likes :from c1 :to p1 :weight 100.0)
(make-likes :from c1 :to p2 :weight 20.0)
(make-likes :from c2 :to p2 :weight 50.0)))
;;; Now run some queries
(lookup-customer-by-email "[email protected]")
(lookup-people-by-last-name "Blow")
(select (:flat nil)
(?liker ?product)
(likes ?liker ?product))
(select (:flat nil :limit 1 :skip 0)
(?liker ?product ?how-much)
(likes ?liker ?product ?how-much))
(select-flat (?customer) (is-a ?customer customer))
(let ((person (select-one (?person) (is-a ?person person))))
(declare (special person))
(destructuring-bind (product like-qty)
(select (:flat t :limit 1 :skip 0)
(?product ?like-qty)
(lisp ?person person) ;; Import the person into Prolog
(likes ?person ?product ?like-qty))
(format nil "~A likes '~A' with a degree of ~F"
(slot-value person 'first-name)
(slot-value product 'name)
like-qty)))
(map-reduced-view (lambda (key id value)
(declare (ignore id))
(let ((product (lookup-vertex key)))
(cons product value)))
'likes
'popularity
:collect-p t)
(map-vertices (lambda (person)
(format t "~A is a person~%" person)
person)
*graph*
:collect-p t
:vertex-type 'person)
(map-edges (lambda (edge)
(let ((how-much (weight edge))
(product (lookup-vertex (to edge))))
(cons product how-much)))
*graph*
:collect-p t
:edge-type 'likes
:vertex (lookup-customer-by-email "[email protected]")
:direction :out)
(close-graph *graph*)