Get Logical with Datalog Stuart Halloway Datomic Team, Clojure/core, Relevance 1
https://github.com/clojure/core.logic https://github.com/nathanmarz/cascalog http://datomic.com/ 2
Roadmap • How • Why • Bonus Round • problem / solution form 3
Query Anatomy q([:find ... :in ... :where ...], input1, ... inputN); 4
Query Anatomy constraints q([:find ... :in ... :where ...], input1, ... inputN); 5
Query Anatomy q([:find ... :in ... :where ...], input1, ... inputs inputN); 6
Query Anatomy q([:find ... names for :in ... inputs :where ...], input1, ... inputN); 7
Query Anatomy q([:find ... :in ... variables to return :where ...], input1, ... inputN); 8
Variables ?customer ?product ?orderId ?email 9
Constants :email 42 “john” :order/id #inst "2012-02-29" 10
Keywords :email 42 “john” :order/id #inst "2012-02-29" 11
Namespaces :email 42 “john” :order/id #inst "2012-02-29" 12
Extensible Reader :email 42 “john” :order/id #inst "2012-02-29" 13
Example Database entity attribute value 42 :email jdoe@example.com 43 :email jane@example.com 42 :orders 107 42 :orders 141 14
Data Pattern Constrains the results returned, binds variables [?customer :email ?email] 15
Data Pattern Constrains the results returned, binds variables [?customer :email ?email] value entity attribute 16
Data Pattern Constrains the results returned, binds variables constant [?customer :email ?email] 17
Data Pattern Constrains the results returned, binds variables variable variable [?customer :email ?email] 18
entity attribute value 42 :email jdoe@example.com 43 :email jane@example.com 42 :orders 107 42 :orders 141 [?customer :email ?email] 19
Constants Anywhere “Find a particular customer’s email” [ 42 :email ?email] 20
entity attribute value 42 :email jdoe@example.com 43 :email jane@example.com 42 :orders 107 42 :orders 141 [ 42 :email ?email] 21
Variables Anywhere “What attributes does customer 42 have? [42 ?attribute ] 22
entity attribute value 42 :email jdoe@example.com 43 :email jane@example.com 42 :orders 107 42 :orders 141 [42 ?attribute ] 23
Variables Anywhere “What attributes and values does customer 42 have? [42 ?attribute ?value ] 24
entity attribute value 42 :email jdoe@example.com 43 :email jane@example.com 42 :orders 107 42 :orders 141 [42 ?attribute ?value] 25
Where Clause data pattern [:find ?customer :where [?customer :email] ] 26
Find Clause variable to return [:find ?customer :where [?customer :email]] 27
Implicit Join “Find all the customers who have placed orders.” [:find ?customer :where [ ?customer :email] [ ?customer :orders]] 28
API import static datomic.Peer.q; q("[:find ?customer :where [?customer :id] [?customer :orders]]", db); 29
q import static datomic.Peer.q ; q ("[:find ?customer :where [?customer :id] [?customer :orders]]", db); 30
Query import static datomic.Peer.q; q(" [:find ?customer :where [?customer :id] [?customer :orders]] ", db); 31
Input(s) import static datomic.Peer.q; q("[:find ?customer :where [?customer :id] [?customer :orders]]", db ); 32
In Clause Names inputs so you can refer to them elsewhere in the query :in $database ?email 33
Parameterized Query “Find a customer by email.” q([:find ?customer :in $database ?email :where [$database ?customer :email ?email]], db, "jdoe@example.com"); 34
First Input “Find a customer by email.” q([:find ?customer :in $database ?email :where [ $database ?customer :email ?email]], db , "jdoe@example.com"); 35
Second Input “Find a customer by email.” q([:find ?customer :in $database ?email :where [$database ?customer :email ?email ]], db, "jdoe@example.com" ); 36
Verbose? “Find a customer by email.” q([:find ?customer :in $database ?email :where [ $database ?customer :email ?email]], db , "jdoe@example.com"); 37
Shortest Name Possible “Find a customer by email.” q([:find ?customer :in $ ?email :where [ $ ?customer :email ?email]], db , "jdoe@example.com"); 38
Elide $ in Where “Find a customer by email.” q([:find ?customer :in $ ?email :where [ ?customer :email ?email]], db, "jdoe@example.com"); no need to specify $ 39
Predicates Functional constraints that can appear in a :where clause [(< 50 ?price)] 40
Adding a Predicate “Find the expensive items” [:find ?item :where [?item :item/price ?price] [ (< 50 ?price) ]] 41
Functions Take bound variables as inputs and bind variables with output [(shipping ?zip ?weight) ?cost] 42
Function Args [(shipping ?zip ?weight ) ?cost] bound inputs 43
Function Returns [(shipping ?zip ?weight) ?cost ] bind return values 44
Calling a Function “Find me the customer/product combinations where the shipping cost dominates the product cost.” [:find ?customer ?product :where [?customer :shipAddress ?addr] [?addr :zip ?zip] [?product :product/weight ?weight] [?product :product/price ?price] [(Shipping/estimate ?zip ?weight) ?shipCost] [(<= ?price ?shipCost)]] 45
Calling a Function “Find me the customer/product combinations where the shipping cost dominates the product cost.” navigate from customer to zip [:find ?customer ?product :where [ ?customer :shipAddress ?addr] [?addr :zip ?zip ] [?product :product/weight ?weight] [?product :product/price ?price] [(Shipping/estimate ?zip ?weight) ?shipCost] [(<= ?price ?shipCost)]] 46
Calling a Function “Find me the customer/product combinations where the shipping cost dominates the product cost.” get product facts [:find ?customer ?product needed during query :where [?customer :shipAddress ?addr] [?addr :zip ?zip] [?product :product/weight ?weight] [?product :product/price ?price] [(Shipping/estimate ?zip ?weight) ?shipCost] [(<= ?price ?shipCost)]] 47
Calling a Function “Find me the customer/product combinations where the shipping cost dominates the product cost.” call web service [:find ?customer ?product to bind shipCost :where [?customer :shipAddress ?addr] [?addr :zip ?zip] [?product :product/weight ?weight] [?product :product/price ?price] [(Shipping/estimate ?zip ?weight) ?shipCost] [(<= ?price ?shipCost)]] 48
BYO Functions Functions can be plain JVM code. public class Shipping { public static BigDecimal estimate(String zip1, int pounds); } 49
Calling a Function “Find me the customer/product combinations where the shipping cost dominates the product cost.” [:find ?customer ?product :where [?customer :shipAddress ?addr] [?addr :zip ?zip] [?product :product/weight ?weight] [?product :product/price ?price] [(Shipping/estimate ?zip ?weight) ?shipCost] [ (<= ?price ?shipCost) ]] constrain price 50
Calling a Function “Find me the customer/product combinations where the shipping cost dominates the product cost.” return customer, product pairs [:find ?customer ?product :where [?customer :shipAddress ?addr] [?addr :zip ?zip] [?product :product/weight ?weight] [?product :product/price ?price] [(Shipping/estimate ?zip ?weight) ?shipCost] [(<= ?price ?shipCost)]] 51
Why 52
Why Clojure? • Data • good literals • immutable data • extensible reader • Platform • extensibility • performance • Lisp 53
Why Datalog? • Equivalent to Relational Model + Recursion • Better fit than Prolog for query • No clause order dependency • Guaranteed termination • Pattern-matching style easy to learn 54
Problem: Rectangles • join table • person table • club table “People can belong to • id key in person table multiple clubs” • person key in join table • club key in join table • id key in club table 55
Structural Navigation Structural Rigidity 56
CoC Taxonomy purpose assessment make an arbitrary choice often helpful default the common choice often helpful automate boilerplate dangerous 57
Solution: Universal Relation “People can belong [?person :club ?club] to multiple clubs” 58
Did You Ever Want To... • Make a column name variable? • Make a table name variable? • Treat metadata as first-class data? 59
First-Class Attributes [?person ?attr ?value] attribute slot isn’t special 60
Schema Made of Ordinary Data [?e :db/valueType ] find all attributes 61
Problem: Ambient DB SELECT ID FROM CUSTOMERS; in what db? 62
Solution: Explicit DB q("[:find ?customer :where [?customer :id] [?customer :orders]]", db); in this db! 63
Benefit: Query Params q([:find ?customer :in $database ?email :where [$database ?customer :email ?email]], db, "jdoe@example.com"); parameterized query is not a separate feature 64
Recommend
More recommend