Skip to content

Commit fe9f443

Browse files
author
Paula Gearon
committed
Final lab
1 parent 3d421c7 commit fe9f443

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

labs/lab6/deps.edn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{:paths ["src" "resources"]
2+
:deps {org.clojure/clojure {:mvn/version "1.11.2"} } }
3+

labs/lab6/src/lab6/indexed.clj

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
(ns lab6.indexed
2+
(:require [clojure.edn :as edn]
3+
[clojure.string :as str]))
4+
5+
(defn variable? [x] (and (symbol? x) (= \? (first (name x)))))
6+
7+
(def ? '?)
8+
(def x 'x)
9+
10+
(defn normalize [_ pattern] (mapv #(if (variable? %) ? x) pattern))
11+
12+
(defmulti get-from-index normalize)
13+
(defmethod get-from-index [x x x] [{idx :spo} [s p o]] (let [os (get-in idx [s p])] (if (get os o) [[]] [])))
14+
(defmethod get-from-index [x x ?] [{idx :spo} [s p o]] (map vector (keys (get-in idx [s p]))))
15+
(defmethod get-from-index [x ? x] [{idx :osp} [s p o]] (map vector (keys (get-in idx [o s]))))
16+
(defmethod get-from-index [x ? ?] [{idx :spo} [s p o]] (let [edx (idx s)] (for [[p om] edx o (keys om)] [p o])))
17+
(defmethod get-from-index [? x x] [{idx :pos} [s p o]] (map vector (keys (get-in idx [p o]))))
18+
(defmethod get-from-index [? x ?] [{idx :pos} [s p o]] (let [edx (idx p)] (for [[o sm] edx s (keys sm)] [s o])))
19+
(defmethod get-from-index [? ? x] [{idx :osp} [s p o]] (let [edx (idx o)] (for [[s pm] edx p (keys pm)] [s p])))
20+
(defmethod get-from-index [? ? ?] [{idx :spo} [s p o]] (for [[s pom] idx [p om] pom o (keys om)] [s p o]))
21+
22+
(defn add-to-index
23+
[index [_ _ c :as triple]]
24+
(assoc-in index triple c))
25+
26+
(defprotocol Index
27+
(add [this triple])
28+
(match [this pattern]))
29+
30+
(defrecord IndexedGraph [spo pos osp]
31+
Index
32+
(add [this [s p o :as triple]]
33+
(IndexedGraph. (add-to-index spo triple)
34+
(add-to-index pos [p o s])
35+
(add-to-index osp [o s p])))
36+
(match [this pattern]
37+
{:vars (vec (filter variable? pattern))
38+
:bindings (get-from-index this pattern)}))
39+
40+
(defn load-data
41+
[filename]
42+
(let [data (edn/read-string (slurp filename))]
43+
(reduce add (IndexedGraph. {} {} {}) data)))
44+
45+
(defn export-data
46+
[filename data]
47+
(let [triples (:bindings (match data '[?s ?p ?o]))]
48+
(spit filename (pr-str (vec triples)))))
49+
50+
(defn do-filter
51+
[match-result filter-expr]
52+
(let [vars (:vars match-result)
53+
data (:bindings match-result)
54+
fltr (first filter-expr)
55+
filter-fn (eval `(fn [~vars] ~fltr))]
56+
{:vars vars
57+
:bindings (filter filter-fn data)}))
58+
59+
(defn rewrite-pattern
60+
[vars binding-data pattern]
61+
(let [binding-map (zipmap vars binding-data)]
62+
(mapv #(if (variable? %) (get binding-map % %) %) pattern)))
63+
64+
(defn join
65+
[graph part-result pattern]
66+
(let [vars (:vars part-result)
67+
new-vars (->> pattern
68+
(filter variable?)
69+
(remove (set vars)))
70+
result (for [binding (:bindings part-result)
71+
new-values (:bindings (match graph (rewrite-pattern vars binding pattern)))]
72+
(vec (concat binding new-values)))]
73+
{:vars (vec (concat vars new-vars))
74+
:bindings result}))
75+
76+
(defn project
77+
[selected-vars result]
78+
(->> (:bindings result)
79+
(map #(zipmap (:vars result) %))
80+
(map #(select-keys % selected-vars))))
81+
82+
(defn step
83+
[graph part-result pattern]
84+
(when-not (vector? pattern)
85+
(throw (ex-info "Pattern must be a vector" {:pattern pattern})))
86+
(if (list? (first pattern))
87+
(do-filter part-result pattern)
88+
(join graph part-result pattern)))
89+
90+
(def identity-binding {:vars [] :bindings [[]]})
91+
92+
(defn query->map
93+
"Takes a string, seq, or map, and returns a map of :find and :where"
94+
[query]
95+
(let [query (if (string? query) (edn/read-string query) query)]
96+
(if (map? query)
97+
query
98+
(let [find-clause (take-while #(not= :where %) query)
99+
where-clause (drop-while #(not= :where %) query)]
100+
(when (or (not= :find (first find-clause))
101+
(not= :where (first where-clause)))
102+
(throw (ex-info "Query must start with :find and :where" {:query query})))
103+
{:find (rest find-clause)
104+
:where (rest where-clause)}))))
105+
106+
(defn q
107+
[query graph]
108+
(let [{:keys [find where]} (query->map query)]
109+
(->> (reduce (partial step graph) identity-binding where)
110+
(project find))))
111+
112+
(comment
113+
;; Load the starwars graph
114+
(def data (load-data "../../graphs/starwars.edn"))
115+
116+
;; [:find ?name ?color :where [?character :name ?name] [?character :color ?color] [(str/starts-with ?name "Darth")]]
117+
(def name-pattern '[?character :name ?name])
118+
(def color-pattern '[?character :color ?color])
119+
(def filter-pattern '[(str/starts-with? ?name "Darth")])
120+
(def first-step (join data identity-binding name-pattern))
121+
(def second-step (join data first-step color-pattern))
122+
(def last-step (do-filter second-step filter-pattern))
123+
(project '[?name ?color] last-step)
124+
125+
(def name-color-query '[:find ?name ?color
126+
:where [?character :name ?name]
127+
[?character :color ?color]
128+
[(str/starts-with? ?name "Darth")]])
129+
130+
(q name-color-query data)
131+
)

0 commit comments

Comments
 (0)